[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openvas-development
Subject:    Re: [Openvas-devel] [Patch] Distributed knowledge base (KB) with Redis
From:       Henri Doreau <henri.doreau () gmail ! com>
Date:       2014-01-27 21:29:32
Message-ID: CAPXEBz6VUhu5tB=xnGNHaA12q5u4rhLtcOYH+nn726tN7dX76g () mail ! gmail ! com
[Download RAW message or body]

2014-01-27 Henri Doreau <henri.doreau@gmail.com>:
> Hi,
>
> 2014-01-27 Jan-Oliver Wagner <Jan-Oliver.Wagner@greenbone.net>:
>> Am Mittwoch, 22. Januar 2014, 21:09:54 schrieb Henri Doreau:
>>> thanks a lot for your help! Please find attached an updated version of
>>> the patch, rebased on latest trunk.
>>
>> thanks!
>> There is a slight problem: openvas-libraries will not build out of the box,
>> because in nasl_builtin_find_service.c:2950 the line
>> kb_item_get_all_free (kbitem);
>> needs to be relaced by
>> kb_item_free (kbitem);
>>
> Sorry for that, I must have forgotten it when rebasing the patch. You
> should be luckier with the one attached.
>
>> Then I did some first scans and the results without redis and with redis
>> showed no difference anymore. The delta is zero. That was for an
>> authenticated test of a single hosts with a couple of vulnerabilities.
>>
> This is my usual test case. Good that you get identical results too.
>
>> The scan times compared 9m33s : 6m48s (redis:trunk).
>> So, there is still some performance drawback.
>>
> Yes, as said in my previous email, I think this delay occurs when
> reporting host_details. The cost seems negligible elsewhere.
> Understanding and fixing it is on my TODO list. I'd like to evaluate
> it on a larger scan as well.
>
>> Will do some more tests and review, but hope this is a first helpful
>> feedback.
>> I'd very much appreciate if some more folks here would contribute
>> their experiences.
>>
> It is definitely helpful, thanks a lot. If someone else is interested
> in testing, feel free to ask for assistance if needed.
>
>> Codewise I think it makes sense to have a entriely new "kb_redis.h"
>> to replace the old "kb.h". That means a number of changes in other files
>> to replace the include, but in the end of the day it looks cleaner to me.
>>
> Well, kb.h contains the generic KB interface and kb_redis.c provides a
> redis-based implementation. I gave them distinct names because there
> could be other implementations eventually, sharing the same API. I'm
> also fine with changing, whatever is seen as the cleanest.
>
>> Best
>>
>> Jan
>>
> Regards
>
> --
> Henri

Sorry there was a bug in the former patch. This latest (and tested)
version is the one to use.

Regards

-- 
Henri

["kb_redis.patch" (text/x-patch)]

diff --git a/openvas-libraries/CMakeLists.txt b/openvas-libraries/CMakeLists.txt
index 4e35a1d..7453204 100644
--- a/openvas-libraries/CMakeLists.txt
+++ b/openvas-libraries/CMakeLists.txt
@@ -230,6 +230,15 @@ if (NOT OPENVAS_OMP_ONLY)
   endif (PCAP_CONFIG)
 endif (NOT OPENVAS_OMP_ONLY)
 
+message (STATUS "Looking for hiredis...")
+find_library (HIREDIS hiredis)
+message (STATUS "Looking for hiredis... ${HIREDIS}")
+if (NOT HIREDIS)
+  message (FATAL_ERROR "The hiredis library is required.")
+endif (NOT HIREDIS)
+
+set (REDIS_LDFLAGS "-lhiredis")
+
 execute_process (COMMAND pkg-config --cflags glib-2.0
   OUTPUT_VARIABLE GLIB_CFLAGS
   OUTPUT_STRIP_TRAILING_WHITESPACE)
diff --git a/openvas-libraries/misc/CMakeLists.txt \
b/openvas-libraries/misc/CMakeLists.txt index a026067..d4c30a8 100644
--- a/openvas-libraries/misc/CMakeLists.txt
+++ b/openvas-libraries/misc/CMakeLists.txt
@@ -70,7 +70,7 @@ if (MINGW)
   set (HEADERS proctitle.h openvas_auth.h openvas_server.h share_fd.h)
 else (MINGW)
   set (FILES arglists.c bpf_share.c ftp_funcs.c hash_table_file.c
-             ids_send.c kb.c network.c openvas_auth.c openvas_logging.c
+             ids_send.c kb_redis.c network.c openvas_auth.c openvas_logging.c
              openvas_server.c openvas_ssh_login.c openvas_uuid.c plugutils.c
              popen.c proctitle.c
              rand.c resource_request.c scanners_utils.c
@@ -120,7 +120,9 @@ if (BUILD_SHARED)
        gcrypt gpgme assuan libgpg-error ole32 ws2_32 ffi z shlwapi dnsapi winmm)
     target_link_libraries (openvas_misc_shared openvas_base_shared ${W32LIBS})
   else (MINGW)
-    target_link_libraries (openvas_misc_shared ${UUID_LDFLAGS} ${GLIB_LDFLAGS} \
${PCAP_LDFLAGS} ${GNUTLS_LDFLAGS} ${GCRYPT_LDFLAGS} openvas_base_shared \
${LDAP_LDFLAGS}) +    target_link_libraries (openvas_misc_shared ${UUID_LDFLAGS} \
${GLIB_LDFLAGS} +                           ${PCAP_LDFLAGS} ${GNUTLS_LDFLAGS} \
${GCRYPT_LDFLAGS} +                           openvas_base_shared ${LDAP_LDFLAGS} \
${REDIS_LDFLAGS})  endif (MINGW)
 endif (BUILD_SHARED)
 
@@ -156,7 +158,6 @@ if (OPENVAS_SYSCONF_DIR)
   add_definitions (-DOPENVAS_SYSCONF_DIR=\\\"${OPENVAS_SYSCONF_DIR}\\\")
 endif (OPENVAS_SYSCONF_DIR)
 
-
 # install library
 
 if (BUILD_STATIC)
diff --git a/openvas-libraries/misc/kb.c b/openvas-libraries/misc/kb.c
deleted file mode 100644
index 88fff24..0000000
--- a/openvas-libraries/misc/kb.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/* OpenVAS Libraries
- * Copyright (C) 1998 - 2003 Renaud Deraison
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 \
                USA.
- *
- *
- * Knowledge base management API
- */
-
-/**
- * @file
- * Knowledge base management API.\n
- * Knowledge bases collect information and can be used to share information
- * between NVTs.\n
- * A knowledge base is an array of knowledge base items (kb_item).
- * An item is defined by its name and has a value (either int or char*), a
- * type flag (indicating whether the value shall be interpreted as int or char*)
- * and a pointer to the "next" item.\n
- * A knowledge base (kb_item**) stores single items at a position according to
- * a hash of the items name (function mkkey). Because of that, a knowledge
- * base has a fixed size of 65537 items and kb_items are implemented as lists.\n
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <fnmatch.h>
-
-#include <glib.h>
-
-#include "arglists.h"
-#include "kb.h"
-#include "system_internal.h"
-
-#define HASH_MAX 65537
-
-
-/**
- * @brief Creates a hash value for a string to be used as index in a knowledge
- * base array.
- *
- * @param Name string to create hash value for.
- * @return Hash value for string name or 0 if name == NULL.
- */
-static unsigned int
-mkkey (char *name)
-{
-  char *p;
-  unsigned int h = 0;
-
-  if (name == NULL)
-    return 0;
-
-  for (p = name; *p != '\0'; p++)
-    h = (h << 3) + (unsigned char) *p;
-
-
-  return h % HASH_MAX;
-}
-
-
-/**
- * @brief Allocates memory for an array of kb_items with max length of HASH_MAX.
- *
- * @return Pointer to first item in knowledge base item array.
- */
-struct kb_item **
-kb_new ()
-{
-  return emalloc (HASH_MAX * sizeof (struct kb_item *));
-}
-
-
-/**
- * @brief READ the knowledge base
- *
- * @return kb_item in knowledge base with name name and type type or NULL if
- *         none found.
- */
-struct kb_item *
-kb_item_get_single (struct kb_item **kb, char *name, int type)
-{
-  unsigned int h = mkkey (name);
-  struct kb_item *ret;
-
-  if (kb == NULL || name == NULL)
-    return NULL;
-
-
-  ret = kb[h];
-  while (ret != NULL)
-    {
-      if ((strcmp (ret->name, name) == 0) && (type == 0 || (ret->type == type)))
-        return ret;
-      ret = ret->next;
-    }
-
-  return ret;
-}
-
-
-/**
- * @brief Get the value of a kb_item with type KB_TYPE_STR and name name.
- *
- * @return (char*) value of the kb_item name with type KB_TYPE_STR.
- */
-char *
-kb_item_get_str (struct kb_item **kb, char *name)
-{
-  struct kb_item *item = kb_item_get_single (kb, name, KB_TYPE_STR);
-
-  if (item == NULL)
-    return NULL;
-  else
-    return item->v.v_str;
-}
-
-/**
- * @brief Get the value of a kb_item with type KB_TYPE_INT and name \ref name.
- *
- * @return Value of the kb_item \ref name with type KB_TYPE_INT or -1 if it
- *         does not exist.
- */
-int
-kb_item_get_int (struct kb_item **kb, char *name)
-{
-  struct kb_item *item = kb_item_get_single (kb, name, KB_TYPE_INT);
-  if (item == NULL)
-    return -1;
-  else
-    return item->v.v_int;
-}
-
-/**
- * @brief Returns a list of copies of kb_items with name name in a knowledge base.
- *
- * The result has to be freed (kb_item_get_all_free).
- * Use kb_item_get_pattern if you want to get all items matching a pattern,
- * rather than a single name.
- *
- * @param kb The knowledge base.
- * @param name Name of the item(s) of interest.
- *
- * @return A kb_item list (has to be freed) with kb_items of name name.
- */
-struct kb_item *
-kb_item_get_all (struct kb_item **kb, char *name)
-{
-  unsigned h = mkkey (name);
-  struct kb_item *k;
-  struct kb_item *ret = NULL;
-
-  if (kb == NULL || name == NULL)
-    return NULL;
-
-  k = kb[h];
-  while (k != NULL)
-    {
-      if (strcmp (k->name, name) == 0)
-        {
-          struct kb_item *p;
-
-          p = emalloc (sizeof (struct kb_item));
-          memcpy (p, k, sizeof (struct kb_item));
-          p->next = ret;
-          ret = p;
-        }
-      k = k->next;
-    }
-  return ret;
-}
-
-/**
- * @brief Returns a list of copies of kb_items that match a pattern.
- *
- * The items have to be freed, e.g. with kb_item_get_all_free.
- *
- * @param kb The knowledge base.
- * @param expr A pattern that can be used with fnmatch (e.g. "www/serv*").
- *
- * @return A list of kb_items (has to be freed) whose name matches the pattern
- *         exp.
- */
-struct kb_item *
-kb_item_get_pattern (struct kb_item **kb, char *expr)
-{
-  int i;
-  struct kb_item *k;
-  struct kb_item *ret = NULL;
-
-  if (kb == NULL)
-    return NULL;
-
-  for (i = 0; i < HASH_MAX; i++)
-    {
-      k = kb[i];
-      while (k != NULL)
-        {
-          if (fnmatch (expr, k->name, 0) == 0)
-            {
-              struct kb_item *p;
-              p = emalloc (sizeof (struct kb_item));
-              memcpy (p, k, sizeof (struct kb_item));
-              p->next = ret;
-              ret = p;
-            }
-          k = k->next;
-        }
-    }
-  return ret;
-}
-
-
-/**
- * @brief Frees a list of kb_items.
- *
- * Can be used to free the results of querying the kb with kb_item_get_all() or
- * kb_item_get_pattern().
- *
- * @param items The list of kb_items to free.
- */
-void
-kb_item_get_all_free (struct kb_item *items)
-{
-  while (items != NULL)
-    {
-      struct kb_item *next;
-      next = items->next;
-      memset (items, 0xd7, sizeof (struct kb_item));
-      efree (&items);
-      items = next;
-    }
-}
-
-
-/**
- * @brief Add a kb_item with type KB_TYPE_STR and value value to the knowledge base.
- *
- * @param kb The knowledge base itself.
- * @param name Name of the item to add.
- * @param value Value of the item to add.
- * @param replace 0 if an existing item should NOT be replaced (e.g. to create
- *                lists), different than 0 if the value of an existing item with
- *                that name shall be replaced.
- *
- * @return -1 if kb equals NULL or if an item as wished exists already, 0 if
- *         success.
- */
-static int
-kb_item_addset_str (struct kb_item **kb, char *name, char *value, int replace)
-{
-  /* Before we write anything to the KB, we need to make sure that the same
-   * (name,value) pair is not present already. */
-  int h = mkkey (name);
-  struct kb_item *item;
-
-  if (kb == NULL)
-    return -1;
-
-  item = kb[h];
-
-  while (item != NULL)
-    {
-      if (strcmp (item->name, name) == 0)
-        {
-          if (item->type == KB_TYPE_STR && strcmp (item->v.v_str, value) == 0)
-            return -1;
-
-          if (replace != 0)
-            {
-              if (item->type == KB_TYPE_STR)
-                efree (&item->v.v_str);
-
-              item->type = KB_TYPE_STR;
-              item->v.v_str = estrdup (value);
-              return 0;
-            }
-        }
-
-      item = item->next;
-    }
-
-  item = emalloc (sizeof (struct kb_item));
-  item->name = estrdup (name);
-  item->v.v_str = estrdup (value);
-  item->type = KB_TYPE_STR;
-  item->next = kb[h];
-  kb[h] = item;
-  return 0;
-}
-
-/**
- * @brief Adds a string to the knowledge base.
- * In contrast to kb_item_set_str the item will not be replaced (useful for
- * list creation).
- *
- * @param kb    The knowledge base.
- * @param name  Key of the entry.
- * @param value Value of the entry.
- */
-int
-kb_item_add_str (struct kb_item **kb, char *name, char *value)
-{
-  return kb_item_addset_str (kb, name, value, 0);
-}
-
-int
-kb_item_set_str (struct kb_item **kb, char *name, char *value)
-{
-  return kb_item_addset_str (kb, name, value, 1);
-}
-
-/**
- * @brief Replace an old value in the KB by a new one.
- *
- * @return -1 if kn is NULL or
- */
-static int
-kb_item_addset_int (struct kb_item **kb, char *name, int value, int replace)
-{
-  /* Before we write anything to the KB, we need to make sure that the same
-   * (name,value) pair is not present already. */
-  int h = mkkey (name);
-  struct kb_item *item;
-
-  if (kb == NULL)
-    return -1;
-
-
-  item = kb[h];
-
-  while (item != NULL)
-    {
-      if (strcmp (item->name, name) == 0)
-        {
-          if (item->type == KB_TYPE_INT && item->v.v_int == value)
-            return -1;
-
-          if (replace != 0)
-            {
-              if (item->type == KB_TYPE_STR)
-                efree (&item->v.v_str);
-
-              item->type = KB_TYPE_INT;
-              item->v.v_int = value;
-              return 0;
-            }
-        }
-
-      item = item->next;
-    }
-
-  item = emalloc (sizeof (struct kb_item));
-  item->name = estrdup (name);
-  item->v.v_int = value;
-  item->type = KB_TYPE_INT;
-  item->next = kb[h];
-  kb[h] = item;
-  return 0;
-}
-
-
-int
-kb_item_set_int (struct kb_item **kb, char *name, int value)
-{
-  return kb_item_addset_int (kb, name, value, 1);
-}
-
-int
-kb_item_add_int (struct kb_item **kb, char *name, int value)
-{
-  return kb_item_addset_int (kb, name, value, 0);
-}
-
-
-void
-kb_item_rm_all (struct kb_item **kb, char *name)
-{
-  int h = mkkey (name);
-  struct kb_item *k, *prev = NULL;
-
-  if (kb == NULL)
-    return;
-
-  k = kb[h];
-  while (k != NULL)
-    {
-      if (strcmp (k->name, name) == 0)
-        {
-          struct kb_item *next;
-          if (k->type == ARG_STRING)
-            efree (&k->v.v_str);
-
-          efree (&k->name);
-          next = k->next;
-          efree (&k);
-          if (prev != NULL)
-            prev->next = next;
-          else
-            kb[h] = next;
-          k = next;
-        }
-      else
-        {
-          prev = k;
-          k = k->next;
-        }
-    }
-}
diff --git a/openvas-libraries/misc/kb.h b/openvas-libraries/misc/kb.h
index 5995295..50b105b 100644
--- a/openvas-libraries/misc/kb.h
+++ b/openvas-libraries/misc/kb.h
@@ -1,74 +1,336 @@
-/* OpenVAS
- * $Id$
- * Description: Header file for module kb.
+/* OpenVAS Libraries
  *
  * Authors:
- * Renaud Deraison <deraison@nessus.org> (Original pre-fork development)
+ * Henri Doreau <henri.doreau@gmail.com>
  *
  * Copyright:
- * Based on work Copyright (C) 1998 - 2007 Tenable Network Security, Inc.
+ * Copyright (C) 2014 - Greenbone Networks GmbH.
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * or, at your option, any later version 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
- * Library General Public License for more details.
+ * 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.
+ *
+ * Knowledge base management API - Redis backend.
  */
 
 #ifndef OPENVAS_KB_H
 #define OPENVAS_KB_H
 
+#include <assert.h>
+
 /**
- * Possible type of a kb_item.
- * The kb_items v should then be interpreted as int.
- */
-#define KB_TYPE_INT ARG_INT
-/**
- * Possible type of a kb_item.
- * The kb_items v should then be interpreted as char*.
+ * @brief Possible type of a kb_item.
  */
-#define KB_TYPE_STR ARG_STRING
+enum kb_item_type {
+  KB_TYPE_UNSPEC,   /**< Ignore the value (name/presence test).              */
+  KB_TYPE_INT,      /**< The kb_items v should then be interpreted as int.   */
+  KB_TYPE_STR,      /**< The kb_items v should then be interpreted as char*. */
+  /* -- */
+  KB_TYPE_CNT,
+};
 
 /**
- * Knowledge base item (defined by name, type (int/char*) and value).
- * Implemented as a singly linked list
+ * @brief Knowledge base item (defined by name, type (int/char*) and value).
+ *        Implemented as a singly linked list
  */
 struct kb_item
 {
-  char *name;  /**< Name of this knowledge base item.  */
-  char type;   /**< One of KB_TYPE_INT or KB_TYPE_STR. */
-  /** @todo Check if this is safe. (What happens if char* and int have not
-            the same size?) */
+  enum kb_item_type type;   /**< One of KB_TYPE_INT or KB_TYPE_STR. */
+
   union
   {
     char *v_str;
     int v_int;
-  } v;        /**< Value of this knowledge base item.  */
-  struct kb_item *next;  /**< Next item in list.       */
+  };                    /**< Value of this knowledge base item. */
+
+  struct kb_item *next; /**< Next item in list. */
+
+  size_t namelen;       /**< Name length (including final NULL byte). */
+  char name[0];         /**< Name of this knowledge base item.  */
 };
 
-typedef struct kb_item ** kb_t;
-
-struct kb_item **kb_new ();
-struct kb_item *kb_item_get_single (struct kb_item **, char *, int);
-char *kb_item_get_str (struct kb_item **, char *);
-int kb_item_get_int (struct kb_item **, char *);
-struct kb_item *kb_item_get_all (struct kb_item **, char *);
-struct kb_item *kb_item_get_pattern (struct kb_item **, char *);
-void kb_item_get_all_free (struct kb_item *);
-
-int kb_item_add_str (struct kb_item **, char *, char *);
-int kb_item_set_str (struct kb_item **, char *, char *);
-int kb_item_add_int (struct kb_item **, char *, int);
-int kb_item_set_int (struct kb_item **, char *, int);
-void kb_item_rm_all (struct kb_item **, char *);
+struct kb_operations;
+
+/**
+ * @brief Top-level KB. This is to be inherited by KB implementations.
+ */
+struct kb
+{
+  const struct kb_operations *kb_ops;   /**< KB vtable. */
+};
+
+/**
+ * @brief type abstraction to hide KB internals.
+ */
+typedef struct kb *kb_t;
+
+/**
+ * @brief KB interface. Functions provided by an implementation. All functions
+ *        have to be provided, there is no default/fallback. These functions
+ *        should be called via the corresponding static inline wrappers below.
+ *        See the wrappers for the documentation.
+ */
+struct kb_operations
+{
+  /* ctor/dtor */
+  int (*kb_new)(kb_t *, const char *);
+  int (*kb_delete)(kb_t);
+
+  /* Actual kb operations */
+  struct kb_item *(*kb_get_single)(kb_t, const char *, enum kb_item_type);
+  char *(*kb_get_str) (kb_t, const char *);
+  int (*kb_get_int) (kb_t, const char *);
+  struct kb_item * (*kb_get_all) (kb_t, const char *);
+  struct kb_item * (*kb_get_pattern) (kb_t, const char *);
+  int (*kb_add_str) (kb_t, const char *, const char *);
+  int (*kb_set_str) (kb_t, const char *, const char *);
+  int (*kb_add_int) (kb_t, const char *, int);
+  int (*kb_set_int) (kb_t, const char *, int);
+  int (*kb_del_items) (kb_t, const char *);
+  int (*kb_lnk_reset) (kb_t);
+};
+
+/**
+ * @brief Default KB operations.
+ *        No selection mechanism is provided yet since there's only one
+ *        implementation (redis-based).
+ */
+extern const struct kb_operations *KBDefaultOperations;
+
+/**
+ * @brief Release a KB item (or a list).
+ */
+void kb_item_free (struct kb_item *);
+
+
+/**
+ * @brief Initialize a new Knowledge Base object.
+ * @param[in] kb  Reference to a kb_t to initialize.
+ * @return 0 on success, non-null on error.
+ */
+static inline int kb_new(kb_t *kb, const char *kb_path)
+{
+  assert (kb);
+  assert (KBDefaultOperations);
+  assert (KBDefaultOperations->kb_new);
+
+  *kb = NULL;
+
+  return KBDefaultOperations->kb_new (kb, kb_path);
+}
+
+/**
+ * @brief Delete all entries and release ownership on the namespace.
+ * @param[in] kb  KB handle to release.
+ * @return 0 on success, non-null on error.
+ */
+static inline int kb_delete(kb_t kb)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_delete);
+
+  return kb->kb_ops->kb_delete (kb);
+}
+
+/**
+ * @brief Get a single KB element.
+ * @param[in] kb  KB handle where to fetch the item.
+ * @param[in] name  Name of the element to retrieve.
+ * @param[in] type  Desired element type.
+ * @return A struct kb_item to be freed with kb_item_free() or NULL if no
+ *         element was found or on error.
+ */
+static inline struct kb_item *
+kb_item_get_single (kb_t kb, const char *name, enum kb_item_type type)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_get_single);
+
+  return kb->kb_ops->kb_get_single (kb, name, type);
+}
+
+/**
+ * @brief Get a single KB string item.
+ * @param[in] kb  KB handle where to fetch the item.
+ * @param[in] name  Name of the element to retrieve.
+ * @return A struct kb_item to be freed with kb_item_free() or NULL if no
+ *         element was found or on error.
+ */
+static inline char *
+kb_item_get_str (kb_t kb, const char *name)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_get_str);
+
+  return kb->kb_ops->kb_get_str (kb, name);
+}
+
+/**
+ * @brief Get a single KB integer item.
+ * @param[in] kb  KB handle where to fetch the item.
+ * @param[in] name  Name of the element to retrieve.
+ * @return A struct kb_item to be freed with kb_item_free() or NULL if no
+ *         element was found or on error.
+ */
+static inline int
+kb_item_get_int (kb_t kb, const char *name)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_get_int);
+
+  return kb->kb_ops->kb_get_int (kb, name);
+}
+
+/**
+ * @brief Get all items stored under a given name.
+ * @param[in] kb  KB handle where to fetch the items.
+ * @param[in] name  Name of the elements to retrieve.
+ * @return Linked struct kb_item instances to be freed with kb_item_free() or
+ *         NULL if no element was found or on error.
+ */
+static inline struct kb_item *
+kb_item_get_all (kb_t kb, const char *name)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_get_all);
+
+  return kb->kb_ops->kb_get_all (kb, name);
+}
+
+/**
+ * @brief Get all items stored under a given pattern.
+ * @param[in] kb  KB handle where to fetch the items.
+ * @param[in] pattern  '*' pattern of the elements to retrieve.
+ * @return Linked struct kb_item instances to be freed with kb_item_free() or
+ *         NULL if no element was found or on error.
+ */
+static inline struct kb_item *
+kb_item_get_pattern (kb_t kb, const char *pattern)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_get_pattern);
+
+  return kb->kb_ops->kb_get_pattern (kb, pattern);
+}
+
+/**
+ * @brief Insert (append) a new entry under a given name.
+ * @param[in] kb  KB handle where to store the item.
+ * @param[in] name  Item name.
+ * @maram[in] str  Item value.
+ * @return 0 on success, non-null on error.
+ */
+static inline int
+kb_item_add_str (kb_t kb, const char *name, const char *str)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_add_str);
+
+  return kb->kb_ops->kb_add_str (kb, name, str);
+}
+
+/**
+ * @brief Set (replace) a new entry under a given name.
+ * @param[in] kb  KB handle where to store the item.
+ * @param[in] name  Item name.
+ * @maram[in] str  Item value.
+ * @return 0 on success, non-null on error.
+ */
+static inline int
+kb_item_set_str (kb_t kb, const char *name, const char *str)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_set_str);
+
+  return kb->kb_ops->kb_set_str (kb, name, str);
+}
+
+/**
+ * @brief Insert (append) a new entry under a given name.
+ * @param[in] kb  KB handle where to store the item.
+ * @param[in] name  Item name.
+ * @maram[in] val  Item value.
+ * @return 0 on success, non-null on error.
+ */
+static inline int
+kb_item_add_int (kb_t kb, const char *name, int val)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_add_int);
+
+  return kb->kb_ops->kb_add_int (kb, name, val);
+}
+
+/**
+ * @brief Set (replace) a new entry under a given name.
+ * @param[in] kb  KB handle where to store the item.
+ * @param[in] name  Item name.
+ * @maram[in] val  Item value.
+ * @return 0 on success, non-null on error.
+ */
+static inline int
+kb_item_set_int (kb_t kb, const char *name, int val)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_set_int);
+
+  return kb->kb_ops->kb_set_int (kb, name, val);
+}
+
+/**
+ * @brief Delete all entries under a given name..
+ * @param[in] kb  KB handle where to store the item.
+ * @param[in] name  Item name.
+ * @return 0 on success, non-null on error.
+ */
+static inline int
+kb_del_items (kb_t kb, const char *name)
+{
+  assert (kb);
+  assert (kb->kb_ops);
+  assert (kb->kb_ops->kb_del_items);
+
+  return kb->kb_ops->kb_del_items (kb, name);
+}
+
+/**
+ * @brief Reset connection to the KB. This is called after each fork() to make
+ *        sure connections aren't shared between concurrent processes.
+ * @param[in] kb  KB handle.
+ * @return 0 on success, non-null on error.
+ */
+static inline int kb_lnk_reset (kb_t kb)
+{
+  int rc = 0;
+
+  assert (kb);
+  assert (kb->kb_ops);
+
+  if (kb->kb_ops->kb_lnk_reset == NULL)
+    rc = kb->kb_ops->kb_lnk_reset (kb);
+
+  return rc;
+}
 
 #endif
