[Libguestfs] [PATCH v3 5/6] New API: yara_scan

Matteo Cafasso
2016-12-18T10:47:10Z

The yara_scan API parses the file generated by the daemon counterpart
function and returns the list of yara_detection structs to the user.

It writes the daemon's command output on a temporary file and parses it,
deserialising the XDR formatted yara_detection structs.

It returns to the caller the list of yara_detection structs generated by
the internal_yara_scan command.

Signed-off-by: Matteo Cafasso <noxdafox@gmail.com>
---
 generator/actions.ml |  25 ++++++++++
 src/Makefile.am      |   1 +
 src/yara.c           | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 153 insertions(+)
 create mode 100644 src/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 75da607..c760b40 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3742,6 +3742,31 @@ Searches all the entries associated with the given inode.
 For each entry, a C<tsk_dirent> structure is returned.
 See C<filesystem_walk> for more information about C<tsk_dirent>
structures." };

+  { defaults with
+    name = "yara_scan"; added = (1, 35, 19);
+    style = RStructList ("detections", "yara_detection"),
[Pathname "path";], [];
+    optional = Some "libyara";
+    progress = true; cancellable = true;
+    shortdesc = "scan a file with the loaded yara rules";
+    longdesc = "\
+Scan a file with the previously loaded Yara rules.
+
+For each matching rule, a C<yara_detection> structure is returned.
+
+The C<tsk_dirent> structure contains the following fields.
+
+=over 4
+
+=item 'name'
+
+Path of the file matching a Yara rule.
+
+=item 'rule'
+
+Identifier of the Yara rule which matched against the given file.
+
+=back" };
+
 ]

 (* daemon_functions are any functions which cause some action
diff --git a/src/Makefile.am b/src/Makefile.am
index 8150d99..812ffbb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -133,6 +133,7 @@ libguestfs_la_SOURCES = \
 	wait.c \
 	whole-file.c \
 	version.c \
+	yara.c \
 	libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/src/yara.c b/src/yara.c
new file mode 100644
index 0000000..864766e
--- /dev/null
+++ b/src/yara.c
@@ -0,0 +1,127 @@
+/* libguestfs
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <rpc/xdr.h>
+#include <rpc/types.h>
+
+#include "guestfs.h"
+#include "guestfs_protocol.h"
+#include "guestfs-internal.h"
+#include "guestfs-internal-all.h"
+#include "guestfs-internal-actions.h"
+
+static struct guestfs_yara_detection_list *parse_yara_detection_file (guestfs_h
*, const char *);
+static int deserialise_yara_detection_list (guestfs_h *, FILE *, struct
guestfs_yara_detection_list *);
+
+struct guestfs_yara_detection_list *
+guestfs_impl_yara_scan (guestfs_h *g, const char *path)
+{
+  int ret = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = guestfs_int_make_temp_path (g, "yara_scan");
+  if (tmpfile == NULL)
+    return NULL;
+
+  ret = guestfs_internal_yara_scan (g, path, tmpfile);
+  if (ret < 0)
+    return NULL;
+
+  return parse_yara_detection_file (g, tmpfile);  /* caller frees */
+}
+
+/* Parse the file content and return detections list.
+ * Return a list of yara_detection on success, NULL on error.
+ */
+static struct guestfs_yara_detection_list *
+parse_yara_detection_file (guestfs_h *g, const char *tmpfile)
+{
+  int ret = 0;
+  CLEANUP_FCLOSE FILE *fp = NULL;
+  struct guestfs_yara_detection_list *detections = NULL;
+
+  fp = fopen (tmpfile, "r");
+  if (fp == NULL) {
+    perrorf (g, "fopen: %s", tmpfile);
+    return NULL;
+  }
+
+  /* Initialise results array. */
+  detections = safe_malloc (g, sizeof (*detections));
+  detections->len = 8;
+  detections->val = safe_malloc (g, detections->len *
+                                 sizeof (*detections->val));
+
+  /* Deserialise buffer into detection list. */
+  ret = deserialise_yara_detection_list (g, fp, detections);
+  if (ret < 0) {
+    guestfs_free_yara_detection_list (detections);
+    return NULL;
+  }
+
+  return detections;
+}
+
+/* Deserialise the file content and populate the detection list.
+ * Return the number of deserialised detections, -1 on error.
+ */
+static int
+deserialise_yara_detection_list (guestfs_h *g, FILE *fp,
+                                 struct guestfs_yara_detection_list
*detections)
+{
+  XDR xdr;
+  int ret = 0;
+  uint32_t index = 0;
+  struct stat statbuf;
+
+  ret = fstat (fileno(fp), &statbuf);
+  if (ret == -1)
+    return -1;
+
+  xdrstdio_create (&xdr, fp, XDR_DECODE);
+
+  for (index = 0; xdr_getpos (&xdr) < statbuf.st_size; index++) {
+    if (index == detections->len) {
+      detections->len = 2 * detections->len;
+      detections->val = safe_realloc (g, detections->val,
+                                      detections->len *
+                                      sizeof (*detections->val));
+    }
+
+    /* Clear the entry so xdr logic will allocate necessary memory. */
+    memset (&detections->val[index], 0, sizeof (*detections->val));
+    ret = xdr_guestfs_int_yara_detection (&xdr, (guestfs_int_yara_detection
*)
+                                          &detections->val[index]);
+    if (ret == 0)
+      break;
+  }
+
+  xdr_destroy (&xdr);
+  detections->len = index;
+
+  return ret ? 0 : -1;
+}
--
2.10.2