[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 (©);
- }
-}
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