OpenVAS Libraries  9.0.3
kb_redis.c
Go to the documentation of this file.
1 /* OpenVAS Libraries
2  *
3  * Authors:
4  * Henri Doreau <henri.doreau@gmail.com>
5  *
6  * Copyright:
7  * Copyright (C) 2014 - Greenbone Networks GmbH.
8  *
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  *
24  * Knowledge base management API - Redis backend.
25  */
26 
27 #define _GNU_SOURCE
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdbool.h>
31 #include <string.h>
32 
33 #include <errno.h>
34 #include <ctype.h>
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <unistd.h>
39 
40 #include <hiredis/hiredis.h>
41 #include <glib.h>
42 
43 #include "kb.h"
44 
45 #undef G_LOG_DOMAIN
46 #define G_LOG_DOMAIN "lib kb_redis"
47 
59 #define GLOBAL_DBINDEX_NAME "OpenVAS.__GlobalDBIndex"
60 
65 #define KB_RETRY_DELAY 60
66 
67 
68 static const struct kb_operations KBRedisOperations;
69 
70 
76 struct kb_redis
77 {
78  struct kb kb;
79  unsigned int max_db;
80  unsigned int db;
81  redisContext *rctx;
82  char path[0];
83 };
84 #define redis_kb(__kb) ((struct kb_redis *)(__kb))
85 
89 struct redis_tx
90 {
91  struct kb_redis *kbr;
92  bool valid;
93 };
94 
95 
96 static int redis_delete_all (struct kb_redis *);
97 static int redis_lnk_reset (kb_t);
98 static int redis_flush_all (kb_t, const char *);
99 static redisReply *redis_cmd (struct kb_redis *kbr, const char *fmt, ...)
100  __attribute__((__format__(__printf__, 2, 3)));
101 
102 
106 static int
107 try_database_index (struct kb_redis *kbr, int index)
108 {
109  redisContext *ctx = kbr->rctx;
110  redisReply *rep;
111  int rc = 0;
112 
113  rep = redisCommand (ctx, "HSETNX %s %d 1", GLOBAL_DBINDEX_NAME, index);
114  if (rep == NULL)
115  return -ENOMEM;
116 
117  if (rep->type != REDIS_REPLY_INTEGER)
118  rc = -EPROTO;
119  else if (rep->integer == 0)
120  rc = -EALREADY;
121  else
122  kbr->db = index;
123 
124  freeReplyObject (rep);
125 
126  return rc;
127 }
128 
129 /* Redis 2.4.* compatibility mode.
130  *
131  * Before 2.6.* redis won't tell its clients how many databases have been
132  * configured. We can find it empirically by attempting to select a given
133  * DB and seeing whether we get an error or not.
134  */
135 #define MAX_DB_INDEX__24 1000
136 
137 static int
138 fetch_max_db_index_compat (struct kb_redis *kbr)
139 {
140  redisContext *ctx = kbr->rctx;
141  redisReply *rep;
142  int min, max;
143  int rc = 0;
144 
145  min = 1;
147 
148  while (min < max)
149  {
150  int current;
151 
152  current = min + ((max - min) / 2);
153 
154  rep = redisCommand (ctx, "SELECT %d", current);
155  if (rep == NULL)
156  {
157  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
158  "%s: redis command failed with '%s'", __func__, ctx->errstr);
159  return -1;
160  }
161 
162  switch (rep->type)
163  {
164  case REDIS_REPLY_ERROR:
165  max = current;
166  break;
167 
168  case REDIS_REPLY_STATUS:
169  min = current + 1;
170  break;
171 
172  default:
173  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
174  "%s: unexpected reply of type %d", __func__, rep->type);
175  freeReplyObject (rep);
176  return -1;
177  }
178  freeReplyObject (rep);
179  }
180 
181  kbr->max_db = min;
182 
183  /* Go back to DB #0 */
184  rep = redisCommand (ctx, "SELECT 0");
185  if (rep == NULL)
186  {
187  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
188  "%s: DB selection failed with '%s'", __func__, ctx->errstr);
189  rc = -1;
190  }
191 
192  if (rep)
193  freeReplyObject (rep);
194 
195  return rc;
196 }
197 
198 static int
199 fetch_max_db_index (struct kb_redis *kbr)
200 {
201  int rc = 0;
202  redisContext *ctx = kbr->rctx;
203  redisReply *rep = NULL;
204 
205  rep = redisCommand (ctx, "CONFIG GET databases");
206  if (rep == NULL)
207  {
208  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
209  "%s: redis command failed with '%s'", __func__, ctx->errstr);
210  rc = -1;
211  goto err_cleanup;
212  }
213 
214  if (rep->type != REDIS_REPLY_ARRAY)
215  {
216  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
217  "%s: cannot retrieve max DB number: %s", __func__, rep->str);
218  rc = -1;
219  goto err_cleanup;
220  }
221 
222  if (rep->elements == 0)
223  {
224  /* Redis 2.4 compatibility mode. Suboptimal... */
225  rc = fetch_max_db_index_compat (kbr);
226  }
227  else if (rep->elements == 2)
228  {
229  kbr->max_db = (unsigned)atoi(rep->element[1]->str);
230  }
231  else
232  {
233  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
234  "%s: unexpected reply length (%zd)", __func__, rep->elements);
235  rc = -1;
236  goto err_cleanup;
237  }
238 
239  g_debug ("%s: maximum DB number: %u", __func__, kbr->max_db);
240 
241 err_cleanup:
242  if (rep != NULL)
243  freeReplyObject (rep);
244 
245  return rc;
246 }
247 
252 static int
253 select_database (struct kb_redis *kbr)
254 {
255  int rc;
256  redisContext *ctx = kbr->rctx;
257  redisReply *rep = NULL;
258 
259  if (kbr->db == 0)
260  {
261  unsigned i;
262 
263  if (kbr->max_db == 0)
264  fetch_max_db_index (kbr);
265 
266  for (i = 1; i < kbr->max_db; i++)
267  {
268  rc = try_database_index (kbr, i);
269  if (rc == 0)
270  break;
271  }
272  }
273 
274  /* No DB available, give up. */
275  if (kbr->db == 0)
276  {
277  rc = -1;
278  goto err_cleanup;
279  }
280 
281  rep = redisCommand (ctx, "SELECT %u", kbr->db);
282  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
283  {
284  rc = -1;
285  goto err_cleanup;
286  }
287 
288  rc = 0;
289 
290 err_cleanup:
291  if (rep != NULL)
292  freeReplyObject (rep);
293 
294  return rc;
295 }
296 
297 static int
298 redis_release_db (struct kb_redis *kbr)
299 {
300  int rc;
301  redisContext *ctx = kbr->rctx;
302  redisReply *rep;
303 
304  if (ctx == NULL)
305  return -EINVAL;
306 
307  rep = redisCommand (ctx, "SELECT 0"); /* Management database*/
308  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
309  {
310  rc = -1;
311  goto err_cleanup;
312  }
313  freeReplyObject (rep);
314 
315  rep = redisCommand (ctx, "HDEL %s %d", GLOBAL_DBINDEX_NAME, kbr->db);
316  if (rep == NULL || rep->type != REDIS_REPLY_INTEGER)
317  {
318  rc = -1;
319  goto err_cleanup;
320  }
321 
322  rc = 0;
323 
324 err_cleanup:
325  if (rep != NULL)
326  freeReplyObject (rep);
327 
328  return rc;
329 }
330 
331 static redisContext *
332 get_redis_ctx (struct kb_redis *kbr)
333 {
334  int rc;
335 
336  if (kbr->rctx != NULL)
337  return kbr->rctx;
338 
339  do
340  {
341  kbr->rctx = redisConnectUnix (kbr->path);
342  if (kbr->rctx == NULL || kbr->rctx->err)
343  {
344  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
345  "%s: redis connection error: %s", __func__,
346  kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
347  redisFree (kbr->rctx);
348  kbr->rctx = NULL;
349  return NULL;
350  }
351 
352  rc = select_database (kbr);
353  if (rc)
354  {
355  g_debug ("%s: No redis DB available, retrying in %ds...", __func__,
357  sleep (KB_RETRY_DELAY);
358  redisFree (kbr->rctx);
359  kbr->rctx = NULL;
360  }
361  }
362  while (rc != 0);
363 
364  g_debug ("%s: connected to redis://%s/%d", __func__, kbr->path, kbr->db);
365  return kbr->rctx;
366 }
367 
368 static int
369 redis_test_connection (struct kb_redis *kbr)
370 {
371  int rc = 0;
372  redisReply *rep;
373 
374  rep = redis_cmd (kbr, "PING");
375  if (rep == NULL)
376  {
377  /* not 100% relevant but hiredis doesn't provide us with proper error
378  * codes. */
379  rc = -ECONNREFUSED;
380  goto out;
381  }
382 
383  if (rep->type != REDIS_REPLY_STATUS)
384  {
385  rc = -EINVAL;
386  goto out;
387  }
388 
389  if (g_ascii_strcasecmp (rep->str, "PONG"))
390  {
391  rc = -EPROTO;
392  goto out;
393  }
394 
395 out:
396  if (rep != NULL)
397  freeReplyObject (rep);
398 
399  return rc;
400 }
401 
402 static int
403 redis_delete (kb_t kb)
404 {
405  struct kb_redis *kbr;
406 
407  kbr = redis_kb (kb);
408 
409  redis_delete_all (kbr);
410  redis_release_db (kbr);
411 
412  if (kbr->rctx != NULL)
413  {
414  redisFree (kbr->rctx);
415  kbr->rctx = NULL;
416  }
417 
418  g_free (kb);
419  return 0;
420 }
421 
422 static int
423 redis_new (kb_t *kb, const char *kb_path)
424 {
425  struct kb_redis *kbr;
426  int rc = 0;
427 
428  kbr = g_malloc0 (sizeof (struct kb_redis) + strlen (kb_path) + 1);
429  kbr->kb.kb_ops = &KBRedisOperations;
430  strcpy (kbr->path, kb_path);
431 
432  rc = redis_test_connection (kbr);
433  if (rc)
434  {
435  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
436  "%s: cannot access redis at '%s'", __func__, kb_path);
437  redis_delete ((kb_t)kbr);
438  kbr = NULL;
439  }
440 
441  *kb = (kb_t)kbr;
442 
443  return rc;
444 }
445 
446 static kb_t
447 redis_find (const char *kb_path, const char *key)
448 {
449  struct kb_redis *kbr;
450  unsigned int i = 1;
451  redisReply *rep;
452 
453  kbr = g_malloc0 (sizeof (struct kb_redis) + strlen (kb_path) + 1);
454  kbr->kb.kb_ops = &KBRedisOperations;
455  strncpy (kbr->path, kb_path, strlen (kb_path));
456 
457  do
458  {
459  kbr->rctx = redisConnectUnix (kbr->path);
460  if (kbr->rctx == NULL || kbr->rctx->err)
461  {
462  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
463  "%s: redis connection error: %s", __func__,
464  kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
465  redisFree (kbr->rctx);
466  g_free (kbr);
467  return NULL;
468  }
469 
470  kbr->db = i;
471  rep = redisCommand (kbr->rctx, "HEXISTS %s %d", GLOBAL_DBINDEX_NAME, i);
472  if (rep == NULL || rep->type != REDIS_REPLY_INTEGER || rep->integer != 1)
473  {
474  if (rep != NULL)
475  freeReplyObject (rep);
476  i++;
477  continue;
478  }
479  freeReplyObject (rep);
480  rep = redisCommand (kbr->rctx, "SELECT %u", i);
481  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
482  {
483  sleep (KB_RETRY_DELAY);
484  kbr->rctx = NULL;
485  }
486  else
487  {
488  freeReplyObject (rep);
489  if (key && kb_item_get_int (&kbr->kb, key) > 0)
490  return (kb_t) kbr;
491  }
492  redisFree (kbr->rctx);
493  i++;
494  }
495  while (i < kbr->max_db);
496 
497  return NULL;
498 }
499 
500 void
501 kb_item_free (struct kb_item *item)
502 {
503  while (item != NULL)
504  {
505  struct kb_item *next;
506 
507  next = item->next;
508  if (item->type == KB_TYPE_STR && item->v_str != NULL)
509  g_free (item->v_str);
510  g_free (item);
511  item = next;
512  }
513 }
514 
515 static int
516 redis_transaction_new (struct kb_redis *kbr, struct redis_tx *rtx)
517 {
518  int rc = 0;
519  redisContext *ctx;
520  redisReply *rep = NULL;
521 
522  rtx->kbr = kbr;
523  rtx->valid = false;
524 
525  /* That is the quick, dirty & easy way to guarantee a fresh connection */
526  redis_lnk_reset ((kb_t)kbr);
527 
528  ctx = get_redis_ctx (kbr);
529  if (ctx == NULL)
530  return -1;
531 
532  rep = redisCommand (ctx, "MULTI");
533  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
534  {
535  rc = -1;
536  goto err_cleanup;
537  }
538 
539  rtx->valid = true;
540 
541 err_cleanup:
542  if (rep != NULL)
543  freeReplyObject (rep);
544 
545  return rc;
546 }
547 
548 static int
549 redis_transaction_cmd (struct redis_tx *rtx, const char *fmt, ...)
550 {
551  int rc = 0;
552  va_list ap;
553  redisReply *rep;
554 
555  if (!rtx->valid)
556  return -1;
557 
558  va_start (ap, fmt);
559 
560  rep = redisvCommand (rtx->kbr->rctx, fmt, ap);
561  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
562  {
563  rc = -1;
564  goto err_cleanup;
565  }
566 
567 err_cleanup:
568  va_end (ap);
569 
570  if (rc)
571  rtx->valid = false;
572 
573  if (rep != NULL)
574  freeReplyObject (rep);
575 
576  return rc;
577 }
578 
579 static int
580 redis_transaction_end (struct redis_tx *rtx, redisReply **rep)
581 {
582  int rc;
583  redisReply *preply;
584 
585  preply = NULL;
586 
587  if (!rtx->valid)
588  return -1;
589 
590  preply = redisCommand (rtx->kbr->rctx, "EXEC");
591  if (preply == NULL || preply->type == REDIS_REPLY_ERROR)
592  {
593  rc = -1;
594  goto err_cleanup;
595  }
596 
597  *rep = preply;
598  rc = 0;
599 
600 err_cleanup:
601 
602  if (rc)
603  {
604  freeReplyObject (preply);
605  *rep = NULL;
606  }
607 
608  memset (rtx, 0, sizeof (struct redis_tx));
609 
610  return rc;
611 }
612 
613 static struct kb_item *
614 redis2kbitem_single (const char *name, const redisReply *elt, int force_int)
615 {
616  struct kb_item *item;
617  size_t namelen;
618 
619  if (elt->type != REDIS_REPLY_STRING && elt->type != REDIS_REPLY_INTEGER)
620  return NULL;
621 
622  namelen = strlen (name) + 1;
623 
624  item = g_malloc0 (sizeof (struct kb_item) + namelen);
625  if (elt->type == REDIS_REPLY_INTEGER)
626  {
627  item->type = KB_TYPE_INT;
628  item->v_int = elt->integer;
629  }
630  else if (force_int)
631  {
632  item->type = KB_TYPE_INT;
633  item->v_int = atoi (elt->str);
634  }
635  else
636  {
637  item->type = KB_TYPE_STR;
638  item->v_str = g_strdup (elt->str);
639  }
640 
641  item->next = NULL;
642  item->namelen = namelen;
643  strcpy (item->name, name);
644 
645  return item;
646 }
647 
648 static struct kb_item *
649 redis2kbitem (const char *name, const redisReply *rep)
650 {
651  struct kb_item *kbi;
652 
653  kbi = NULL;
654 
655  switch (rep->type)
656  {
657  unsigned int i;
658 
659  case REDIS_REPLY_STRING:
660  case REDIS_REPLY_INTEGER:
661  kbi = redis2kbitem_single (name, rep, 0);
662  break;
663 
664  case REDIS_REPLY_ARRAY:
665  for (i = 0; i < rep->elements; i++)
666  {
667  struct kb_item *tmpitem;
668 
669  tmpitem = redis2kbitem_single (name, rep->element[i], 0);
670  if (tmpitem == NULL)
671  break;
672 
673  if (kbi != NULL)
674  {
675  tmpitem->next = kbi;
676  kbi = tmpitem;
677  }
678  else
679  kbi = tmpitem;
680  }
681  break;
682 
683  case REDIS_REPLY_NIL:
684  case REDIS_REPLY_STATUS:
685  case REDIS_REPLY_ERROR:
686  default:
687  break;
688  }
689 
690  return kbi;
691 }
692 
693 static redisReply *
694 redis_cmd (struct kb_redis *kbr, const char *fmt, ...)
695 {
696  redisReply *rep;
697  va_list ap, aq;
698  int retry = 0;
699 
700  va_start (ap, fmt);
701  do
702  {
703  redisContext *ctx;
704 
705  rep = NULL;
706 
707  ctx = get_redis_ctx (kbr);
708  if (ctx == NULL)
709  {
710  va_end (ap);
711  return NULL;
712  }
713 
714  va_copy (aq, ap);
715  rep = redisvCommand (ctx, fmt, aq);
716  va_end (aq);
717 
718  if (ctx->err)
719  {
720  if (rep != NULL)
721  freeReplyObject (rep);
722 
723  redis_lnk_reset ((kb_t)kbr);
724  retry = !retry;
725  }
726  else
727  retry = 0;
728  }
729  while (retry);
730 
731  va_end (ap);
732 
733  return rep;
734 }
735 
736 static struct kb_item *
737 redis_get_single (kb_t kb, const char *name, enum kb_item_type type)
738 {
739  struct kb_item *kbi;
740  struct kb_redis *kbr;
741  redisReply *rep;
742 
743  kbr = redis_kb (kb);
744  kbi = NULL;
745 
746  rep = redis_cmd (kbr, "SRANDMEMBER %s", name);
747  if (rep == NULL || rep->type != REDIS_REPLY_STRING)
748  {
749  kbi = NULL;
750  goto out;
751  }
752 
753  kbi = redis2kbitem_single (name, rep, type == KB_TYPE_INT);
754 
755 out:
756  if (rep != NULL)
757  freeReplyObject (rep);
758 
759  return kbi;
760 }
761 
762 static char *
763 redis_get_str (kb_t kb, const char *name)
764 {
765  struct kb_item *kbi;
766 
767  kbi = redis_get_single (kb, name, KB_TYPE_STR);
768  if (kbi != NULL)
769  {
770  char *res;
771 
772  res = kbi->v_str;
773  kbi->v_str = NULL;
774  kb_item_free (kbi);
775  return res;
776  }
777  return NULL;
778 }
779 
780 static int
781 redis_get_int (kb_t kb, const char *name)
782 {
783  struct kb_item *kbi;
784 
785  kbi = redis_get_single (kb, name, KB_TYPE_INT);
786  if (kbi != NULL)
787  {
788  int res;
789 
790  res = kbi->v_int;
791  kb_item_free (kbi);
792  return res;
793  }
794  return -1;
795 }
796 
797 static char *
798 redis_get_nvt (kb_t kb, const char *oid, enum kb_nvt_pos position)
799 {
800  struct kb_redis *kbr;
801  redisReply *rep;
802  char *res = NULL;
803 
804  kbr = redis_kb (kb);
805  rep = redis_cmd (kbr, "LINDEX nvt:%s %d", oid, position);
806  if (!rep)
807  return NULL;
808  if (rep->type == REDIS_REPLY_INTEGER)
809  res = g_strdup_printf ("%lld", rep->integer);
810  else if (rep->type == REDIS_REPLY_STRING)
811  res = g_strdup (rep->str);
812  freeReplyObject (rep);
813 
814  return res;
815 }
816 
817 static struct kb_item *
818 redis_get_all (kb_t kb, const char *name)
819 {
820  struct kb_redis *kbr;
821  struct kb_item *kbi;
822  redisReply *rep;
823 
824  kbr = redis_kb (kb);
825 
826  rep = redis_cmd (kbr, "SMEMBERS %s", name);
827  if (rep == NULL)
828  return NULL;
829 
830  kbi = redis2kbitem (name, rep);
831 
832  freeReplyObject (rep);
833 
834  return kbi;
835 }
836 
837 static struct kb_item *
838 redis_get_pattern (kb_t kb, const char *pattern)
839 {
840  struct kb_redis *kbr;
841  struct kb_item *kbi;
842  redisReply *rep;
843  unsigned int i;
844 
845  kbr = redis_kb (kb);
846  kbi = NULL;
847 
848  rep = redis_cmd (kbr, "KEYS %s", pattern);
849  if (rep == NULL)
850  return NULL;
851 
852  if (rep->type != REDIS_REPLY_ARRAY)
853  {
854  freeReplyObject (rep);
855  return NULL;
856  }
857 
858  for (i = 0; i < rep->elements; i++)
859  {
860  const char *key;
861  struct kb_item *tmp;
862  redisReply *rep_range;
863 
864  key = rep->element[i]->str;
865 
866  rep_range = redis_cmd (kbr, "SMEMBERS %s", key);
867  if (rep_range == NULL)
868  continue;
869 
870  tmp = redis2kbitem (key, rep_range);
871  if (tmp == NULL)
872  goto next; /* race condition, bah... */
873 
874  if (kbi != NULL)
875  {
876  struct kb_item *tmp2;
877 
878  tmp2 = tmp;
879  while (tmp->next != NULL)
880  tmp = tmp->next;
881 
882  tmp->next = kbi;
883  kbi = tmp2;
884  }
885  else
886  kbi = tmp;
887 
888 next:
889  if (rep_range != NULL)
890  freeReplyObject (rep_range);
891  }
892 
893  freeReplyObject (rep);
894 
895  return kbi;
896 }
897 
898 static size_t
899 redis_count (kb_t kb, const char *pattern)
900 {
901  struct kb_redis *kbr;
902  redisReply *rep;
903  size_t count;
904 
905  kbr = redis_kb (kb);
906 
907  rep = redis_cmd (kbr, "KEYS %s", pattern);
908  if (rep == NULL)
909  return 0;
910 
911  if (rep->type != REDIS_REPLY_ARRAY)
912  {
913  freeReplyObject (rep);
914  return 0;
915  }
916 
917  count = rep->elements;
918  freeReplyObject (rep);
919  return count;
920 }
921 
922 static int
923 redis_del_items (kb_t kb, const char *name)
924 {
925  struct kb_redis *kbr;
926  redisReply *rep;
927  int rc = 0;
928 
929  kbr = redis_kb (kb);
930 
931  rep = redis_cmd (kbr, "DEL %s", name);
932  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
933  rc = -1;
934 
935  if (rep != NULL)
936  freeReplyObject (rep);
937 
938  return rc;
939 }
940 
941 static int
942 redis_add_str (kb_t kb, const char *name, const char *str)
943 {
944  struct kb_redis *kbr;
945  redisReply *rep;
946  int rc = 0;
947 
948  kbr = redis_kb (kb);
949 
950  rep = redis_cmd (kbr, "SADD %s %s", name, str);
951  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
952  rc = -1;
953 
954  if (rep != NULL)
955  freeReplyObject (rep);
956 
957  return rc;
958 }
959 
960 static int
961 redis_set_str (kb_t kb, const char *name, const char *val)
962 {
963  struct kb_redis *kbr;
964  struct redis_tx rtx;
965  redisReply *rep;
966  int rc;
967 
968  kbr = redis_kb (kb);
969  rep = NULL;
970 
971  rc = redis_transaction_new (kbr, &rtx);
972  if (rc)
973  {
974  rc = -1;
975  goto out;
976  }
977 
978  redis_transaction_cmd (&rtx, "DEL %s", name);
979  redis_transaction_cmd (&rtx, "SADD %s %s", name, val);
980 
981  rc = redis_transaction_end (&rtx, &rep);
982  if (rc || rep == NULL || rep->type == REDIS_REPLY_ERROR)
983  {
984  rc = -1;
985  goto out;
986  }
987 
988 out:
989  if (rep != NULL)
990  freeReplyObject (rep);
991 
992  return rc;
993 }
994 
995 static int
996 redis_add_int (kb_t kb, const char *name, int val)
997 {
998  struct kb_redis *kbr;
999  redisReply *rep;
1000  int rc = 0;
1001 
1002  kbr = redis_kb (kb);
1003 
1004  rep = redis_cmd (kbr, "SADD %s %d", name, val);
1005  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
1006  {
1007  rc = -1;
1008  goto out;
1009  }
1010 
1011 out:
1012  if (rep != NULL)
1013  freeReplyObject (rep);
1014 
1015  return rc;
1016 }
1017 
1018 static int
1019 redis_set_int (kb_t kb, const char *name, int val)
1020 {
1021  struct kb_redis *kbr;
1022  struct redis_tx rtx;
1023  redisReply *rep;
1024  int rc;
1025 
1026  kbr = redis_kb (kb);
1027  rep = NULL;
1028 
1029  rc = redis_transaction_new (kbr, &rtx);
1030  if (rc)
1031  {
1032  rc = -1;
1033  goto out;
1034  }
1035 
1036  redis_transaction_cmd (&rtx, "DEL %s", name);
1037  redis_transaction_cmd (&rtx, "SADD %s %d", name, val);
1038 
1039  rc = redis_transaction_end (&rtx, &rep);
1040  if (rc || rep == NULL || rep->type == REDIS_REPLY_ERROR)
1041  {
1042  rc = -1;
1043  goto out;
1044  }
1045 
1046 out:
1047  if (rep != NULL)
1048  freeReplyObject (rep);
1049 
1050  return rc;
1051 }
1052 
1053 static int
1054 redis_add_nvt (kb_t kb, const nvti_t *nvt, const char *filename)
1055 {
1056  struct kb_redis *kbr;
1057  redisReply *rep = NULL;
1058  int rc = 0;
1059 
1060  if (!nvt || !filename)
1061  return -1;
1062 
1063  kbr = redis_kb (kb);
1064  rep = redis_cmd (kbr,
1065  "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %s %d %d %s %s"
1066  " %s %s",
1067  nvti_oid (nvt), filename, nvti_required_keys (nvt) ?: "",
1068  nvti_mandatory_keys (nvt) ?: "",
1069  nvti_excluded_keys (nvt) ?: "",
1070  nvti_required_udp_ports (nvt) ?: "",
1071  nvti_required_ports (nvt) ?: "",
1072  nvti_dependencies (nvt) ?: "", nvti_tag (nvt) ?: "",
1073  nvti_cve (nvt) ?: "", nvti_bid (nvt) ?: "",
1074  nvti_xref (nvt) ?: "", nvti_category (nvt),
1075  nvti_timeout (nvt), nvti_family (nvt), nvti_copyright (nvt),
1076  nvti_name (nvt), nvti_version (nvt));
1077  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
1078  rc = -1;
1079  if (rep != NULL)
1080  freeReplyObject (rep);
1081 
1082  rep = redis_cmd (kbr, "SADD filename:%s:oid %s", filename, nvti_oid (nvt));
1083  if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
1084  rc = -1;
1085  if (rep != NULL)
1086  freeReplyObject (rep);
1087 
1088  return rc;
1089 }
1090 
1091 static int
1092 redis_lnk_reset (kb_t kb)
1093 {
1094  struct kb_redis *kbr;
1095 
1096  kbr = redis_kb (kb);
1097 
1098  if (kbr->rctx != NULL)
1099  {
1100  redisFree (kbr->rctx);
1101  kbr->rctx = NULL;
1102  }
1103 
1104  return 0;
1105 }
1106 
1107 static int
1108 redis_flush_all (kb_t kb, const char *except)
1109 {
1110  unsigned int i = 1;
1111  struct kb_redis *kbr;
1112  redisReply *rep;
1113 
1114  kbr = redis_kb (kb);
1115  if (kbr->rctx)
1116  redisFree (kbr->rctx);
1117 
1118  g_debug ("%s: deleting all DBs at %s except %s", __func__, kbr->path, except);
1119  do
1120  {
1121  kbr->rctx = redisConnectUnix (kbr->path);
1122  if (kbr->rctx == NULL || kbr->rctx->err)
1123  {
1124  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
1125  "%s: redis connection error: %s", __func__,
1126  kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
1127  redisFree (kbr->rctx);
1128  kbr->rctx = NULL;
1129  return -1;
1130  }
1131 
1132  kbr->db = i;
1133  rep = redisCommand (kbr->rctx, "HEXISTS %s %d", GLOBAL_DBINDEX_NAME, i);
1134  if (rep == NULL || rep->type != REDIS_REPLY_INTEGER || rep->integer != 1)
1135  {
1136  freeReplyObject (rep);
1137  redisFree (kbr->rctx);
1138  i++;
1139  continue;
1140  }
1141  freeReplyObject (rep);
1142  rep = redisCommand (kbr->rctx, "SELECT %u", i);
1143  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
1144  {
1145  freeReplyObject (rep);
1146  sleep (KB_RETRY_DELAY);
1147  redisFree (kbr->rctx);
1148  kbr->rctx = NULL;
1149  }
1150  else
1151  {
1152  freeReplyObject (rep);
1153  /* Don't remove DB if it has "except" key. */
1154  if (except && kb_item_get_int (kb, except) > 0)
1155  {
1156  i++;
1157  redisFree (kbr->rctx);
1158  continue;
1159  }
1160  redis_delete_all (kbr);
1161  redis_release_db (kbr);
1162  redisFree (kbr->rctx);
1163  }
1164  i++;
1165  }
1166  while (i < kbr->max_db);
1167 
1168  g_free (kb);
1169  return 0;
1170 }
1171 
1172 int
1173 redis_delete_all (struct kb_redis *kbr)
1174 {
1175  int rc;
1176  redisReply *rep;
1177  struct sigaction new_action, original_action;
1178 
1179  /* Ignore SIGPIPE, in case of a lost connection. */
1180  new_action.sa_flags = 0;
1181  if (sigemptyset (&new_action.sa_mask))
1182  return -1;
1183  new_action.sa_handler = SIG_IGN;
1184  if (sigaction (SIGPIPE, &new_action, &original_action))
1185  return -1;
1186 
1187  g_debug ("%s: deleting all elements from KB #%u", __func__, kbr->db);
1188  rep = redis_cmd (kbr, "FLUSHDB");
1189  if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
1190  {
1191  rc = -1;
1192  goto err_cleanup;
1193  }
1194 
1195  rc = 0;
1196 
1197 err_cleanup:
1198  if (sigaction (SIGPIPE, &original_action, NULL))
1199  return -1;
1200  if (rep != NULL)
1201  freeReplyObject (rep);
1202 
1203  return rc;
1204 }
1205 
1206 
1207 static const struct kb_operations KBRedisOperations = {
1208  .kb_new = redis_new,
1209  .kb_find = redis_find,
1210  .kb_delete = redis_delete,
1211  .kb_get_single = redis_get_single,
1212  .kb_get_str = redis_get_str,
1213  .kb_get_int = redis_get_int,
1214  .kb_get_nvt = redis_get_nvt,
1215  .kb_get_all = redis_get_all,
1216  .kb_get_pattern = redis_get_pattern,
1217  .kb_count = redis_count,
1218  .kb_add_str = redis_add_str,
1219  .kb_set_str = redis_set_str,
1220  .kb_add_int = redis_add_int,
1221  .kb_set_int = redis_set_int,
1222  .kb_add_nvt = redis_add_nvt,
1223  .kb_del_items = redis_del_items,
1224  .kb_lnk_reset = redis_lnk_reset,
1225  .kb_flush = redis_flush_all,
1226 };
1227 
1228 const struct kb_operations *KBDefaultOperations = &KBRedisOperations;
kb_nvt_pos
Possible positions of nvt values in cache list.
Definition: kb.h:57
gchar * nvti_xref(const nvti_t *n)
Get the xref&#39;s.
Definition: nvti.c:302
#define GLOBAL_DBINDEX_NAME
Name of the namespace usage bitmap in redis.
Definition: kb_redis.c:59
Definition: kb.h:49
gchar * nvti_required_ports(const nvti_t *n)
Get the required ports list.
Definition: nvti.c:400
const char * val
Definition: nasl_init.c:525
gchar * nvti_copyright(const nvti_t *n)
Get the copyright notice.
Definition: nvti.c:260
unsigned int max_db
Definition: kb_redis.c:79
gchar * nvti_cve(const nvti_t *n)
Get the CVE references.
Definition: nvti.c:274
The structure of a information record that corresponds to a NVT.
Definition: nvti.h:64
#define max
Definition: nasl_wmi.c:61
Knowledge base item (defined by name, type (int/char*) and value). Implemented as a singly linked lis...
Definition: kb.h:81
struct kb_item * next
Definition: kb.h:91
const char * oid
enum kb_item_type type
Definition: kb.h:83
#define MAX_DB_INDEX__24
Definition: kb_redis.c:135
unsigned int db
Definition: kb_redis.c:80
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.
Definition: kb.h:118
gint nvti_category(const nvti_t *n)
Get the category for this NVT.
Definition: nvti.c:483
#define redis_kb(__kb)
Definition: kb_redis.c:84
redisContext * rctx
Definition: kb_redis.c:81
gint nvti_timeout(const nvti_t *n)
Get the timeout for this NVT.
Definition: nvti.c:470
gchar * nvti_tag(const nvti_t *n)
Get the tag.
Definition: nvti.c:316
struct kb_redis * kbr
Definition: kb_redis.c:91
#define KB_RETRY_DELAY
Number of seconds to wait for between two attempts to acquire a KB namespace.
Definition: kb_redis.c:65
gchar * nvti_family(const nvti_t *n)
Get the family name.
Definition: nvti.c:428
gchar * nvti_dependencies(const nvti_t *n)
Get the dependencies list.
Definition: nvti.c:344
Definition: kb.h:48
char path[0]
Definition: kb_redis.c:82
gchar * nvti_excluded_keys(const nvti_t *n)
Get the excluded keys list.
Definition: nvti.c:386
gchar * nvti_mandatory_keys(const nvti_t *n)
Get the mandatory keys list.
Definition: nvti.c:372
Top-level KB. This is to be inherited by KB implementations.
Definition: kb.h:102
const struct kb_operations * kb_ops
Definition: kb.h:104
Redis transaction handle.
Definition: kb_redis.c:89
void kb_item_free(struct kb_item *item)
Release a KB item (or a list).
Definition: kb_redis.c:501
const char * name
Definition: nasl_init.c:524
gchar * nvti_required_udp_ports(const nvti_t *n)
Get the required udp ports list.
Definition: nvti.c:414
struct kb kb
Definition: kb_redis.c:78
int v_int
Definition: kb.h:88
kb_item_type
Possible type of a kb_item.
Definition: kb.h:46
#define G_LOG_DOMAIN
Definition: kb_redis.c:46
size_t namelen
Definition: kb.h:93
Subclass of struct kb, it contains the redis-specific fields, such as the redis context, current DB (namespace) id and the server socket path.
Definition: kb_redis.c:76
struct kb * kb_t
type abstraction to hide KB internals.
Definition: kb.h:110
gchar * nvti_required_keys(const nvti_t *n)
Get the required keys list.
Definition: nvti.c:358
char name[0]
Definition: kb.h:94
gchar * nvti_oid(const nvti_t *n)
Get the OID string.
Definition: nvti.c:218
gchar * nvti_bid(const nvti_t *n)
Get the bid references.
Definition: nvti.c:288
bool valid
Definition: kb_redis.c:92
gchar * nvti_version(const nvti_t *n)
Get the version.
Definition: nvti.c:232
const struct kb_operations * KBDefaultOperations
Default KB operations. No selection mechanism is provided yet since there&#39;s only one implementation (...
Definition: kb_redis.c:1228
char * v_str
Definition: kb.h:87
int(* kb_new)(kb_t *, const char *)
Definition: kb.h:121
gchar * nvti_name(const nvti_t *n)
Get the name.
Definition: nvti.c:246