diff --git a/openvas-libraries/misc/kb_redis.c b/openvas-libraries/misc/kb_redis.c
new file mode 100644
index 0000000..c779f9e
--- /dev/null
+++ b/openvas-libraries/misc/kb_redis.c
@@ -0,0 +1,880 @@
+/* OpenVAS Libraries
+ *
+ * Authors:
+ * Henri Doreau <henri.doreau@gmail.com>
+ *
+ * Copyright:
+ * Copyright (C) 2014 - Greenbone Networks GmbH.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * or, at your option, any later version 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.
+ *
+ * Knowledge base management API - Redis backend.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <errno.h>
+#include <ctype.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <hiredis/hiredis.h>
+#include <glib.h>
+
+#include "arglists.h"
+#include "kb.h"
+#include "system_internal.h"
+
+#undef  G_LOG_DOMAIN
+#define G_LOG_DOMAIN "lib  kb_redis"
+
+/**
+ * @file kb_redis.c
+ *
+ * @brief Contains specialized structures and functions to use redis as a KB
+ *        server.
+ */
+
+
+/**
+ * @brief Name of the namespace usage bitmap in redis.
+ */
+#define GLOBAL_DBINDEX_NAME "OpenVAS.__GlobalDBIndex"
+
+/**
+ * @brief Number of seconds to wait for between two attempts to acquire a KB
+ *        namespace.
+ */
+#define KB_RETRY_DELAY      60
+
+
+static const struct kb_operations KBRedisOperations;
+
+
+/**
+ * @brief Subclass of struct kb, it contains the redis-specific fields, such as
+ *        the redis context, current DB (namespace) id and the server socket
+ *        path.
+ */
+struct kb_redis
+{
+  struct kb kb;         /**< Parent KB handle. */
+  unsigned int max_db;  /**< Max # of databases. */
+  unsigned int db;      /**< Namespace ID number, 0 if uninitialized. */
+  redisContext *rctx;   /**< Redis client context. */
+  char path[0];         /**< Path to the server socket. */
+};
+#define redis_kb(__kb) ((struct kb_redis *)(__kb))
+
+/**
+ * @brief Redis transaction handle.
+ */
+struct redis_tx
+{
+  struct kb_redis *kbr; /**< Redis KB handle. */
+  bool valid;           /**< Whether the transaction is still valid. */
+};
+
+
+static int redis_delete_all (struct kb_redis *);
+static int redis_lnk_reset (kb_t);
+
+
+/**
+ * Attempt to atomically acquire ownership of a database.
+ */
+static int
+try_database_index (struct kb_redis *kbr, int index)
+{
+  redisContext *ctx = kbr->rctx;
+  redisReply *rep;
+  int rc = 0;
+
+  rep = redisCommand (ctx, "HSETNX %s %d 1", GLOBAL_DBINDEX_NAME, index);
+  if (rep == NULL)
+    return -ENOMEM;
+
+  if (rep->type != REDIS_REPLY_INTEGER)
+    rc = -EPROTO;
+  else if (rep->integer == 0)
+    rc = -EALREADY;
+  else
+    kbr->db = index;
+
+  freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+fetch_max_db_index (struct kb_redis *kbr)
+{
+  int rc = 0;
+  redisContext *ctx = kbr->rctx;
+  redisReply *rep = NULL;
+
+  rep = redisCommand (ctx, "CONFIG GET databases");
+  if (rep == NULL)
+    {
+      g_error ("Redis command error: %s", ctx->errstr);
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  if (rep->type != REDIS_REPLY_ARRAY)
+    {
+      g_error ("Cannot retrieve max DB number: %s", rep->str);
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  if (rep->elements != 2)
+    {
+      g_error ("Unexpected reply length (%zd)", rep->elements);
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  kbr->max_db = (unsigned)atoi(rep->element[1]->str);
+  g_debug ("Maximum DB number: %u", kbr->max_db);
+
+err_cleanup:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+/**
+ * WARNING: do not call redis_cmd in here, since our context is not fully
+ * acquired yet!
+ */
+static int
+select_database (struct kb_redis *kbr)
+{
+  int rc, i;
+  redisContext *ctx = kbr->rctx;
+  redisReply *rep = NULL;
+
+  if (kbr->db == 0)
+    {
+      if (kbr->max_db == 0)
+        fetch_max_db_index (kbr);
+
+      for (i = 1; i < kbr->max_db; i++)
+        {
+          rc = try_database_index(kbr, i);
+          if (rc == 0)
+            break;
+        }
+    }
+
+  /* No DB available, give up. */
+  if (kbr->db == 0)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  rep = redisCommand (ctx, "SELECT %u", kbr->db);
+  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  rc = 0;
+
+err_cleanup:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_release_db (struct kb_redis *kbr)
+{
+  int rc;
+  redisContext *ctx = kbr->rctx;
+  redisReply *rep;
+
+  rep = redisCommand (ctx, "SELECT 0"); /* Management database*/
+  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+  freeReplyObject (rep);
+
+  rep = redisCommand (ctx, "HDEL %s %d", GLOBAL_DBINDEX_NAME, kbr->db);
+  if (rep == NULL || rep->type != REDIS_REPLY_INTEGER)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  rc = 0;
+
+err_cleanup:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static redisContext *
+get_redis_ctx (struct kb_redis *kbr)
+{
+  int rc;
+
+  if (kbr->rctx != NULL)
+    return kbr->rctx;
+
+  kbr->rctx = redisConnectUnix (kbr->path);
+  if (kbr->rctx != NULL && kbr->rctx->err)
+    {
+      g_error ("Redis error: %s (%d)", kbr->rctx->errstr, kbr->rctx->err);
+      redisFree (kbr->rctx);
+      kbr->rctx = NULL;
+      return NULL;
+    }
+
+  do
+    {
+      rc = select_database (kbr);
+      if (rc)
+        {
+          g_debug ("No redis DB available, retrying in %ds...", KB_RETRY_DELAY);
+          sleep (KB_RETRY_DELAY);
+        }
+    }
+  while (rc != 0);
+
+  g_debug ("Connected to redis://%s/%d", kbr->path, kbr->db);
+  return kbr->rctx;
+}
+
+static int redis_new (kb_t *kb, const char *kb_path)
+{
+  struct kb_redis *kbr;
+  struct stat st;
+  int rc = 0;
+
+  kbr = g_malloc0(sizeof(struct kb_redis) + strlen(kb_path) + 1);
+  kbr->kb.kb_ops = &KBRedisOperations;
+  strcpy(kbr->path, kb_path);
+
+  rc = lstat(kb_path, &st);
+  if (rc)
+    {
+      rc = -errno;
+      g_error ("Cannot access redis path at '%s': %s", kb_path, strerror (-rc));
+      g_free (kbr);
+      kbr = NULL;
+    }
+
+  *kb = (kb_t)kbr;
+
+  return rc;
+}
+
+static int redis_delete (kb_t kb)
+{
+  struct kb_redis *kbr;
+
+  kbr = redis_kb (kb);
+
+  redis_delete_all (kbr);
+  redis_release_db (kbr);
+
+  if (kbr->rctx != NULL)
+    {
+      redisFree (kbr->rctx);
+      kbr->rctx = NULL;
+    }
+
+  g_free (kb);
+  return 0;
+}
+
+void kb_item_free (struct kb_item *item)
+{
+  while (item != NULL)
+    {
+      struct kb_item *next;
+
+      next = item->next;
+      if (item->type == KB_TYPE_STR && item->v_str != NULL)
+        g_free (item->v_str);
+      g_free (item);
+      item = next;
+    }
+}
+
+static int
+redis_transaction_new (struct kb_redis *kbr, struct redis_tx *rtx)
+{
+  int rc = 0;
+  redisContext *ctx;
+  redisReply *rep = NULL;
+
+  rtx->kbr = kbr;
+  rtx->valid = false;
+
+  /* That is the quick, dirty & easy way to guarantee a fresh connection */
+  redis_lnk_reset ((kb_t)kbr);
+
+  ctx = get_redis_ctx (kbr);
+  if (ctx == NULL)
+    return -1;
+
+  rep = redisCommand (ctx, "MULTI");
+  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  rtx->valid = true;
+
+err_cleanup:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_transaction_cmd (struct redis_tx *rtx, const char *fmt, ...)
+{
+  int rc = 0;
+  va_list ap;
+  redisReply *rep;
+
+  if (!rtx->valid)
+    return -1;
+
+  va_start (ap, fmt);
+
+  rep = redisvCommand (rtx->kbr->rctx, fmt, ap);
+  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+err_cleanup:
+  va_end (ap);
+
+  if (rc)
+    rtx->valid = false;
+
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_transaction_end (struct redis_tx *rtx, redisReply **rep)
+{
+  int rc;
+  redisReply *preply;
+
+  preply = NULL;
+
+  if (!rtx->valid)
+    return -1;
+
+  preply = redisCommand (rtx->kbr->rctx, "EXEC");
+  if (preply == NULL || preply->type == REDIS_REPLY_ERROR)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  *rep = preply;
+  rc = 0;
+
+err_cleanup:
+
+  if (rc)
+    {
+      freeReplyObject (preply);
+      *rep = NULL;
+    }
+
+  memset (rtx, 0, sizeof (struct redis_tx));
+
+  return rc;
+}
+
+static struct kb_item *
+redis2kbitem_single (const char *name, const redisReply *elt, int force_int)
+{
+  struct kb_item *item;
+  size_t namelen;
+
+  if (elt->type != REDIS_REPLY_STRING && elt->type != REDIS_REPLY_INTEGER)
+    return NULL;
+
+  namelen = strlen (name) + 1;
+
+  item = g_malloc0 (sizeof (struct kb_item) + namelen);
+  if (elt->type == REDIS_REPLY_INTEGER)
+    {
+      item->type  = KB_TYPE_INT;
+      item->v_int = elt->integer;
+    }
+  else if (force_int)
+    {
+      item->type  = KB_TYPE_INT;
+      item->v_int = atoi (elt->str);
+    }
+  else
+    {
+      item->type  = KB_TYPE_STR;
+      item->v_str = g_strdup (elt->str);
+    }
+
+  item->next    = NULL;
+  item->namelen = namelen;
+  strcpy (item->name, name);
+
+  return item;
+}
+
+static struct kb_item *
+redis2kbitem (const char *name, const redisReply *rep)
+{
+  int i;
+  struct kb_item *kbi;
+
+  kbi = NULL;
+
+  switch (rep->type)
+    {
+      case REDIS_REPLY_STRING:
+      case REDIS_REPLY_INTEGER:
+        kbi = redis2kbitem_single (name, rep, 0);
+        break;
+
+      case REDIS_REPLY_ARRAY:
+        for (i = 0; i < rep->elements; i++)
+          {
+            struct kb_item *tmpitem;
+
+            tmpitem = redis2kbitem_single (name, rep->element[i], 0);
+            if (tmpitem == NULL)
+              break;
+
+            if (kbi != NULL)
+              {
+                tmpitem->next = kbi;
+                kbi = tmpitem;
+              }
+            else
+              kbi = tmpitem;
+          }
+        break;
+
+      case REDIS_REPLY_NIL:
+      case REDIS_REPLY_STATUS:
+      case REDIS_REPLY_ERROR:
+      default:
+        break;
+    }
+
+  return kbi;
+}
+
+static redisReply *
+redis_cmd (struct kb_redis *kbr, const char *fmt, ...)
+{
+  redisReply *rep;
+  va_list ap, aq;
+  int retry = 0;
+
+  va_start (ap, fmt);
+  do
+    {
+      redisContext *ctx;
+
+      rep = NULL;
+
+      ctx = get_redis_ctx (kbr);
+      if (ctx == NULL)
+        return NULL;
+
+      va_copy (aq, ap);
+      rep = redisvCommand (ctx, fmt, aq);
+      va_end (aq);
+
+      if (ctx->err)
+        {
+          if (rep != NULL)
+            freeReplyObject (rep);
+
+          redis_lnk_reset ((kb_t)kbr);
+          retry = !retry;
+        }
+      else
+        retry = 0;
+    }
+  while (retry);
+
+  va_end (ap);
+
+  return rep;
+}
+
+static struct kb_item *
+redis_get_single (kb_t kb, const char *name, enum kb_item_type type)
+{
+  struct kb_item *kbi;
+  struct kb_redis *kbr;
+  redisReply *rep;
+
+  kbr = redis_kb (kb);
+  kbi = NULL;
+
+  rep = redis_cmd (kbr, "LINDEX %s 0", name);
+  if (rep == NULL || rep->type != REDIS_REPLY_STRING)
+    {
+      kbi = NULL;
+      goto out;
+    }
+
+  kbi = redis2kbitem_single (name, rep, 1);
+
+out:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return kbi;
+}
+
+static char *
+redis_get_str (kb_t kb, const char *name)
+{
+  struct kb_item *kbi;
+
+  kbi = redis_get_single (kb, name, KB_TYPE_STR);
+  if (kbi != NULL)
+    {
+      char *res;
+
+      res = kbi->v_str;
+      kbi->v_str = NULL;
+      kb_item_free (kbi);
+      return res;
+    }
+  return NULL;
+}
+
+static int
+redis_get_int (kb_t kb, const char *name)
+{
+  struct kb_item *kbi;
+
+  kbi = redis_get_single (kb, name, KB_TYPE_INT);
+  if (kbi != NULL)
+    {
+      int res;
+
+      res = kbi->v_int;
+      kb_item_free (kbi);
+      return res;
+    }
+  return -1;
+}
+
+static struct kb_item *
+redis_get_all (kb_t kb, const char *name)
+{
+  struct kb_redis *kbr;
+  struct kb_item *kbi;
+  redisReply *rep;
+
+  kbr = redis_kb (kb);
+
+  rep = redis_cmd (kbr, "LRANGE %s 0 -1", name);
+  if (rep == NULL)
+    return NULL;
+
+  kbi = redis2kbitem (name, rep);
+
+  freeReplyObject (rep);
+
+  return kbi;
+}
+
+static struct kb_item *
+redis_get_pattern (kb_t kb, const char *pattern)
+{
+  struct kb_redis *kbr;
+  struct kb_item *kbi;
+  redisReply *rep;
+  int i;
+
+  kbr = redis_kb (kb);
+  kbi = NULL;
+
+  rep = redis_cmd (kbr, "KEYS %s", pattern);
+  if (rep == NULL)
+    return NULL;
+
+  if (rep->type != REDIS_REPLY_ARRAY)
+    {
+      freeReplyObject (rep);
+      return NULL;
+    }
+
+  for (i = 0; i < rep->elements; i++)
+    {
+      const char *key;
+      struct kb_item *tmp;
+      redisReply *rep_range;
+
+      key = rep->element[i]->str;
+
+      rep_range = redis_cmd (kbr, "LRANGE %s 0 -1", key);
+      if (rep_range == NULL)
+        continue;
+
+      tmp = redis2kbitem (key, rep_range);
+      if (tmp == NULL)
+        goto next; /* race condition, bah... */
+
+      if (kbi != NULL)
+        {
+          struct kb_item *tmp2;
+
+          tmp2 = tmp;
+          while (tmp->next != NULL)
+            tmp = tmp->next;
+
+          tmp->next = kbi;
+          kbi = tmp2;
+        }
+      else
+        kbi = tmp;
+
+next:
+      if (rep_range != NULL)
+        freeReplyObject (rep_range);
+    }
+
+  freeReplyObject (rep);
+
+  return kbi;
+}
+
+static int
+redis_del_items (kb_t kb, const char *name)
+{
+  struct kb_redis *kbr;
+  redisReply *rep;
+  int rc = 0;
+
+  kbr = redis_kb (kb);
+
+  rep = redis_cmd (kbr, "DEL %s", name);
+  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
+    rc = -1;
+
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_add_str (kb_t kb, const char *name, const char *str)
+{
+  struct kb_redis *kbr;
+  redisReply *rep;
+  int rc = 0;
+
+  kbr = redis_kb (kb);
+
+  rep = redis_cmd (kbr, "RPUSH %s %s", name, str);
+  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
+    rc = -1;
+
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_set_str (kb_t kb, const char *name, const char *val)
+{
+  struct kb_redis *kbr;
+  struct redis_tx rtx;
+  redisReply *rep;
+  int rc;
+
+  kbr = redis_kb (kb);
+  rep = NULL;
+
+  rc = redis_transaction_new (kbr, &rtx);
+  if (rc)
+    {
+      rc = -1;
+      goto out;
+    }
+
+  redis_transaction_cmd (&rtx, "DEL %s", name);
+  redis_transaction_cmd (&rtx, "RPUSH %s %s", name, val);
+
+  rc = redis_transaction_end (&rtx, &rep);
+  if (rc || rep == NULL || rep->type == REDIS_REPLY_ERROR)
+    {
+      rc = -1;
+      goto out;
+    }
+
+out:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_add_int (kb_t kb, const char *name, int val)
+{
+  struct kb_redis *kbr;
+  redisReply *rep;
+  int rc = 0;
+
+  kbr = redis_kb (kb);
+
+  rep = redis_cmd (kbr, "RPUSH %s %d", name, val);
+  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
+    {
+      rc = -1;
+      goto out;
+    }
+
+out:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_set_int (kb_t kb, const char *name, int val)
+{
+  struct kb_redis *kbr;
+  struct redis_tx rtx;
+  redisReply *rep;
+  int rc;
+
+  kbr = redis_kb (kb);
+  rep = NULL;
+
+  rc = redis_transaction_new (kbr, &rtx);
+  if (rc)
+    {
+      rc = -1;
+      goto out;
+    }
+
+  redis_transaction_cmd (&rtx, "DEL %s", name);
+  redis_transaction_cmd (&rtx, "RPUSH %s %d", name, val);
+
+  rc = redis_transaction_end (&rtx, &rep);
+  if (rc || rep == NULL || rep->type == REDIS_REPLY_ERROR)
+    {
+      rc = -1;
+      goto out;
+    }
+
+out:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+static int
+redis_lnk_reset (kb_t kb)
+{
+  struct kb_redis *kbr;
+
+  kbr = redis_kb (kb);
+
+  if (kbr->rctx != NULL)
+    {
+      redisFree(kbr->rctx);
+      kbr->rctx = NULL;
+    }
+
+  return 0;
+}
+
+int
+redis_delete_all (struct kb_redis *kbr)
+{
+  int rc;
+  redisReply *rep;
+
+  g_debug ("Now deleting all elements from KB #%u", kbr->db);
+  rep = redis_cmd (kbr, "FLUSHDB");
+  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
+    {
+      rc = -1;
+      goto err_cleanup;
+    }
+
+  rc = 0;
+
+err_cleanup:
+  if (rep != NULL)
+    freeReplyObject (rep);
+
+  return rc;
+}
+
+
+static const struct kb_operations KBRedisOperations = {
+  .kb_new          = redis_new,
+  .kb_delete       = redis_delete,
+  .kb_get_single   = redis_get_single,
+  .kb_get_str      = redis_get_str,
+  .kb_get_int      = redis_get_int,
+  .kb_get_all      = redis_get_all,
+  .kb_get_pattern  = redis_get_pattern,
+  .kb_add_str      = redis_add_str,
+  .kb_set_str      = redis_set_str,
+  .kb_add_int      = redis_add_int,
+  .kb_set_int      = redis_set_int,
+  .kb_del_items    = redis_del_items,
+  .kb_lnk_reset    = redis_lnk_reset,
+};
+
+const struct kb_operations *KBDefaultOperations = &KBRedisOperations;
diff --git a/openvas-libraries/misc/plugutils.c b/openvas-libraries/misc/plugutils.c
index 603a2dd..7d23dd7 100644
--- a/openvas-libraries/misc/plugutils.c
+++ b/openvas-libraries/misc/plugutils.c
@@ -45,7 +45,7 @@
 #include "network.h"
 #include "rand.h"
 #include "plugutils.h"
-#include "internal_com.h" /* for INTERNAL_COMM_MSG_TYPE_KB */
+#include "internal_com.h"
 #include "share_fd.h"
 #include "system.h"
 #include "scanners_utils.h"
@@ -982,129 +982,33 @@ get_plugin_preference_file_size (struct arglist *desc, const \
char *identifier)  return atol (filesize_str);
 }
 
-
-void *
-plug_get_fresh_key (struct arglist *args, char *name, int *type)
-{
-  struct arglist *globals = arg_get_value (args, "globals");
-  int soc = GPOINTER_TO_SIZE (arg_get_value (globals, "global_socket"));
-  int e;
-  char *buf = NULL;
-  int bufsz = 0;
-  int msg;
-
-  if (name == NULL || type == NULL)
-    return NULL;
-  *type = -1;
-
-  e =
-    internal_send (soc, name, INTERNAL_COMM_MSG_TYPE_KB | INTERNAL_COMM_KB_GET);
-  if (e < 0)
-    {
-      fprintf (stderr, "[%d] plug_get_fresh_key:internal_send(%d, %s): %s\n",
-               getpid (), soc, name, strerror (errno));
-      goto err;
-    }
-
-  internal_recv (soc, &buf, &bufsz, &msg);
-  if ((msg & INTERNAL_COMM_MSG_TYPE_KB) == 0)
-    {
-      fprintf (stderr,
-               "[%d] plug_get_fresh_key:internal_send(%d): Unexpected message %d",
-               getpid (), soc, msg);
-      goto err;
-    }
-
-  if (msg & INTERNAL_COMM_KB_ERROR)
-    return NULL;
-  if (msg & INTERNAL_COMM_KB_SENDING_STR)
-    {
-      char *ret = estrdup (buf);
-      *type = ARG_STRING;
-      efree (&buf);
-      return ret;
-    }
-  else if (msg & INTERNAL_COMM_KB_SENDING_INT)
-    {
-      int ret;
-      *type = ARG_INT;
-      ret = atoi (buf);
-      efree (&buf);
-      return GSIZE_TO_POINTER (ret);
-    }
-err:
-  if (buf != NULL)
-    efree (&buf);
-  return NULL;
-}
-
-static void
-plug_set_replace_key (struct arglist *args, char *name, int type, void *value,
-                      int replace)
+void
+plug_set_key (struct arglist *args, char *name, int type, void *value)
 {
-  struct kb_item **kb = plug_get_kb (args);
-  struct arglist *globals = arg_get_value (args, "globals");
-  int soc = GPOINTER_TO_SIZE (arg_get_value (globals, "global_socket"));
-  char *str = NULL;
-  int msg;
+  kb_t kb = plug_get_kb (args);
 
   if (name == NULL || value == NULL)
     return;
 
-  switch (type)
-    {
-    case ARG_STRING:
-      kb_item_add_str (kb, name, value);
-      value = addslashes (value);
-      str = emalloc (strlen (name) + strlen (value) + 10);
-      // RATS: ignore
-      snprintf (str, strlen (name) + strlen (value) + 10, "%d %s=%s;\n",
-                ARG_STRING, name, (char *) value);
-      if (global_nasl_debug == 1)
-        fprintf (stderr, "set key %s -> %s\n", name, (char *) value);
-      efree (&value);
-      break;
-    case ARG_INT:
-      kb_item_add_int (kb, name, GPOINTER_TO_SIZE (value));
-      str = emalloc (strlen (name) + 20);
-      // RATS: ignore
-      snprintf (str, strlen (name) + 20, "%d %s=%d;\n", ARG_INT, name,
-                (int) GPOINTER_TO_SIZE (value));
-      if (global_nasl_debug == 1)
-        fprintf (stderr, "set key %s -> %d\n", name,
-                 (int) GPOINTER_TO_SIZE (value));
-      break;
-    }
-
-  if (str && soc)
-    {
-      int e;
-      if (replace != 0)
-        msg = INTERNAL_COMM_MSG_TYPE_KB | INTERNAL_COMM_KB_REPLACE;
-      else
-        msg = INTERNAL_COMM_MSG_TYPE_KB;
-
-      e = internal_send (soc, str, msg);
-      if (e < 0)
-        fprintf (stderr, "[%d] plug_set_key:internal_send(%d)['%s']: %s\n",
-                 getpid (), soc, str, strerror (errno));
-    }
-  if (str)
-    efree (&str);
+  if (type == ARG_STRING)
+    kb_item_add_str (kb, name, value);
+  else if (type == ARG_INT)
+    kb_item_add_int (kb, name, GPOINTER_TO_SIZE (value));
 }
 
 
 void
-plug_set_key (struct arglist *args, char *name, int type, void *value)
+plug_replace_key (struct arglist *args, char *name, int type, void *value)
 {
-  plug_set_replace_key (args, name, type, value, 0);
-}
+  kb_t kb = plug_get_kb (args);
 
+  if (name == NULL || value == NULL)
+    return;
 
-void
-plug_replace_key (struct arglist *args, char *name, int type, void *value)
-{
-  plug_set_replace_key (args, name, type, value, 1);
+  if (type == ARG_STRING)
+    kb_item_set_str (kb, name, value);
+  else if (type == ARG_INT)
+    kb_item_set_int (kb, name, GPOINTER_TO_SIZE (value));
 }
 
 void
@@ -1208,16 +1112,16 @@ plug_get_key (struct arglist *args, char *name, int *type)
       if (res->type == KB_TYPE_INT)
         {
           if (type != NULL)
-            *type = ARG_INT;
-          ret = GSIZE_TO_POINTER (res->v.v_int);
+            *type = KB_TYPE_INT;
+          ret = GSIZE_TO_POINTER (res->v_int);
         }
       else
         {
           if (type != NULL)
-            *type = ARG_STRING;
-          ret = GSIZE_TO_POINTER (res->v.v_str);
+            *type = KB_TYPE_STR;
+          ret = strdup (res->v_str);
         }
-      kb_item_get_all_free (res);
+      kb_item_free (res);
       return ret;
     }
 
@@ -1229,6 +1133,7 @@ plug_get_key (struct arglist *args, char *name, int *type)
       pid_t pid;
 
       socketpair (AF_UNIX, SOCK_STREAM, 0, sockpair);
+      kb_lnk_reset (kb);
       if ((pid = fork ()) == 0)
         {
           int old, soc;
@@ -1255,22 +1160,15 @@ plug_get_key (struct arglist *args, char *name, int *type)
 
           if (res->type == KB_TYPE_INT)
             {
-              int old_value = res->v.v_int;
-              kb_item_rm_all (kb, name);
-              kb_item_add_int (kb, name, old_value);
               if (type != NULL)
-                *type = ARG_INT;
-              return GSIZE_TO_POINTER (old_value);
+                *type = KB_TYPE_INT;
+              return GSIZE_TO_POINTER (res->v_int);
             }
           else
             {
-              char *old_value = estrdup (res->v.v_str);
-              kb_item_rm_all (kb, name);
-              kb_item_add_str (kb, name, old_value);
               if (type != NULL)
-                *type = ARG_STRING;
-              efree (&old_value);
-              return kb_item_get_str (kb, name);
+                *type = KB_TYPE_STR;
+              return strdup (res->v_str);
             }
         }
       else if (pid < 0)
@@ -1278,7 +1176,6 @@ plug_get_key (struct arglist *args, char *name, int *type)
           fprintf (stderr,
                    "libopenvas:%s:%s(): fork() failed (%s)",
                    __FILE__, __func__, strerror (errno));
-
           return NULL;
         }
       else
@@ -1374,7 +1271,7 @@ plug_get_host_open_port (struct arglist *desc)
             break;
         }
 
-      kb_item_get_all_free (k);
+      kb_item_free (k);
       if (num_candidates != 0)
         return candidates[lrand48 () % num_candidates]; /* RATS: ignore */
       else if (open21)
diff --git a/openvas-libraries/misc/plugutils.h b/openvas-libraries/misc/plugutils.h
index dd3ea5e..9640c4e 100644
--- a/openvas-libraries/misc/plugutils.h
+++ b/openvas-libraries/misc/plugutils.h
@@ -102,7 +102,6 @@ char * host_get_port_banner(struct arglist *, int);
  */
 void plug_set_key (struct arglist *, char *, int, void *);
 void plug_replace_key (struct arglist *, char *, int, void *);
-void *plug_get_fresh_key (struct arglist *, char *, int *);
 kb_t plug_get_kb (struct arglist *);
 void *plug_get_key (struct arglist *, char *, int *);
 
diff --git a/openvas-libraries/nasl/CMakeLists.txt \
b/openvas-libraries/nasl/CMakeLists.txt index cd60464..d89dfbc 100644
--- a/openvas-libraries/nasl/CMakeLists.txt
+++ b/openvas-libraries/nasl/CMakeLists.txt
@@ -131,7 +131,7 @@ endif (BUILD_SHARED)
 if (BUILD_STATIC)
   add_executable (openvas-nasl nasl.c)
   target_link_libraries (openvas-nasl openvas_misc_static openvas_nasl_static
-    openvas_base_static ${GLIB_LDFLAGS} -lgcrypt
+    openvas_base_static ${GLIB_LDFLAGS} -lgcrypt -lgpg-error
     "${GPGME_LDFLAGS}" -lgnutls "${PCAP_LDFLAGS}" -lresolv -lm ${WMI_LIBS}
     ${GPGME_LDFLAGS} ${LIBSSH_LDFLAGS} ${KSBA_LDFLAGS} ${WINCMD_LIBS}) 
   set_target_properties (openvas-nasl PROPERTIES COMPILE_FLAGS
@@ -140,7 +140,7 @@ endif (BUILD_STATIC)
 if (BUILD_SHARED)
   add_executable (openvas-nasl nasl.c)
   target_link_libraries (openvas-nasl openvas_misc_shared openvas_nasl_shared
-    openvas_base_shared ${GLIB_LDFLAGS} -lgcrypt
+    openvas_base_shared ${GLIB_LDFLAGS} -lgcrypt -lgpg-error
     "${GPGME_LDFLAGS}" -lgnutls "${PCAP_LDFLAGS}" -lresolv -lm ${WMI_LIBS}
     ${GPGME_LDFLAGS} ${LIBSSH_LDFLAGS} ${KSBA_LDFLAGS} ${WINCMD_LIBS}) 
   set_target_properties (openvas-nasl PROPERTIES COMPILE_FLAGS
diff --git a/openvas-libraries/nasl/nasl.c b/openvas-libraries/nasl/nasl.c
index ae0700d..a41cad1 100644
--- a/openvas-libraries/nasl/nasl.c
+++ b/openvas-libraries/nasl/nasl.c
@@ -45,6 +45,9 @@
 #endif
 
 
+#define DEFAULT_KB_LOCATION "/tmp/redis.sock"
+
+
 extern char *nasl_version ();
 extern int execute_instruction (struct arglist *, char *);
 void exit_nasl (struct arglist *, int);
@@ -83,7 +86,7 @@ my_gnutls_log_func (int level, const char *text)
 }
 
 struct arglist *
-init (char *hostname, struct in6_addr ip)
+init (char *hostname, struct in6_addr ip, kb_t kb)
 {
   struct arglist *script_infos = g_malloc0 (sizeof (struct arglist));
   struct arglist *prefs = g_malloc0 (sizeof (struct arglist));
@@ -94,7 +97,7 @@ init (char *hostname, struct in6_addr ip)
   arg_add_value (script_infos, "standalone", ARG_INT, sizeof (int), (void *) 1);
   arg_add_value (prefs, "checks_read_timeout", ARG_STRING, 4, g_strdup ("5"));
   arg_add_value (script_infos, "preferences", ARG_ARGLIST, -1, prefs);
-  arg_add_value (script_infos, "key", ARG_PTR, -1, kb_new ());
+  arg_add_value (script_infos, "key", ARG_PTR, -1, kb);
 
   if (safe_checks_only != 0)
     arg_add_value (prefs, "safe_checks", ARG_STRING, 3, g_strdup ("yes"));
@@ -284,6 +287,8 @@ main (int argc, char **argv)
     {
       struct in6_addr ip6;
       char *hostname;
+      kb_t kb;
+      int rc;
 
       hostname = openvas_host_value_str (host);
       if (openvas_host_get_addr6 (host, &ip6) == -1)
@@ -293,7 +298,12 @@ main (int argc, char **argv)
           g_free (hostname);
           continue;
         }
-      script_infos = init (hostname, ip6);
+
+      rc = kb_new (&kb, DEFAULT_KB_LOCATION);
+      if (rc)
+        exit (1);
+
+      script_infos = init (hostname, ip6, kb);
       n = start;
       while (nasl_filenames[n])
         {
@@ -301,6 +311,7 @@ main (int argc, char **argv)
             err++;
           n++;
         }
+      kb_delete (kb);
       g_free (hostname);
     }
 
diff --git a/openvas-libraries/nasl/nasl_builtin_find_service.c \
b/openvas-libraries/nasl/nasl_builtin_find_service.c index d99401e..9283df7 100644
--- a/openvas-libraries/nasl/nasl_builtin_find_service.c
+++ b/openvas-libraries/nasl/nasl_builtin_find_service.c
@@ -2947,7 +2947,7 @@ plugin_run_find_service (lex_ctxt * lexic)
       kbitem_tmp = kbitem_tmp->next;
     }
 
-  kb_item_get_all_free (kbitem);
+  kb_item_free (kbitem);
 
 
   for (i = 0; i < num_sons; i++)
@@ -2973,6 +2973,7 @@ plugin_run_find_service (lex_ctxt * lexic)
             {
               int soc;
 
+              kb_lnk_reset (kb);
               soc = GPOINTER_TO_SIZE (arg_get_value (globals, "global_socket"));
               close (sons_pipe[i][1]);
               close (soc);
diff --git a/openvas-libraries/nasl/nasl_builtin_nmap.c \
b/openvas-libraries/nasl/nasl_builtin_nmap.c index fff7798..c26abe5 100644
--- a/openvas-libraries/nasl/nasl_builtin_nmap.c
+++ b/openvas-libraries/nasl/nasl_builtin_nmap.c
@@ -784,14 +784,14 @@ get_script_list (nmap_t * nmap)
   while (res)
     {
       scriptv = (gchar **) g_realloc (scriptv, (i + 1) * sizeof (gchar *));
-      scriptv[i++] = g_strdup (res->v.v_str);
+      scriptv[i++] = g_strdup (res->v_str);
       res = res->next;
     }
 
   scriptv = (gchar **) g_realloc (scriptv, (i + 1) * sizeof (gchar *));
   scriptv[i] = NULL;
 
-  kb_item_get_all_free (top);
+  kb_item_free (top);
 
   scriptstr = g_strjoinv (",", scriptv);
 
@@ -825,14 +825,14 @@ get_script_args (nmap_t * nmap)
   while (res)
     {
       argv = (gchar **) g_realloc (argv, (i + 1) * sizeof (gchar *));
-      argv[i++] = g_strdup (res->v.v_str);
+      argv[i++] = g_strdup (res->v_str);
       res = res->next;
     }
 
   argv = (gchar **) g_realloc (argv, (i + 1) * sizeof (gchar *));
   argv[i] = NULL;
 
-  kb_item_get_all_free (top);
+  kb_item_free (top);
 
   argstr = g_strjoinv (",", argv);
 
diff --git a/openvas-libraries/nasl/nasl_scanner_glue.c \
b/openvas-libraries/nasl/nasl_scanner_glue.c index 053ce4c..d29b9db 100644
--- a/openvas-libraries/nasl/nasl_scanner_glue.c
+++ b/openvas-libraries/nasl/nasl_scanner_glue.c
@@ -722,22 +722,22 @@ get_kb_list (lex_ctxt * lexic)
       if (res->type == KB_TYPE_INT)
         {
           v.var_type = VAR2_INT;
-          v.v.v_int = res->v.v_int;
+          v.v.v_int = res->v_int;
           add_var_to_array (a, res->name, &v);
           num_elems++;
         }
       else if (res->type == KB_TYPE_STR)
         {
           v.var_type = VAR2_DATA;
-          v.v.v_str.s_val = (unsigned char *) res->v.v_str;
-          v.v.v_str.s_siz = strlen (res->v.v_str);
+          v.v.v_str.s_val = (unsigned char *) res->v_str;
+          v.v.v_str.s_siz = strlen (res->v_str);
           add_var_to_array (a, res->name, &v);
           num_elems++;
         }
       res = res->next;
     }
 
-  kb_item_get_all_free (top);
+  kb_item_free (top);
 
   if (num_elems == 0)
     {
@@ -793,52 +793,12 @@ get_kb_item (lex_ctxt * lexic)
 }
 
 /**
- * Instead of reading the local copy of the KB, we ask the upstream
- * father the "newest" value of a given KB item. This is especially useful
- * when dealing with shared sockets and SSH.
+ * XXX Deprecated call.
  */
 tree_cell *
 get_kb_fresh_item (lex_ctxt * lexic)
 {
-  struct arglist *script_infos = lexic->script_infos;
-
-  char *kb_entry = get_str_var_by_num (lexic, 0);
-  char *val;
-  tree_cell *retc;
-  int type;
-
-  if (kb_entry == NULL)
-    return NULL;
-
-  val = plug_get_fresh_key (script_infos, kb_entry, &type);
-
-
-  if (val == NULL && type == -1)
-    return NULL;
-
-  retc = alloc_tree_cell (0, NULL);
-  if (type == KB_TYPE_INT)
-    {
-      retc->type = CONST_INT;
-      retc->x.i_val = GPOINTER_TO_SIZE (val);
-      return retc;
-    }
-  else
-    {
-      retc->type = CONST_DATA;
-      if (val != NULL)
-        {
-          retc->size = strlen (val);
-          retc->x.str_val = val;        /* Do NOT estrdup() the value, since \
                plug_get_fresh_key() allocated the memory already */
-        }
-      else
-        {
-          retc->size = 0;
-          retc->x.str_val = NULL;
-        }
-    }
-
-  return retc;
+  return get_kb_item (lexic);
 }
 
 tree_cell *
diff --git a/openvas-manager/src/CMakeLists.txt b/openvas-manager/src/CMakeLists.txt
index 5a54805..b512a16 100644
--- a/openvas-manager/src/CMakeLists.txt
+++ b/openvas-manager/src/CMakeLists.txt
@@ -49,7 +49,7 @@ set_target_properties (otp PROPERTIES COMPILE_FLAGS \
"${OPENVAS_CFLAGS} ${GLIB_CF  ## Program
 
 add_executable (openvasmd openvasmd.c ompd.c)
-target_link_libraries (openvasmd ovas-mngr-comm omp otp manage "${GNUTLS_LDFLAGS}")
+target_link_libraries (openvasmd ovas-mngr-comm omp otp manage -lgpg-error \
"${GNUTLS_LDFLAGS}")  
 set_target_properties (openvasmd PROPERTIES LINKER_LANGUAGE C)
 
diff --git a/openvas-scanner/doc/redis_config.txt \
b/openvas-scanner/doc/redis_config.txt new file mode 100644
index 0000000..fe3caea
--- /dev/null
+++ b/openvas-scanner/doc/redis_config.txt
@@ -0,0 +1,46 @@
+= Redis KB server =
+
+== Presentation ==
+Redis (http://redis.io) is used to store and access the KB. Scans won't run if
+they cannot access the server and might be significantly slowed down if redis is
+not properly configured.
+
+The feature has been developped with neither cluster mode nor replication
+enabled. Redis 2.4 and 2.6 are supported.
+
+
+== Connection ==
+OpenVAS can currently only access redis via a unix socket. This choice has been
+made for the sake of speed and security. No authentication is supported yet, we
+rely on filesystem permissions to protect the KBs.
+
+The path to the unix socket is '/tmp/redis.sock' by default, and can be changed
+using the 'kb_location' parameter.
+
+On the redis side, use the following directives:
+
+  port 0 # prevent redis from listening on a TCP socket
+  unixsocket /tmp/redis.sock
+  unixsocketperm 700
+  timeout 0
+
+
+== Database number ==
+Multiple KBs can be served in parallel, for multiple hosts scanned by one or
+several tasks. This is done using redis databases, which are independent
+namepaces. The DB#0, which is where every new connected client starts, is
+reserved and used to schedule concurrent accesses to the available namespaces.
+It contains a single variable, called 'OpenVAS.__GlobalDBIndex'. This variable
+is a bitmap of the different namespaces. When opening a new DB, the scanner will
+look for the first bit that is not set, starting from 1 to the maximum number of
+available DBs. If none is found, the scanner will enter a wait and retry loop.
+Otherwise, it will (atomically, along with the check) set the bit to 1 and
+switch to the selected namespace.
+
+It is therefore important that redis exports enough databases. This number can
+be calculated using the following formula:
+
+  #DB = 1 + (#of parallel tasks) * (#of parallel hosts)
+
+The desired/needed value should be set to redis.conf, as a 'databases'
+directive.
diff --git a/openvas-scanner/src/CMakeLists.txt b/openvas-scanner/src/CMakeLists.txt
index 63339fc..480279e 100644
--- a/openvas-scanner/src/CMakeLists.txt
+++ b/openvas-scanner/src/CMakeLists.txt
@@ -27,7 +27,7 @@
 
 add_executable (openvassd attack.c comm.c hosts.c locks.c log.c
                 nasl_plugins.c ntp_11.c openvassd.c otp_1_0.c
-                parser.c piic.c pluginlaunch.c pluginload.c
+                parser.c pluginlaunch.c pluginload.c
                 pluginscheduler.c plugs_req.c preferences.c
                 processes.c save_kb.c sighand.c utils.c)
 
@@ -135,7 +135,7 @@ add_dependencies (check splint rats flawfinder)
 
 set (C_FILES "attack.c" "comm.c" "hosts.c" "locks.c" "log.c"
      "nasl_plugins.c" "ntp_11.c" "openvassd.c" "otp_1_0.c"
-     "parser.c" "piic.c" "pluginlaunch.c" "pluginload.c"
+     "parser.c" "pluginlaunch.c" "pluginload.c"
      "pluginscheduler.c" "plugs_req.c" "preferences.c"
      "processes.c" "save_kb.c" "sighand.c" "utils.c")
 add_custom_target (etags COMMENT "Building TAGS..."
diff --git a/openvas-scanner/src/attack.c b/openvas-scanner/src/attack.c
index 684781b..e378c1e 100644
--- a/openvas-scanner/src/attack.c
+++ b/openvas-scanner/src/attack.c
@@ -571,12 +571,18 @@ init_host_kb (struct arglist *globals, char *hostname,
               struct arglist *hostinfos, gboolean * new_kb)
 {
   kb_t kb, network_kb;
-  (*new_kb) = FALSE;
-  char *vhosts = (char *) arg_get_value (hostinfos, "VHOSTS");
-  struct kb_item *host_network_results = NULL;
+  char *vhosts;
+  struct kb_item *host_network_results;
   struct kb_item *result_iter;
+  gchar *network_scan_status;
+  gchar *kb_path = scanner_kb_path (globals);
+  int rc;
+
+  (*new_kb) = FALSE;
+  vhosts = (char *)arg_get_value (hostinfos, "VHOSTS");
+  host_network_results = NULL;
 
-  gchar *network_scan_status = (gchar *) arg_get_value (globals, \
"network_scan_status"); +  network_scan_status = (gchar *) arg_get_value (globals, \
"network_scan_status");  if (network_scan_status != NULL)
     {
       if (g_ascii_strcasecmp (network_scan_status, "done") == 0)
@@ -590,7 +596,9 @@ init_host_kb (struct arglist *globals, char *hostname,
           arg_add_value (globals, "CURRENTLY_TESTED_HOST", ARG_STRING,
                          strlen ("network"), "network");
           save_kb_new (globals, "network");
-          kb = kb_new ();
+          rc = kb_new (&kb, kb_path);
+          if (rc)
+            return NULL;
           (*new_kb) = TRUE;
           return kb;
         }
@@ -609,7 +617,9 @@ init_host_kb (struct arglist *globals, char *hostname,
         {
           // We shall not or cannot restore.
           save_kb_new (globals, hostname);
-          kb = kb_new ();
+          rc = kb_new (&kb, kb_path);
+          if (rc)
+            return NULL;
           (*new_kb) = TRUE;
         }
  
@@ -618,7 +628,9 @@ init_host_kb (struct arglist *globals, char *hostname,
     }
   else                          /* save_kb(globals) */
     {
-      kb = kb_new ();
+      rc = kb_new (&kb, kb_path);
+      if (rc)
+        return NULL;
     }
 
   // Add local check (SSH)- related knowledge base items
@@ -643,13 +655,13 @@ init_host_kb (struct arglist *globals, char *hostname,
       char *newname = strstr (result_iter->name, "/") + 1;
       if (result_iter->type == KB_TYPE_STR)
         {
-          kb_item_add_str (kb, newname, result_iter->v.v_str);
-          save_kb_write_str (globals, hostname, newname, result_iter->v.v_str);
+          kb_item_add_str (kb, newname, result_iter->v_str);
+          save_kb_write_str (globals, hostname, newname, result_iter->v_str);
         }
       else if (result_iter->type == KB_TYPE_INT)
         {
-          kb_item_add_int (kb, newname, result_iter->v.v_int);
-          save_kb_write_int (globals, hostname, newname, result_iter->v.v_int);
+          kb_item_add_int (kb, newname, result_iter->v_int);
+          save_kb_write_int (globals, hostname, newname, result_iter->v_int);
         }
       result_iter = result_iter->next;
     }
@@ -667,7 +679,6 @@ attack_host (struct arglist *globals, struct arglist *hostinfos, \
char *hostname,  /* Used for the status */
   int num_plugs = 0;
   int cur_plug = 1;
-
   kb_t kb;
   gboolean new_kb = FALSE;
   int forks_retry = 0;
@@ -678,6 +689,8 @@ attack_host (struct arglist *globals, struct arglist *hostinfos, \
char *hostname,  (char *) arg_get_value (hostinfos, "NAME"));
 
   kb = init_host_kb (globals, hostname, hostinfos, &new_kb);
+  if (kb == NULL)
+    return;
 
   num_plugs = get_active_plugins_number (plugins);
 
@@ -791,6 +804,7 @@ host_died:
     if (new_kb == TRUE)
       save_kb_close (globals, hostname);
 
+  kb_delete (kb);
 }
 
 /**
diff --git a/openvas-scanner/src/piic.c b/openvas-scanner/src/piic.c
deleted file mode 100644
index 7b4f474..0000000
--- a/openvas-scanner/src/piic.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* OpenVAS
-* $Id$
-* Description: Reads from plugin output pipe, writes to arglist.
-*
-* 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 <stdio.h>  /* for printf() */
-#include <string.h> /* for strchr() */
-#include <stdlib.h> /* for atoi() */
-
-#include <openvas/misc/kb.h>         /* for kb_item_set_int */
-#include <openvas/misc/network.h>    /* for internal_recv */
-#include <openvas/misc/plugutils.h>  /* for rmslashes */
-#include <openvas/misc/internal_com.h>  /* for INTERNAL_COMM_MSG_TYPE_KB */
-#include <openvas/misc/system.h>     /* for efree */
-
-#include "log.h"
-#include "save_kb.h"
-#include "utils.h"
-#include "piic.h"
-
-/**
- * @brief Modifies the knowledge base or sends content of a kb item.
- *
- * If the knowledge base is going to be saved to disc, modify the entry on the
- * file system, too.
- *
- * @param soc "Internal" socket to the child process that queries the kb or
- *            requests modification.
- * @param msg Explicitly handled if INTERNAL_COMM_KB_GET,
- *            INTERNAL_COMM_KB_REPLACE (defined in plugutils.h)
- */
-void
-kb_parse (int soc, struct arglist *globals, struct kb_item **kb, char *buf,
-          int msg)
-{
-  char *t;
-  int type;
-  char *c;
-  int buf_len;
-  char *copy;
-  char *name;
-  char *value;
-
-  if (buf == NULL || kb == NULL)
-    return;
-
-  if (msg & INTERNAL_COMM_KB_GET)
-    {
-      struct kb_item *kitem = kb_item_get_single (kb, buf, 0);
-
-      if (kitem == NULL)
-        {
-          internal_send (soc, NULL,
-                         INTERNAL_COMM_MSG_TYPE_KB | INTERNAL_COMM_KB_ERROR);
-          return;
-        }
-
-      if (kitem->type == KB_TYPE_STR)
-        {
-          internal_send (soc, kitem->v.v_str,
-                         INTERNAL_COMM_MSG_TYPE_KB |
-                         INTERNAL_COMM_KB_SENDING_STR);
-          return;
-        }
-      else if (kitem->type == KB_TYPE_INT)
-        {
-          char buf[64];
-          snprintf (buf, sizeof (buf), "%d", kitem->v.v_int);
-          internal_send (soc, buf,
-                         INTERNAL_COMM_MSG_TYPE_KB |
-                         INTERNAL_COMM_KB_SENDING_INT);
-        }
-      else
-        internal_send (soc, NULL,
-                       INTERNAL_COMM_MSG_TYPE_KB | INTERNAL_COMM_KB_ERROR);
-
-      return;
-    }
-
-  if (buf[0] == '\0')
-    return;
-
-  buf_len = strlen (buf);
-
-  if (buf[buf_len - 1] == '\n')
-    buf[buf_len - 1] = '\0';
-
-  c = strrchr (buf, ';');
-  if (c != NULL)
-    c[0] = '\0';
-
-  t = strchr (buf, ' ');
-  if (t == NULL)
-    return;
-
-  t[0] = '\0';
-  type = atoi (buf);
-  t[0] = ' ';
-
-  value = strchr (buf, '=');
-
-  if (value == NULL)
-    return;
-
-  value[0] = '\0';
-  value++;
-
-  name = t + 1;
-
-  if (type == ARG_INT)
-    {
-      int v = atoi (value);
-      if (msg & INTERNAL_COMM_KB_REPLACE)
-        kb_item_set_int (kb, name, v);
-      else
-        {
-          kb_item_add_int (kb, name, v);
-          if (save_kb (globals))
-            save_kb_write_int (globals,
-                               arg_get_value (globals, "CURRENTLY_TESTED_HOST"),
-                               name, v);
-        }
-    }
-  else
-    {
-      copy = rmslashes (value);
-      if (msg & INTERNAL_COMM_KB_REPLACE)
-        kb_item_set_str (kb, name, copy);
-      else
-        {
-          kb_item_add_str (kb, name, copy);
-          if (save_kb (globals))
-            save_kb_write_str (globals,
-                               arg_get_value (globals, "CURRENTLY_TESTED_HOST"),
-                               name, copy);
-        }
-      efree (&copy);
-    }
-}
diff --git a/openvas-scanner/src/piic.h b/openvas-scanner/src/piic.h
deleted file mode 100644
index 0b810d1..0000000
--- a/openvas-scanner/src/piic.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* OpenVAS
-* $Id$
-* Description: header for piic.c.
-*
-* 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.
-*
-*
-*/
-
-
-#ifndef OPENVAS_PIIC_H
-#define OPENVAS_PIIC_H
-
-void kb_parse (int, struct arglist *, struct kb_item **, char *, int);
-#endif
diff --git a/openvas-scanner/src/pluginlaunch.c b/openvas-scanner/src/pluginlaunch.c
index 065aa4e..4456949 100644
--- a/openvas-scanner/src/pluginlaunch.c
+++ b/openvas-scanner/src/pluginlaunch.c
@@ -39,7 +39,6 @@
 #include <openvas/misc/system.h>     /* for efree */
 
 #include "pluginload.h"
-#include "piic.h"
 #include "utils.h"
 #include "preferences.h"
 #include "log.h"
@@ -116,8 +115,7 @@ process_internal_msg (int p)
   else if (type & INTERNAL_COMM_MSG_TYPE_KB)
     {
       e = 0;
-      kb_parse (processes[p].internal_soc, processes[p].globals,
-                processes[p].kb, buffer, type);
+      log_write ("Received an obsolete KB message. Ignoring.\n");
     }
   else if (type & INTERNAL_COMM_MSG_TYPE_CTRL)
     {
diff --git a/openvas-scanner/src/plugs_req.c b/openvas-scanner/src/plugs_req.c
index 945473d..5836423 100644
--- a/openvas-scanner/src/plugs_req.c
+++ b/openvas-scanner/src/plugs_req.c
@@ -106,10 +106,15 @@ key_missing (kb_t kb, struct arglist *keys)
     {
       while (keys->next != NULL)
         {
-          if (kb_item_get_single (kb, keys->name, 0) == NULL)
-            return keys->name;
-          else
-            keys = keys->next;
+          struct kb_item *kbi;
+
+          kbi = kb_item_get_single (kb, keys->name, KB_TYPE_UNSPEC);
+          if (kbi != NULL)
+            {
+              kb_item_free (kbi);
+              keys = keys->next;
+            }
+          else return keys->name;
         }
     }
   return NULL;
@@ -127,10 +132,15 @@ key_present (kb_t kb, struct arglist *keys)
     {
       while (keys->next != NULL)
         {
-          if (kb_item_get_single (kb, keys->name, 0) != NULL)
-            return keys->name;
-          else
-            keys = keys->next;
+          struct kb_item *kbi;
+
+          kbi = kb_item_get_single (kb, keys->name, KB_TYPE_UNSPEC);
+          if (kbi != NULL)
+            {
+              kb_item_free (kbi);
+              return keys->name;
+            }
+          else keys = keys->next;
         }
     }
   return NULL;
diff --git a/openvas-scanner/src/save_kb.c b/openvas-scanner/src/save_kb.c
index 6c27881..805d3bc 100644
--- a/openvas-scanner/src/save_kb.c
+++ b/openvas-scanner/src/save_kb.c
@@ -615,6 +615,7 @@ kb_t
 save_kb_load_kb (struct arglist *globals, char *hostname)
 {
   char *fname = kb_fname (hostname);
+  char *kb_path = scanner_kb_path (globals);
   FILE *f;
   int fd;
   kb_t kb;
@@ -644,7 +645,7 @@ save_kb_load_kb (struct arglist *globals, char *hostname)
       return NULL;
     }
 
-  kb = kb_new ();
+  kb_new (&kb, kb_path);
 
   /* Ignore the date */
   bzero (buf, sizeof (buf));
diff --git a/openvas-scanner/src/save_kb.h b/openvas-scanner/src/save_kb.h
index 99e3129..db3d574 100644
--- a/openvas-scanner/src/save_kb.h
+++ b/openvas-scanner/src/save_kb.h
@@ -33,6 +33,8 @@
 
 #include <openvas/misc/arglists.h>   /* for struct arglist */
 
+#define KB_PATH_DEFAULT "/tmp/redis.sock"
+
 int save_kb_new (struct arglist *, char *);
 void save_kb_close (struct arglist *, char *);
 
@@ -47,4 +49,15 @@ kb_t save_kb_load_kb (struct arglist *, char *);
 
 int save_kb (struct arglist *);
 
+static inline gchar *
+scanner_kb_path (struct arglist *globals)
+{
+  gchar *kb_path;
+
+  kb_path = (gchar *) arg_get_value (globals, "kb_location");
+  if (kb_path == NULL)
+    kb_path = KB_PATH_DEFAULT;
+
+  return kb_path;
+}
 #endif



_______________________________________________
Openvas-devel mailing list
Openvas-devel@wald.intevation.org
https://lists.wald.intevation.org/cgi-bin/mailman/listinfo/openvas-devel

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic