[Libguestfs] [PATCH 2/2] python: unicode decode handler error scheme setter

2017-05-21 Thread Matteo Cafasso
The set_decode_error_handler function allows the User to set the
decoding error scheme to be used when non UTF8 characters are
encountered in Python 3.

The function has no effect in Python 2.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml| 16 
 python/handle.c| 18 --
 python/t/test830RHBZ1406906.py |  6 ++
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/generator/python.ml b/generator/python.ml
index f7c1f80bb..66bb7f27d 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -82,6 +82,7 @@ put_handle (guestfs_h *g)
 }

 extern void guestfs_int_py_extend_module (PyObject *module);
+extern PyObject *guestfs_int_py_set_decode_error_handler (PyObject *self, 
PyObject *args);

 extern PyObject *guestfs_int_py_create (PyObject *self, PyObject *args);
 extern PyObject *guestfs_int_py_close (PyObject *self, PyObject *args);
@@ -577,6 +578,8 @@ and generate_python_module () =

   (* Table of functions. *)
   pr "static PyMethodDef methods[] = {\n";
+  pr "  { (char *) \"set_decode_error_handler\", \n";
+  pr "guestfs_int_py_set_decode_error_handler, METH_VARARGS, NULL },\n";
   pr "  { (char *) \"create\", guestfs_int_py_create, METH_VARARGS, NULL },\n";
   pr "  { (char *) \"close\", guestfs_int_py_close, METH_VARARGS, NULL },\n";
   pr "  { (char *) \"set_event_callback\",\n";
@@ -728,6 +731,19 @@ class ClosedHandle(ValueError):
 pass


+def set_decode_error_handler(handler):
+\"\"\"Set the error handling scheme to use for the handling
+of decoding errors.
+The default is 'strict' meaning that decoding errors raise a
+UnicodeDecodeError.
+
+The other possible value is 'surrogateescape', see PEP383 for reference.
+
+Return the previous error handler.
+\"\"\"
+return libguestfsmod.set_decode_error_handler(handler)
+
+
 class GuestFS(object):
 \"\"\"Instances of this class are libguestfs API handles.\"\"\"

diff --git a/python/handle.c b/python/handle.c
index 52c36f1d2..b665bb899 100644
--- a/python/handle.c
+++ b/python/handle.c
@@ -35,6 +35,8 @@

 #include "actions.h"

+static const char *decode_error_handler = "strict";
+
 static PyObject **get_all_event_callbacks (guestfs_h *g, size_t *len_rtn);

 void
@@ -45,6 +47,17 @@ guestfs_int_py_extend_module (PyObject *module)
 }

 PyObject *
+guestfs_int_py_set_decode_error_handler (PyObject *self, PyObject *args)
+{
+  const char *previous_handler = decode_error_handler;
+
+  if (!PyArg_ParseTuple (args, (char *) "s:set_decode_error_handler", 
_error_handler))
+return NULL;
+
+  return guestfs_int_py_fromstring (previous_handler);
+}
+
+PyObject *
 guestfs_int_py_create (PyObject *self, PyObject *args)
 {
   guestfs_h *g;
@@ -386,7 +399,8 @@ guestfs_int_py_fromstring (const char *str)
 #ifdef HAVE_PYSTRING_ASSTRING
   return PyString_FromString (str);
 #else
-  return PyUnicode_FromString (str);
+  Py_ssize_t size = strlen(str);
+  return PyUnicode_DecodeUTF8 (str, size, decode_error_handler);
 #endif
 }

@@ -396,7 +410,7 @@ guestfs_int_py_fromstringsize (const char *str, size_t size)
 #ifdef HAVE_PYSTRING_ASSTRING
   return PyString_FromStringAndSize (str, size);
 #else
-  return PyUnicode_FromStringAndSize (str, size);
+  return PyUnicode_DecodeUTF8 (str, size, decode_error_handler);
 #endif
 }

diff --git a/python/t/test830RHBZ1406906.py b/python/t/test830RHBZ1406906.py
index 17b875226..0bb1ac1d0 100644
--- a/python/t/test830RHBZ1406906.py
+++ b/python/t/test830RHBZ1406906.py
@@ -55,3 +55,9 @@ class Test830RHBZ1406906(unittest.TestCase):
 elif sys.version_info >= (2, 0):
 self.assertTrue(
 any(path for path in g.find("/") if non_utf8_fname in path))
+
+# change decoding error handler
+self.assertEqual(
+guestfs.set_decode_error_handler("surrogateescape"), 'strict')
+self.assertTrue(
+any(path for path in g.find("/") if non_utf8_fname in path))
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 1/2] python: return bytes when return value is RBufferOut

2017-05-21 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml |  3 ++-
 python/handle.c | 10 ++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/generator/python.ml b/generator/python.ml
index 4cae24757..f7c1f80bb 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -93,6 +93,7 @@ extern PyObject *guestfs_int_py_put_string_list (char * const 
* const argv);
 extern PyObject *guestfs_int_py_put_table (char * const * const argv);
 extern PyObject *guestfs_int_py_fromstring (const char *str);
 extern PyObject *guestfs_int_py_fromstringsize (const char *str, size_t size);
+extern PyObject *guestfs_int_py_bytesfromstringsize (const char *str, size_t 
size);
 extern char *guestfs_int_py_asstring (PyObject *obj);

 ";
@@ -513,7 +514,7 @@ and generate_python_actions actions () =
pr "  guestfs_int_free_string_list (r);\n";
pr "  if (py_r == NULL) goto out;\n";
| RBufferOut _ ->
-   pr "  py_r = guestfs_int_py_fromstringsize (r, size);\n";
+   pr "  py_r = guestfs_int_py_bytesfromstringsize (r, size);\n";
pr "  free (r);\n";
pr "  if (py_r == NULL) goto out;\n";
   );
diff --git a/python/handle.c b/python/handle.c
index d93f2f021..52c36f1d2 100644
--- a/python/handle.c
+++ b/python/handle.c
@@ -400,6 +400,16 @@ guestfs_int_py_fromstringsize (const char *str, size_t 
size)
 #endif
 }

+PyObject *
+guestfs_int_py_bytesfromstringsize (const char *str, size_t size)
+{
+#ifdef HAVE_PYSTRING_ASSTRING
+  return PyString_FromStringAndSize (str, size);
+#else
+  return PyBytes_FromStringAndSize (str, size);
+#endif
+}
+
 char *
 guestfs_int_py_asstring (PyObject *obj)
 {
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 0/2] python: improved UTF8 decoding error handling

2017-05-21 Thread Matteo Cafasso
The Python 3 bindings currently are unable to deal with non UTF8 characters.
This series continues what proposed in RHBZ#1406906.

A new function 'set_decode_error_handler' allows the User to specify
how to deal with decoding errors.

The default behaviour will be raising a UnicodeDecodeError.
If the handler is changed to 'surrogateescape', non UTF8 characters will be 
escaped
in a similar manner as for Python 2.

See PEP383 for reference.

This series fixes also a bug introduced in commit 
9d25b4e56471f9c33ea6229a8b620fc800c240f8.

Matteo Cafasso (2):
  python: return bytes when return value is RBufferOut
  python: unicode decode handler error scheme setter

 generator/python.ml| 19 ++-
 python/handle.c| 28 ++--
 python/t/test830RHBZ1406906.py |  6 ++
 3 files changed, 50 insertions(+), 3 deletions(-)

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2] RHBZ#1406906: check return value of Python object functions

2017-05-11 Thread Matteo Cafasso
Verify the returned values of Python Object constructor functions
are not NULL before adding them to a collection.

This is particularly relevant when constructing Unicode strings in
Python 3 as they will return NULL if non UTF-8 characters are present.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml| 102 ++---
 python/handle.c|  36 ---
 python/t/test830RHBZ1406906.py |  57 +++
 3 files changed, 152 insertions(+), 43 deletions(-)
 create mode 100644 python/t/test830RHBZ1406906.py

diff --git a/generator/python.ml b/generator/python.ml
index cf0829489..4cae24757 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -155,12 +155,20 @@ and generate_python_structs () =
 pr "PyObject *\n";
 pr "guestfs_int_py_put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ 
typ;
 pr "{\n";
-pr "  PyObject *list;\n";
+pr "  PyObject *list, *element;\n";
 pr "  size_t i;\n";
 pr "\n";
 pr "  list = PyList_New (%ss->len);\n" typ;
-pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
-pr "PyList_SetItem (list, i, guestfs_int_py_put_%s (&%ss->val[i]));\n" 
typ typ;
+pr "  if (list == NULL)\n";
+pr "return NULL;\n";
+pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
+pr "element = guestfs_int_py_put_%s (&%ss->val[i]);\n" typ typ;
+pr "if (element == NULL) {\n";
+pr "  Py_CLEAR (list);\n";
+pr "  return NULL;\n";
+pr "}\n";
+pr "PyList_SetItem (list, i, element);\n";
+pr "  }\n";
 pr "  return list;\n";
 pr "};\n";
 pr "#endif\n";
@@ -174,54 +182,72 @@ and generate_python_structs () =
   pr "PyObject *\n";
   pr "guestfs_int_py_put_%s (struct guestfs_%s *%s)\n" typ typ typ;
   pr "{\n";
-  pr "  PyObject *dict;\n";
+  pr "  PyObject *dict, *value;\n";
   pr "\n";
   pr "  dict = PyDict_New ();\n";
+  pr "  if (dict == NULL)\n";
+  pr "return NULL;\n";
   List.iter (
 function
 | name, FString ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "guestfs_int_py_fromstring (%s->%s));\n"
-  typ name
+pr "  value = guestfs_int_py_fromstring (%s->%s);" typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FBuffer ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "guestfs_int_py_fromstringsize (%s->%s, 
%s->%s_len));\n"
-  typ name typ name
+pr "  value = guestfs_int_py_fromstringsize (%s->%s, 
%s->%s_len);\n"
+  typ name typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FUUID ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "guestfs_int_py_fromstringsize (%s->%s, 
32));\n"
-  typ name
+pr "  value = guestfs_int_py_fromstringsize (%s->%s, 32);\n"
+  typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, (FBytes|FUInt64) ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "PyLong_FromUnsignedLongLong 
(%s->%s));\n"
-  typ name
+pr "  value = PyLong_FromUnsignedLongLong (%s->%s);\n" typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FInt64 ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "PyLong_FromLongLong (%s->%s));\n"
-  typ name
+pr "  value = PyLong_FromLongLong (%s->%s);\n" typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n&qu

[Libguestfs] [PATCH] RHBZ#1406906: check return value of Python object functions

2017-05-09 Thread Matteo Cafasso
Verify the returned values of Python Object constructor functions
are not NULL before adding them to a collection.

This is particularly relevant when constructing Unicode strings in
Python 3 as they will return NULL if non UTF-8 characters are present.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml| 102 ++---
 python/handle.c|  34 +++---
 python/t/test830RHBZ1406906.py |  51 +
 3 files changed, 145 insertions(+), 42 deletions(-)
 create mode 100644 python/t/test830RHBZ1406906.py

diff --git a/generator/python.ml b/generator/python.ml
index cf0829489..4cae24757 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -155,12 +155,20 @@ and generate_python_structs () =
 pr "PyObject *\n";
 pr "guestfs_int_py_put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ 
typ;
 pr "{\n";
-pr "  PyObject *list;\n";
+pr "  PyObject *list, *element;\n";
 pr "  size_t i;\n";
 pr "\n";
 pr "  list = PyList_New (%ss->len);\n" typ;
-pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
-pr "PyList_SetItem (list, i, guestfs_int_py_put_%s (&%ss->val[i]));\n" 
typ typ;
+pr "  if (list == NULL)\n";
+pr "return NULL;\n";
+pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
+pr "element = guestfs_int_py_put_%s (&%ss->val[i]);\n" typ typ;
+pr "if (element == NULL) {\n";
+pr "  Py_CLEAR (list);\n";
+pr "  return NULL;\n";
+pr "}\n";
+pr "PyList_SetItem (list, i, element);\n";
+pr "  }\n";
 pr "  return list;\n";
 pr "};\n";
 pr "#endif\n";
@@ -174,54 +182,72 @@ and generate_python_structs () =
   pr "PyObject *\n";
   pr "guestfs_int_py_put_%s (struct guestfs_%s *%s)\n" typ typ typ;
   pr "{\n";
-  pr "  PyObject *dict;\n";
+  pr "  PyObject *dict, *value;\n";
   pr "\n";
   pr "  dict = PyDict_New ();\n";
+  pr "  if (dict == NULL)\n";
+  pr "return NULL;\n";
   List.iter (
 function
 | name, FString ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "guestfs_int_py_fromstring (%s->%s));\n"
-  typ name
+pr "  value = guestfs_int_py_fromstring (%s->%s);" typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FBuffer ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "guestfs_int_py_fromstringsize (%s->%s, 
%s->%s_len));\n"
-  typ name typ name
+pr "  value = guestfs_int_py_fromstringsize (%s->%s, 
%s->%s_len);\n"
+  typ name typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FUUID ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "guestfs_int_py_fromstringsize (%s->%s, 
32));\n"
-  typ name
+pr "  value = guestfs_int_py_fromstringsize (%s->%s, 32);\n"
+  typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, (FBytes|FUInt64) ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "PyLong_FromUnsignedLongLong 
(%s->%s));\n"
-  typ name
+pr "  value = PyLong_FromUnsignedLongLong (%s->%s);\n" typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FInt64 ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
-pr "PyLong_FromLongLong (%s->%s));\n"
-  typ name
+pr "  value = PyLong_FromLongLong (%s->%s);\n" typ name;
+pr "  if (value == NULL)\n";
+pr "goto err;\n&qu

[Libguestfs] [Bug 1406906] [PATCH 1/3] generator: check return value of Python object functions

2017-05-06 Thread Matteo Cafasso
Verify the returned values of Python Object constructor functions
are not NULL before adding them to a collection.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml | 119 +++-
 1 file changed, 72 insertions(+), 47 deletions(-)

diff --git a/generator/python.ml b/generator/python.ml
index 0162733f9..ace15d3e0 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -152,12 +152,20 @@ and generate_python_structs () =
 pr "PyObject *\n";
 pr "guestfs_int_py_put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ 
typ;
 pr "{\n";
-pr "  PyObject *list;\n";
+pr "  PyObject *list, *element;\n";
 pr "  size_t i;\n";
 pr "\n";
 pr "  list = PyList_New (%ss->len);\n" typ;
-pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
-pr "PyList_SetItem (list, i, guestfs_int_py_put_%s (&%ss->val[i]));\n" 
typ typ;
+pr "  if (list == NULL)\n";
+pr "return NULL;\n";
+pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
+pr "element = guestfs_int_py_put_%s (&%ss->val[i]);\n" typ typ;
+pr "if (element == NULL) {\n";
+pr "  Py_CLEAR (list);\n";
+pr "  return NULL;\n";
+pr "}\n";
+pr "PyList_SetItem (list, i, element);\n";
+pr "  }\n";
 pr "  return list;\n";
 pr "};\n";
 pr "#endif\n";
@@ -171,75 +179,88 @@ and generate_python_structs () =
   pr "PyObject *\n";
   pr "guestfs_int_py_put_%s (struct guestfs_%s *%s)\n" typ typ typ;
   pr "{\n";
-  pr "  PyObject *dict;\n";
+  pr "  PyObject *dict, *value;\n";
   pr "\n";
   pr "  dict = PyDict_New ();\n";
+  pr "  if (dict == NULL)\n";
+  pr "return NULL;\n";
   List.iter (
 function
 | name, FString ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromString (%s->%s));\n"
-  typ name;
+pr "  value = PyString_FromString (%s->%s);\n" typ name;
 pr "#else\n";
-pr "PyUnicode_FromString (%s->%s));\n"
-  typ name;
-pr "#endif\n"
+pr "  value = PyUnicode_FromString (%s->%s);\n" typ name;
+pr "#endif\n";
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FBuffer ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromStringAndSize (%s->%s, 
%s->%s_len));\n"
+pr "  value = PyString_FromStringAndSize (%s->%s, %s->%s_len);\n"
   typ name typ name;
 pr "#else\n";
-pr "PyBytes_FromStringAndSize (%s->%s, 
%s->%s_len));\n"
+pr "  value = PyBytes_FromStringAndSize (%s->%s, %s->%s_len);\n"
   typ name typ name;
-pr "#endif\n"
+pr "#endif\n";
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FUUID ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromStringAndSize (%s->%s, 
32));\n"
-  typ name;
+pr "  value = PyString_FromStringAndSize (%s->%s, 32);\n" typ name;
 pr "#else\n";
-pr "PyBytes_FromStringAndSize (%s->%s, 
32));\n"
-  typ name;
-pr "#endif\n"
+pr "  value = PyBytes_FromStringAndSize (%s->%s, 32);\n" typ name;
+pr "#endif\n";
+pr "  if (value == NULL)\n";
+pr "goto err;\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, (FBytes|FUInt64) ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" na

[Libguestfs] [Bug 1406906] [PATCH 0/3] Fix segmentation fault in Python bindings

2017-05-06 Thread Matteo Cafasso
This series addresses the issue where non UTF8 file names in a guest image lead 
to libguestfs segfault with Python 3 APIs.

The core issue is the APIs are not checking the return value when constructing 
a new PyObject. Therefore NULL pointers are added to Python collections (lists 
and dictionaries) crashing the application.

Few notes regarding the comments on the previous patch.

- Added a regression test file
- Removed the Exception string setter functions as Python APIs already set them 
in case of error
  https://docs.python.org/3.6/c-api/exceptions.html#exception-handling (third 
paragraph)
- Fixed functions in python/handle.c
- Correctly clear and decrement the refcount of the list/dictionary object 
before returning on error

Matteo Cafasso (3):
  generator: check return value of Python object functions
  python: check return value of object functions in handle.c
  python: add regression test for RHBZ#1406906

 generator/python.ml| 119 +
 python/handle.c|  48 +
 python/t/test830RHBZ1406906.py |  55 +++
 3 files changed, 165 insertions(+), 57 deletions(-)
 create mode 100644 python/t/test830RHBZ1406906.py

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [Bug #1406906] [PATCH] python: fix segmentation fault when setting non UTF-8 strings

2017-04-25 Thread Matteo Cafasso
When constructing the returned objects, check the return value of
Python APIs.

A RuntimeError will be raised on failure pointing to the problematic
entry and the field name.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml | 143 +++-
 1 file changed, 97 insertions(+), 46 deletions(-)

diff --git a/generator/python.ml b/generator/python.ml
index 11dc48102..7d86131b1 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -152,12 +152,20 @@ and generate_python_structs () =
 pr "PyObject *\n";
 pr "guestfs_int_py_put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ 
typ;
 pr "{\n";
-pr "  PyObject *list;\n";
+pr "  PyObject *list, *element;\n";
 pr "  size_t i;\n";
 pr "\n";
 pr "  list = PyList_New (%ss->len);\n" typ;
-pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
-pr "PyList_SetItem (list, i, guestfs_int_py_put_%s (&%ss->val[i]));\n" 
typ typ;
+pr "  if (list == NULL) {\n";
+pr "PyErr_SetString (PyExc_RuntimeError, \"PyList_New\");\n";
+pr "return NULL;\n";
+pr "  }\n";
+pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
+pr "element = guestfs_int_py_put_%s (&%ss->val[i]);\n" typ typ;
+pr "if (element == NULL)\n";
+pr "  return NULL;\n";
+pr "PyList_SetItem (list, i, element);\n";
+pr "  }\n";
 pr "  return list;\n";
 pr "};\n";
 pr "#endif\n";
@@ -171,73 +179,112 @@ and generate_python_structs () =
   pr "PyObject *\n";
   pr "guestfs_int_py_put_%s (struct guestfs_%s *%s)\n" typ typ typ;
   pr "{\n";
-  pr "  PyObject *dict;\n";
+  pr "  PyObject *dict, *value;\n";
   pr "\n";
   pr "  dict = PyDict_New ();\n";
+  pr "  if (dict == NULL) {\n";
+  pr "PyErr_SetString (PyExc_RuntimeError, \"PyDict_New\");\n";
+  pr "return NULL;\n";
+  pr "  }\n";
   List.iter (
 function
 | name, FString ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromString (%s->%s));\n"
-  typ name;
+pr "  value = PyString_FromString (%s->%s);\n" typ name;
 pr "#else\n";
-pr "PyUnicode_FromString (%s->%s));\n"
-  typ name;
-pr "#endif\n"
+pr "  value = PyUnicode_FromString (%s->%s);\n" typ name;
+pr "#endif\n";
+pr "  if (value == NULL) {\n";
+pr "PyErr_SetString (PyExc_RuntimeError,\n";
+pr " \"Error setting %s.%s\");\n" typ name;
+pr "return NULL;\n";
+pr "  }\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FBuffer ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromStringAndSize (%s->%s, 
%s->%s_len));\n"
+pr "  value = PyString_FromStringAndSize (%s->%s, %s->%s_len);\n"
   typ name typ name;
 pr "#else\n";
-pr "PyBytes_FromStringAndSize (%s->%s, 
%s->%s_len));\n"
+pr "  value = PyBytes_FromStringAndSize (%s->%s, %s->%s_len);\n"
   typ name typ name;
-pr "#endif\n"
+pr "#endif\n";
+pr "  if (value == NULL) {\n";
+pr "PyErr_SetString (PyExc_RuntimeError,\n";
+pr " \"Error setting %s.%s\");\n" typ name;
+pr "return NULL;\n";
+pr "  }\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FUUID ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromStringAndSize (%s->%s, 
32));\n"
-  typ name;
+pr "  value = PyString_FromStringAndSize (%s->%s, 32);\n" typ name;
  

[Libguestfs] [PATCH v9 1/7] daemon: expose file upload logic

2017-04-25 Thread Matteo Cafasso
Allows other modules to use the same logic for uploading files.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/daemon.h |  3 +++
 daemon/upload.c | 66 -
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index 5137e2c2a..75af5246e 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -261,6 +261,9 @@ extern int64_t ntfs_minimum_size (const char *device);
 extern int swap_set_uuid (const char *device, const char *uuid);
 extern int swap_set_label (const char *device, const char *label);

+/*-- in upload.c --*/
+extern int upload_to_fd (int fd, const char *filename);
+
 /* ordinary daemon functions use these to indicate errors
  * NB: you don't need to prefix the string with the current command,
  * it is added automatically by the client-side RPC stubs.
diff --git a/daemon/upload.c b/daemon/upload.c
index dc467d62b..8aaeb2570 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -56,19 +56,50 @@ write_cb (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+int
+upload_to_fd (int fd, const char *filename)
+{
+  int r, err;
+  struct write_cb_data data = { .fd = fd, .written = 0 };
+
+  r = receive_file (write_cb, );
+  if (r == -1) {   /* write error */
+err = errno;
+ignore_value (cancel_receive ());
+errno = err;
+reply_with_error ("write error: %s", filename);
+close (fd);
+return -1;
+  }
+  if (r == -2) {   /* cancellation from library */
+/* This error is ignored by the library since it initiated the
+ * cancel.  Nevertheless we must send an error reply here.
+ */
+reply_with_error ("file upload cancelled");
+close (fd);
+return -1;
+  }
+
+  if (close (fd) == -1) {
+reply_with_perror ("close");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Has one FileIn parameter. */
 static int
 upload (const char *filename, int flags, int64_t offset)
 {
-  struct write_cb_data data = { .written = 0 };
-  int err, r, is_dev;
+  int err, is_dev, fd;

   is_dev = STRPREFIX (filename, "/dev/");

   if (!is_dev) CHROOT_IN;
-  data.fd = open (filename, flags, 0666);
+  fd = open (filename, flags, 0666);
   if (!is_dev) CHROOT_OUT;
-  if (data.fd == -1) {
+  if (fd == -1) {
 err = errno;
 ignore_value (cancel_receive ());
 errno = err;
@@ -77,7 +108,7 @@ upload (const char *filename, int flags, int64_t offset)
   }

   if (offset) {
-if (lseek (data.fd, offset, SEEK_SET) == -1) {
+if (lseek (fd, offset, SEEK_SET) == -1) {
   err = errno;
   ignore_value (cancel_receive ());
   errno = err;
@@ -86,30 +117,7 @@ upload (const char *filename, int flags, int64_t offset)
 }
   }

-  r = receive_file (write_cb, );
-  if (r == -1) {   /* write error */
-err = errno;
-ignore_value (cancel_receive ());
-errno = err;
-reply_with_error ("write error: %s", filename);
-close (data.fd);
-return -1;
-  }
-  if (r == -2) {   /* cancellation from library */
-/* This error is ignored by the library since it initiated the
- * cancel.  Nevertheless we must send an error reply here.
- */
-reply_with_error ("file upload cancelled");
-close (data.fd);
-return -1;
-  }
-
-  if (close (data.fd) == -1) {
-reply_with_perror ("close: %s", filename);
-return -1;
-  }
-
-  return 0;
+  return upload_to_fd (fd, filename);
 }

 /* Has one FileIn parameter. */
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v9 3/7] New API: yara_load

2017-04-25 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am |   1 +
 daemon/cleanups.c  |   9 ++
 daemon/cleanups.h  |   2 +
 daemon/yara.c  | 215 +
 generator/Makefile.am  |   3 +
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  48 ++
 generator/actions_yara.mli |  21 +
 generator/proc_nr.ml   |   1 +
 lib/MAX_PROC_NR|   2 +-
 10 files changed, 303 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ca01aeb4e..68f863bcd 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -170,6 +170,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493d7..3102cf94b 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e2744..a791244cb 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0..a1e3aa878
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,215 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#ifdef HAVE_ATTRIBUTE_CLEANUP
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+#else
+#define CLEANUP_DESTROY_YARA_COMPILER
+#endif
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (void)
+{
+  int r;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  r = upload_to_fd (fd, tmpfile);
+  if (r == -1) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+r = yr_initialize ();
+if (r != ERROR_SUCCESS) {
+  rep

[Libguestfs] [PATCH v9 6/7] New API: yara_scan

2017-04-25 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  28 ++
 generator/actions_yara.mli |   1 +
 lib/Makefile.am|   1 +
 lib/yara.c | 132 +
 5 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 lib/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 6e11d99c3..2722f3dcd 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -38,7 +38,8 @@ let non_daemon_functions =
   Actions_inspection_deprecated.non_daemon_functions @
   Actions_properties.non_daemon_functions @
   Actions_properties_deprecated.non_daemon_functions @
-  Actions_tsk.non_daemon_functions
+  Actions_tsk.non_daemon_functions @
+  Actions_yara.non_daemon_functions

 (* daemon_functions are any functions which cause some action
  * to take place in the daemon.
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 1f7decdd4..5afbd47e9 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -22,6 +22,34 @@ open Types

 (* Yara APIs. *)

+let non_daemon_functions = [
+  { defaults with
+name = "yara_scan"; added = (1, 37, 12);
+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 structure is returned.
+
+The C structure contains the following fields.
+
+=over 4
+
+=item C
+
+Path of the file matching a Yara rule.
+
+=item C
+
+Identifier of the Yara rule which matched against the given file.
+
+=back" };
+
+]
+
 let daemon_functions = [
   { defaults with
   name = "yara_load"; added = (1, 37, 12);
diff --git a/generator/actions_yara.mli b/generator/actions_yara.mli
index 23eefe068..06b8116c4 100644
--- a/generator/actions_yara.mli
+++ b/generator/actions_yara.mli
@@ -18,4 +18,5 @@

 (* Please read generator/README first. *)

+val non_daemon_functions : Types.action list
 val daemon_functions : Types.action list
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 063706f8f..fc55c2dcf 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -127,6 +127,7 @@ libguestfs_la_SOURCES = \
wait.c \
whole-file.c \
version.c \
+   yara.c \
libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/lib/yara.c b/lib/yara.c
new file mode 100644
index 0..7e4683101
--- /dev/null
+++ b/lib/yara.c
@@ -0,0 +1,132 @@
+/* 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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 r;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = guestfs_int_make_temp_path (g, "yara_scan");
+  if (tmpfile == NULL)
+return NULL;
+
+  r = guestfs_internal_yara_scan (g, path, tmpfile);
+  if (r == -1)
+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.
+ 

[Libguestfs] [PATCH v9 5/7] New API: internal_yara_scan

2017-04-25 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/actions_yara.ml|  8 +++
 generator/proc_nr.ml |  1 +
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 lib/MAX_PROC_NR  |  2 +-
 8 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 56eec74ad..0fd09815a 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -58,6 +58,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -125,6 +127,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int r;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd == -1) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  r = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (r == ERROR_SUCCESS)
+r = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -184,6 +218,58 @@ compile_error_callback (int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int r;
+  size_t len;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.yara_name = (char *) name;
+  detection.yara_rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  r = xdr_guestfs_int_yara_detection (, );
+  if (r == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 59c571b9e..1f7decdd4 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -53,4 +53,12 @@ Previously loaded rules will be destroyed." };
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };

+  { defaults with
+name = "internal_yara_scan"; added = (1, 37, 12);
+style = RErr, [Pathname "path"; FileOut "filename"], [];
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d471b1a83..c7619638a 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -481,6 +481,7 @@ let proc_nr = [
 471, "mksquashfs";
 472, "yara_load";
 473, "yara_destroy";
+474, "internal_yara_scan";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/generator/structs.ml b/generator/structs.ml
index c1c9b668e..834fa9c54 

[Libguestfs] [PATCH v9 4/7] New API: yara_destroy

2017-04-25 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c | 14 ++
 generator/actions_yara.ml |  8 
 generator/proc_nr.ml  |  1 +
 lib/MAX_PROC_NR   |  2 +-
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index a1e3aa878..56eec74ad 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -111,6 +111,20 @@ do_yara_load (void)
   return (r == ERROR_SUCCESS) ? 0 : -1;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index c38f68eb0..59c571b9e 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -45,4 +45,12 @@ it is recommended to compile them first.

 Previously loaded rules will be destroyed." };

+  { defaults with
+name = "yara_destroy"; added = (1, 37, 12);
+style = RErr, [], [];
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d50cc9efa..d471b1a83 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -480,6 +480,7 @@ let proc_nr = [
 470, "internal_find_inode";
 471, "mksquashfs";
 472, "yara_load";
+473, "yara_destroy";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index 68cfb10d1..8410b8b89 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-472
+473
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v9 7/7] yara_scan: added API tests

2017-04-25 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 +++
 tests/yara/test-yara-scan.sh | 61 
 3 files changed, 88 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index ee805abd8..a5c7e279f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,6 +296,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 0..e23d94e4c
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 0..501c459e4
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+$TEST_FUNCTIONS
+skip_if_skipped
+skip_unless_feature_available sleuthkit
+skip_unless_phony_guest blank-fs.img
+
+rm -f test-yara-rules.yar
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v9 0/7] Feature: Yara file scanning

2017-04-25 Thread Matteo Cafasso
v9:

- fixes according to comments

Matteo Cafasso (7):
  daemon: expose file upload logic
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/daemon.h  |   3 +
 daemon/upload.c  |  66 ---
 daemon/yara.c| 315 +++
 docs/guestfs-building.pod|   4 +
 generator/Makefile.am|   3 +
 generator/actions.ml |   6 +-
 generator/actions_yara.ml|  92 +
 generator/actions_yara.mli   |  22 +++
 generator/proc_nr.ml |   3 +
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   2 +
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 lib/MAX_PROC_NR  |   2 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 132 +
 m4/guestfs_daemon.m4 |  14 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  61 ++
 24 files changed, 750 insertions(+), 33 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli
 create mode 100644 lib/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v9 2/7] appliance: add yara dependency

2017-04-25 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in  |  4 
 daemon/Makefile.am|  3 ++-
 docs/guestfs-building.pod |  4 
 m4/guestfs_daemon.m4  | 14 ++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 5cf22768a..8846ce846 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -52,6 +52,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -86,6 +87,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-journal0
   libtirpc1
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -129,6 +131,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -159,6 +162,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index b46dd5fd3..ca01aeb4e 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -193,7 +193,8 @@ guestfsd_LDADD = \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
$(TSK_LIBS) \
-   $(RPC_LIBS)
+   $(RPC_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index bfb46a02f..6e89acfc8 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -427,6 +427,10 @@ Optional.  For tab-completion of commands in bash.

 Optional.  Library for filesystem forensics analysis.

+=item yara
+
+Optional.  Tool for categorizing files based on their content.
+
 =back

 =head1 BUILDING FROM GIT
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index eb5a6d5cf..522cd5f0e 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v8 6/8] New API: internal_yara_scan

2017-04-24 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/actions_yara.ml|  8 +++
 generator/proc_nr.ml |  1 +
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 lib/MAX_PROC_NR  |  2 +-
 8 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 78e367f23..cab008a03 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -58,6 +58,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -125,6 +127,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int r = 0;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  r = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (r == ERROR_SUCCESS)
+r = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -182,6 +216,58 @@ compile_error_callback (int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int r = 0;
+  size_t len = 0;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.yara_name = (char *) name;
+  detection.yara_rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  r = xdr_guestfs_int_yara_detection (, );
+  if (r == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 59c571b9e..1f7decdd4 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -53,4 +53,12 @@ Previously loaded rules will be destroyed." };
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };

+  { defaults with
+name = "internal_yara_scan"; added = (1, 37, 12);
+style = RErr, [Pathname "path"; FileOut "filename"], [];
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d471b1a83..c7619638a 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -481,6 +481,7 @@ let proc_nr = [
 471, "mksquashfs";
 472, "yara_load";
 473, "yara_destroy";
+474, "internal_yara_scan";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/generator/structs.ml b/generator/structs.ml
index c1c9b6

[Libguestfs] [PATCH v8 4/8] New API: yara_load

2017-04-24 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am |   1 +
 daemon/cleanups.c  |   9 ++
 daemon/cleanups.h  |   2 +
 daemon/yara.c  | 213 +
 generator/Makefile.am  |   3 +
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  48 ++
 generator/actions_yara.mli |  21 +
 generator/proc_nr.ml   |   1 +
 lib/MAX_PROC_NR|   2 +-
 10 files changed, 301 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ca01aeb4e..68f863bcd 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -170,6 +170,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493d7..3102cf94b 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e2744..a791244cb 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0..3c80b1123
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,213 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#ifdef HAVE_ATTRIBUTE_CLEANUP
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+#else
+#define CLEANUP_DESTROY_YARA_COMPILER
+#endif
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (void)
+{
+  int r = 0;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  r = upload_to_fd (fd, tmpfile);
+  if (r == -1) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+r = yr_initialize ();
+if (r != ERROR_SUCCESS) {
+  rep

[Libguestfs] [PATCH v8 3/8] appliance: add yara dependency

2017-04-24 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in  |  4 
 daemon/Makefile.am|  3 ++-
 docs/guestfs-building.pod |  4 
 m4/guestfs_daemon.m4  | 14 ++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 5cf22768a..8846ce846 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -52,6 +52,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -86,6 +87,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-journal0
   libtirpc1
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -129,6 +131,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -159,6 +162,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index b46dd5fd3..ca01aeb4e 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -193,7 +193,8 @@ guestfsd_LDADD = \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
$(TSK_LIBS) \
-   $(RPC_LIBS)
+   $(RPC_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index bfb46a02f..6e89acfc8 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -427,6 +427,10 @@ Optional.  For tab-completion of commands in bash.

 Optional.  Library for filesystem forensics analysis.

+=item yara
+
+Optional.  Tool for categorizing files based on their content.
+
 =back

 =head1 BUILDING FROM GIT
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index eb5a6d5cf..522cd5f0e 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v8 7/8] New API: yara_scan

2017-04-24 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  28 ++
 generator/actions_yara.mli |   1 +
 lib/Makefile.am|   1 +
 lib/yara.c | 132 +
 5 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 lib/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 6e11d99c3..2722f3dcd 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -38,7 +38,8 @@ let non_daemon_functions =
   Actions_inspection_deprecated.non_daemon_functions @
   Actions_properties.non_daemon_functions @
   Actions_properties_deprecated.non_daemon_functions @
-  Actions_tsk.non_daemon_functions
+  Actions_tsk.non_daemon_functions @
+  Actions_yara.non_daemon_functions

 (* daemon_functions are any functions which cause some action
  * to take place in the daemon.
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 1f7decdd4..5afbd47e9 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -22,6 +22,34 @@ open Types

 (* Yara APIs. *)

+let non_daemon_functions = [
+  { defaults with
+name = "yara_scan"; added = (1, 37, 12);
+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 structure is returned.
+
+The C structure contains the following fields.
+
+=over 4
+
+=item C
+
+Path of the file matching a Yara rule.
+
+=item C
+
+Identifier of the Yara rule which matched against the given file.
+
+=back" };
+
+]
+
 let daemon_functions = [
   { defaults with
   name = "yara_load"; added = (1, 37, 12);
diff --git a/generator/actions_yara.mli b/generator/actions_yara.mli
index 23eefe068..06b8116c4 100644
--- a/generator/actions_yara.mli
+++ b/generator/actions_yara.mli
@@ -18,4 +18,5 @@

 (* Please read generator/README first. *)

+val non_daemon_functions : Types.action list
 val daemon_functions : Types.action list
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 063706f8f..fc55c2dcf 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -127,6 +127,7 @@ libguestfs_la_SOURCES = \
wait.c \
whole-file.c \
version.c \
+   yara.c \
libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/lib/yara.c b/lib/yara.c
new file mode 100644
index 0..f4a6f5833
--- /dev/null
+++ b/lib/yara.c
@@ -0,0 +1,132 @@
+/* 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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 r = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = guestfs_int_make_temp_path (g, "yara_scan");
+  if (tmpfile == NULL)
+return NULL;
+
+  r = guestfs_internal_yara_scan (g, path, tmpfile);
+  if (r == -1)
+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 succes

[Libguestfs] [PATCH v8 1/8] daemon: ignore unused return value in upload function

2017-04-24 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/upload.c | 8 +---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/daemon/upload.c b/daemon/upload.c
index 655baf29d..dc467d62b 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -27,6 +27,8 @@
 #include 
 #include 

+#include "ignore-value.h"
+
 #include "guestfs_protocol.h"
 #include "daemon.h"
 #include "actions.h"
@@ -68,7 +70,7 @@ upload (const char *filename, int flags, int64_t offset)
   if (!is_dev) CHROOT_OUT;
   if (data.fd == -1) {
 err = errno;
-r = cancel_receive ();
+ignore_value (cancel_receive ());
 errno = err;
 reply_with_perror ("%s", filename);
 return -1;
@@ -77,7 +79,7 @@ upload (const char *filename, int flags, int64_t offset)
   if (offset) {
 if (lseek (data.fd, offset, SEEK_SET) == -1) {
   err = errno;
-  r = cancel_receive ();
+  ignore_value (cancel_receive ());
   errno = err;
   reply_with_perror ("lseek: %s", filename);
   return -1;
@@ -87,7 +89,7 @@ upload (const char *filename, int flags, int64_t offset)
   r = receive_file (write_cb, );
   if (r == -1) {   /* write error */
 err = errno;
-r = cancel_receive ();
+ignore_value (cancel_receive ());
 errno = err;
 reply_with_error ("write error: %s", filename);
 close (data.fd);
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v8 2/8] daemon: expose file upload logic

2017-04-24 Thread Matteo Cafasso
Allows other modules to use the same logic for uploading files.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/daemon.h |  3 +++
 daemon/upload.c | 66 -
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index 5137e2c2a..75af5246e 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -261,6 +261,9 @@ extern int64_t ntfs_minimum_size (const char *device);
 extern int swap_set_uuid (const char *device, const char *uuid);
 extern int swap_set_label (const char *device, const char *label);

+/*-- in upload.c --*/
+extern int upload_to_fd (int fd, const char *filename);
+
 /* ordinary daemon functions use these to indicate errors
  * NB: you don't need to prefix the string with the current command,
  * it is added automatically by the client-side RPC stubs.
diff --git a/daemon/upload.c b/daemon/upload.c
index dc467d62b..c59fde295 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -56,19 +56,50 @@ write_cb (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+int
+upload_to_fd (int fd, const char *filename)
+{
+  int r = 0, err = 0;
+  struct write_cb_data data = { .fd = fd, .written = 0 };
+
+  r = receive_file (write_cb, );
+  if (r == -1) {   /* write error */
+err = errno;
+ignore_value (cancel_receive ());
+errno = err;
+reply_with_error ("write error: %s", filename);
+close (fd);
+return -1;
+  }
+  if (r == -2) {   /* cancellation from library */
+/* This error is ignored by the library since it initiated the
+ * cancel.  Nevertheless we must send an error reply here.
+ */
+reply_with_error ("file upload cancelled");
+close (fd);
+return -1;
+  }
+
+  if (close (fd) == -1) {
+reply_with_perror ("close");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Has one FileIn parameter. */
 static int
 upload (const char *filename, int flags, int64_t offset)
 {
-  struct write_cb_data data = { .written = 0 };
-  int err, r, is_dev;
+  int err, is_dev, fd;

   is_dev = STRPREFIX (filename, "/dev/");

   if (!is_dev) CHROOT_IN;
-  data.fd = open (filename, flags, 0666);
+  fd = open (filename, flags, 0666);
   if (!is_dev) CHROOT_OUT;
-  if (data.fd == -1) {
+  if (fd == -1) {
 err = errno;
 ignore_value (cancel_receive ());
 errno = err;
@@ -77,7 +108,7 @@ upload (const char *filename, int flags, int64_t offset)
   }

   if (offset) {
-if (lseek (data.fd, offset, SEEK_SET) == -1) {
+if (lseek (fd, offset, SEEK_SET) == -1) {
   err = errno;
   ignore_value (cancel_receive ());
   errno = err;
@@ -86,30 +117,7 @@ upload (const char *filename, int flags, int64_t offset)
 }
   }

-  r = receive_file (write_cb, );
-  if (r == -1) {   /* write error */
-err = errno;
-ignore_value (cancel_receive ());
-errno = err;
-reply_with_error ("write error: %s", filename);
-close (data.fd);
-return -1;
-  }
-  if (r == -2) {   /* cancellation from library */
-/* This error is ignored by the library since it initiated the
- * cancel.  Nevertheless we must send an error reply here.
- */
-reply_with_error ("file upload cancelled");
-close (data.fd);
-return -1;
-  }
-
-  if (close (data.fd) == -1) {
-reply_with_perror ("close: %s", filename);
-return -1;
-  }
-
-  return 0;
+  return upload_to_fd (fd, filename);
 }

 /* Has one FileIn parameter. */
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v8 8/8] yara_scan: added API tests

2017-04-24 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 +++
 tests/yara/test-yara-scan.sh | 61 
 3 files changed, 88 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index ee805abd8..a5c7e279f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,6 +296,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 0..e23d94e4c
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 0..501c459e4
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+$TEST_FUNCTIONS
+skip_if_skipped
+skip_unless_feature_available sleuthkit
+skip_unless_phony_guest blank-fs.img
+
+rm -f test-yara-rules.yar
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v8 5/8] New API: yara_destroy

2017-04-24 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c | 14 ++
 generator/actions_yara.ml |  8 
 generator/proc_nr.ml  |  1 +
 lib/MAX_PROC_NR   |  2 +-
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 3c80b1123..78e367f23 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -111,6 +111,20 @@ do_yara_load (void)
   return (r == ERROR_SUCCESS) ? 0 : -1;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index c38f68eb0..59c571b9e 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -45,4 +45,12 @@ it is recommended to compile them first.

 Previously loaded rules will be destroyed." };

+  { defaults with
+name = "yara_destroy"; added = (1, 37, 12);
+style = RErr, [], [];
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d50cc9efa..d471b1a83 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -480,6 +480,7 @@ let proc_nr = [
 470, "internal_find_inode";
 471, "mksquashfs";
 472, "yara_load";
+473, "yara_destroy";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index 68cfb10d1..8410b8b89 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-472
+473
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v8 0/8] Feature: Yara file scanning

2017-04-24 Thread Matteo Cafasso
v8:

- Ignore returned value in daemon/upload.c
- Report serialization errors in lib/yara.c

Matteo Cafasso (8):
  daemon: ignore unused return value in upload function
  daemon: expose file upload logic
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/daemon.h  |   3 +
 daemon/upload.c  |  72 ---
 daemon/yara.c| 313 +++
 docs/guestfs-building.pod|   4 +
 generator/Makefile.am|   3 +
 generator/actions.ml |   6 +-
 generator/actions_yara.ml|  92 +
 generator/actions_yara.mli   |  22 +++
 generator/proc_nr.ml |   3 +
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   2 +
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 lib/MAX_PROC_NR  |   2 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 132 +
 m4/guestfs_daemon.m4 |  14 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  61 ++
 24 files changed, 752 insertions(+), 35 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli
 create mode 100644 lib/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 7/7] yara_scan: added API tests

2017-04-23 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 +++
 tests/yara/test-yara-scan.sh | 61 
 3 files changed, 88 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index ee805abd8..a5c7e279f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,6 +296,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 0..e23d94e4c
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 0..501c459e4
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+$TEST_FUNCTIONS
+skip_if_skipped
+skip_unless_feature_available sleuthkit
+skip_unless_phony_guest blank-fs.img
+
+rm -f test-yara-rules.yar
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 3/7] New API: yara_load

2017-04-23 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am |   1 +
 daemon/cleanups.c  |   9 ++
 daemon/cleanups.h  |   2 +
 daemon/yara.c  | 213 +
 generator/Makefile.am  |   3 +
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  48 ++
 generator/actions_yara.mli |  21 +
 generator/proc_nr.ml   |   1 +
 lib/MAX_PROC_NR|   2 +-
 10 files changed, 301 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ca01aeb4e..68f863bcd 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -170,6 +170,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493d7..3102cf94b 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e2744..a791244cb 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0..3c80b1123
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,213 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#ifdef HAVE_ATTRIBUTE_CLEANUP
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+#else
+#define CLEANUP_DESTROY_YARA_COMPILER
+#endif
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (void)
+{
+  int r = 0;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  r = upload_to_fd (fd, tmpfile);
+  if (r == -1) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+r = yr_initialize ();
+if (r != ERROR_SUCCESS) {
+  rep

[Libguestfs] [PATCH v7 1/7] daemon: expose file upload logic

2017-04-23 Thread Matteo Cafasso
Allows other modules to use the same logic for uploading files.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/daemon.h |  3 +++
 daemon/upload.c | 66 -
 2 files changed, 40 insertions(+), 29 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index 5137e2c2a..75af5246e 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -261,6 +261,9 @@ extern int64_t ntfs_minimum_size (const char *device);
 extern int swap_set_uuid (const char *device, const char *uuid);
 extern int swap_set_label (const char *device, const char *label);

+/*-- in upload.c --*/
+extern int upload_to_fd (int fd, const char *filename);
+
 /* ordinary daemon functions use these to indicate errors
  * NB: you don't need to prefix the string with the current command,
  * it is added automatically by the client-side RPC stubs.
diff --git a/daemon/upload.c b/daemon/upload.c
index 655baf29d..1b109e634 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -54,19 +54,50 @@ write_cb (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+int
+upload_to_fd (int fd, const char *filename)
+{
+  int r = 0, err = 0;
+  struct write_cb_data data = { .fd = fd, .written = 0 };
+
+  r = receive_file (write_cb, );
+  if (r == -1) {   /* write error */
+err = errno;
+r = cancel_receive ();
+errno = err;
+reply_with_error ("write error: %s", filename);
+close (fd);
+return -1;
+  }
+  if (r == -2) {   /* cancellation from library */
+/* This error is ignored by the library since it initiated the
+ * cancel.  Nevertheless we must send an error reply here.
+ */
+reply_with_error ("file upload cancelled");
+close (fd);
+return -1;
+  }
+
+  if (close (fd) == -1) {
+reply_with_perror ("close");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Has one FileIn parameter. */
 static int
 upload (const char *filename, int flags, int64_t offset)
 {
-  struct write_cb_data data = { .written = 0 };
-  int err, r, is_dev;
+  int r, err, is_dev, fd;

   is_dev = STRPREFIX (filename, "/dev/");

   if (!is_dev) CHROOT_IN;
-  data.fd = open (filename, flags, 0666);
+  fd = open (filename, flags, 0666);
   if (!is_dev) CHROOT_OUT;
-  if (data.fd == -1) {
+  if (fd == -1) {
 err = errno;
 r = cancel_receive ();
 errno = err;
@@ -75,7 +106,7 @@ upload (const char *filename, int flags, int64_t offset)
   }

   if (offset) {
-if (lseek (data.fd, offset, SEEK_SET) == -1) {
+if (lseek (fd, offset, SEEK_SET) == -1) {
   err = errno;
   r = cancel_receive ();
   errno = err;
@@ -84,30 +115,7 @@ upload (const char *filename, int flags, int64_t offset)
 }
   }

-  r = receive_file (write_cb, );
-  if (r == -1) {   /* write error */
-err = errno;
-r = cancel_receive ();
-errno = err;
-reply_with_error ("write error: %s", filename);
-close (data.fd);
-return -1;
-  }
-  if (r == -2) {   /* cancellation from library */
-/* This error is ignored by the library since it initiated the
- * cancel.  Nevertheless we must send an error reply here.
- */
-reply_with_error ("file upload cancelled");
-close (data.fd);
-return -1;
-  }
-
-  if (close (data.fd) == -1) {
-reply_with_perror ("close: %s", filename);
-return -1;
-  }
-
-  return 0;
+  return upload_to_fd (fd, filename);
 }

 /* Has one FileIn parameter. */
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 5/7] New API: internal_yara_scan

2017-04-23 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/actions_yara.ml|  8 +++
 generator/proc_nr.ml |  1 +
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 lib/MAX_PROC_NR  |  2 +-
 8 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 78e367f23..cab008a03 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -58,6 +58,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -125,6 +127,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int r = 0;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  r = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (r == ERROR_SUCCESS)
+r = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -182,6 +216,58 @@ compile_error_callback (int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int r = 0;
+  size_t len = 0;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.yara_name = (char *) name;
+  detection.yara_rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  r = xdr_guestfs_int_yara_detection (, );
+  if (r == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 59c571b9e..1f7decdd4 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -53,4 +53,12 @@ Previously loaded rules will be destroyed." };
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };

+  { defaults with
+name = "internal_yara_scan"; added = (1, 37, 12);
+style = RErr, [Pathname "path"; FileOut "filename"], [];
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d471b1a83..c7619638a 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -481,6 +481,7 @@ let proc_nr = [
 471, "mksquashfs";
 472, "yara_load";
 473, "yara_destroy";
+474, "internal_yara_scan";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/generator/structs.ml b/generator/structs.ml
index c1c9b6

[Libguestfs] [PATCH v7 4/7] New API: yara_destroy

2017-04-23 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c | 14 ++
 generator/actions_yara.ml |  8 
 generator/proc_nr.ml  |  1 +
 lib/MAX_PROC_NR   |  2 +-
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 3c80b1123..78e367f23 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -111,6 +111,20 @@ do_yara_load (void)
   return (r == ERROR_SUCCESS) ? 0 : -1;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index c38f68eb0..59c571b9e 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -45,4 +45,12 @@ it is recommended to compile them first.

 Previously loaded rules will be destroyed." };

+  { defaults with
+name = "yara_destroy"; added = (1, 37, 12);
+style = RErr, [], [];
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d50cc9efa..d471b1a83 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -480,6 +480,7 @@ let proc_nr = [
 470, "internal_find_inode";
 471, "mksquashfs";
 472, "yara_load";
+473, "yara_destroy";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index 68cfb10d1..8410b8b89 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-472
+473
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 6/7] New API: yara_scan

2017-04-23 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  28 ++
 generator/actions_yara.mli |   1 +
 lib/Makefile.am|   1 +
 lib/yara.c | 130 +
 5 files changed, 162 insertions(+), 1 deletion(-)
 create mode 100644 lib/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 6e11d99c3..2722f3dcd 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -38,7 +38,8 @@ let non_daemon_functions =
   Actions_inspection_deprecated.non_daemon_functions @
   Actions_properties.non_daemon_functions @
   Actions_properties_deprecated.non_daemon_functions @
-  Actions_tsk.non_daemon_functions
+  Actions_tsk.non_daemon_functions @
+  Actions_yara.non_daemon_functions

 (* daemon_functions are any functions which cause some action
  * to take place in the daemon.
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 1f7decdd4..5afbd47e9 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -22,6 +22,34 @@ open Types

 (* Yara APIs. *)

+let non_daemon_functions = [
+  { defaults with
+name = "yara_scan"; added = (1, 37, 12);
+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 structure is returned.
+
+The C structure contains the following fields.
+
+=over 4
+
+=item C
+
+Path of the file matching a Yara rule.
+
+=item C
+
+Identifier of the Yara rule which matched against the given file.
+
+=back" };
+
+]
+
 let daemon_functions = [
   { defaults with
   name = "yara_load"; added = (1, 37, 12);
diff --git a/generator/actions_yara.mli b/generator/actions_yara.mli
index 23eefe068..06b8116c4 100644
--- a/generator/actions_yara.mli
+++ b/generator/actions_yara.mli
@@ -18,4 +18,5 @@

 (* Please read generator/README first. *)

+val non_daemon_functions : Types.action list
 val daemon_functions : Types.action list
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 063706f8f..fc55c2dcf 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -127,6 +127,7 @@ libguestfs_la_SOURCES = \
wait.c \
whole-file.c \
version.c \
+   yara.c \
libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/lib/yara.c b/lib/yara.c
new file mode 100644
index 0..4e0dc3fe0
--- /dev/null
+++ b/lib/yara.c
@@ -0,0 +1,130 @@
+/* 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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 r = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = guestfs_int_make_temp_path (g, "yara_scan");
+  if (tmpfile == NULL)
+return NULL;
+
+  r = guestfs_internal_yara_scan (g, path, tmpfile);
+  if (r == -1)
+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 succes

[Libguestfs] [PATCH v7 2/7] appliance: add yara dependency

2017-04-23 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in  |  4 
 daemon/Makefile.am|  3 ++-
 docs/guestfs-building.pod |  4 
 m4/guestfs_daemon.m4  | 14 ++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 5cf22768a..8846ce846 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -52,6 +52,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -86,6 +87,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-journal0
   libtirpc1
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -129,6 +131,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -159,6 +162,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index b46dd5fd3..ca01aeb4e 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -193,7 +193,8 @@ guestfsd_LDADD = \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
$(TSK_LIBS) \
-   $(RPC_LIBS)
+   $(RPC_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/docs/guestfs-building.pod b/docs/guestfs-building.pod
index bfb46a02f..6e89acfc8 100644
--- a/docs/guestfs-building.pod
+++ b/docs/guestfs-building.pod
@@ -427,6 +427,10 @@ Optional.  For tab-completion of commands in bash.

 Optional.  Library for filesystem forensics analysis.

+=item yara
+
+Optional.  Tool for categorizing files based on their content.
+
 =back

 =head1 BUILDING FROM GIT
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index eb5a6d5cf..522cd5f0e 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 0/7] Feature: Yara file scanning

2017-04-23 Thread Matteo Cafasso
v7:

- Fixes according to comments
- Rebase on top of 1.37.12

Matteo Cafasso (7):
  daemon: expose file upload logic
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/daemon.h  |   3 +
 daemon/upload.c  |  66 ---
 daemon/yara.c| 313 +++
 docs/guestfs-building.pod|   4 +
 generator/Makefile.am|   3 +
 generator/actions.ml |   6 +-
 generator/actions_yara.ml|  92 +
 generator/actions_yara.mli   |  22 +++
 generator/proc_nr.ml |   3 +
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   2 +
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 lib/MAX_PROC_NR  |   2 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 130 +
 m4/guestfs_daemon.m4 |  14 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  61 ++
 24 files changed, 746 insertions(+), 33 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli
 create mode 100644 lib/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v6 4/7] New API: yara_destroy

2017-04-06 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c | 14 ++
 generator/actions_yara.ml |  8 
 generator/proc_nr.ml  |  1 +
 lib/MAX_PROC_NR   |  2 +-
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 0d33d83cd..186a330c1 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -107,6 +107,20 @@ do_yara_load (void)
   return (ret == ERROR_SUCCESS) ? 0 : -1;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 3e55206ec..9d93d9f11 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -45,4 +45,12 @@ it is recommended to compile them first.

 Previously loaded rules will be destroyed." };

+  { defaults with
+name = "yara_destroy"; added = (1, 37, 9);
+style = RErr, [], [];
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d50cc9efa..d471b1a83 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -480,6 +480,7 @@ let proc_nr = [
 470, "internal_find_inode";
 471, "mksquashfs";
 472, "yara_load";
+473, "yara_destroy";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index 68cfb10d1..8410b8b89 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-472
+473
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v6 6/7] New API: yara_scan

2017-04-06 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  28 ++
 generator/actions_yara.mli |   1 +
 lib/Makefile.am|   1 +
 lib/yara.c | 127 +
 5 files changed, 159 insertions(+), 1 deletion(-)
 create mode 100644 lib/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 4df3b2a32..d36a4f8a9 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -38,7 +38,8 @@ let non_daemon_functions =
   Actions_inspection_deprecated.non_daemon_functions @
   Actions_properties.non_daemon_functions @
   Actions_properties_deprecated.non_daemon_functions @
-  Actions_tsk.non_daemon_functions
+  Actions_tsk.non_daemon_functions @
+  Actions_yara.non_daemon_functions

 (* daemon_functions are any functions which cause some action
  * to take place in the daemon.
diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 2166d6f0a..deb4190a9 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -22,6 +22,34 @@ open Types

 (* Yara APIs. *)

+let non_daemon_functions = [
+  { defaults with
+name = "yara_scan"; added = (1, 37, 9);
+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 structure is returned.
+
+The C structure contains the following fields.
+
+=over 4
+
+=item 'yara_name'
+
+Path of the file matching a Yara rule.
+
+=item 'yara_rule'
+
+Identifier of the Yara rule which matched against the given file.
+
+=back" };
+
+]
+
 let daemon_functions = [
   { defaults with
   name = "yara_load"; added = (1, 37, 9);
diff --git a/generator/actions_yara.mli b/generator/actions_yara.mli
index 23eefe068..06b8116c4 100644
--- a/generator/actions_yara.mli
+++ b/generator/actions_yara.mli
@@ -18,4 +18,5 @@

 (* Please read generator/README first. *)

+val non_daemon_functions : Types.action list
 val daemon_functions : Types.action list
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 063706f8f..fc55c2dcf 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -127,6 +127,7 @@ libguestfs_la_SOURCES = \
wait.c \
whole-file.c \
version.c \
+   yara.c \
libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/lib/yara.c b/lib/yara.c
new file mode 100644
index 0..864766e7a
--- /dev/null
+++ b/lib/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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 

[Libguestfs] [PATCH v6 2/7] appliance: add yara dependency

2017-04-06 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in |  4 
 daemon/Makefile.am   |  3 ++-
 m4/guestfs_daemon.m4 | 14 ++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 5cf22768a..8846ce846 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -52,6 +52,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -86,6 +87,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-journal0
   libtirpc1
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -129,6 +131,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -159,6 +162,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 8632c3768..af4430f20 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -191,7 +191,8 @@ guestfsd_LDADD = \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
$(TSK_LIBS) \
-   $(RPC_LIBS)
+   $(RPC_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index eb5a6d5cf..522cd5f0e 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v6 PATCH 7/7] yara_scan: added API tests

2017-04-06 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 +++
 tests/yara/test-yara-scan.sh | 61 
 3 files changed, 88 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index a23416bc0..b2bdada00 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,6 +296,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 0..e23d94e4c
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 0..501c459e4
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+$TEST_FUNCTIONS
+skip_if_skipped
+skip_unless_feature_available sleuthkit
+skip_unless_phony_guest blank-fs.img
+
+rm -f test-yara-rules.yar
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v6 3/7] New API: yara_load

2017-04-06 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am |   1 +
 daemon/cleanups.c  |   9 ++
 daemon/cleanups.h  |   2 +
 daemon/yara.c  | 203 +
 generator/Makefile.am  |   3 +
 generator/actions.ml   |   3 +-
 generator/actions_yara.ml  |  48 +++
 generator/actions_yara.mli |  21 +
 generator/proc_nr.ml   |   1 +
 lib/MAX_PROC_NR|   2 +-
 10 files changed, 291 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index af4430f20..e4679a8c5 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -168,6 +168,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493d7..3102cf94b 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e2744..a791244cb 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0..0d33d83cd
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,203 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (void)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  ret = upload_to_fd (fd);
+  if (ret < 0) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+ret = yr_initialize ();
+if (ret != ERROR_SUCCESS) {
+  reply_with_error ("failed initializing yara");
+  unlink (tmpfile);
+   

[Libguestfs] [PATCH v6 5/7] New API: internal_yara_scan

2017-04-06 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/actions_yara.ml|  8 +++
 generator/proc_nr.ml |  1 +
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 lib/MAX_PROC_NR  |  2 +-
 8 files changed, 109 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 186a330c1..80e3f692b 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -54,6 +54,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -121,6 +123,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (ret == ERROR_SUCCESS)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -172,6 +206,58 @@ compile_error_callback(int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int ret = 0;
+  size_t len = 0;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.yara_name = (char *) name;
+  detection.yara_rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  ret = xdr_guestfs_int_yara_detection (, );
+  if (ret == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/actions_yara.ml b/generator/actions_yara.ml
index 9d93d9f11..2166d6f0a 100644
--- a/generator/actions_yara.ml
+++ b/generator/actions_yara.ml
@@ -53,4 +53,12 @@ Previously loaded rules will be destroyed." };
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };

+  { defaults with
+name = "internal_yara_scan"; added = (1, 37, 9);
+style = RErr, [Pathname "path"; FileOut "filename"], [];
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d471b1a83..c7619638a 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -481,6 +481,7 @@ let proc_nr = [
 471, "mksquashfs";
 472, "yara_load";
 473, "yara_destroy";
+474, "internal_yara_scan";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/generator/structs.ml b/generator/structs.ml
in

[Libguestfs] [PATCH v6 0/7] Feature: Yara file scanning

2017-04-06 Thread Matteo Cafasso
v6:

- use new test functions
- fix yara_detection struct field names
- revert yara_load function to initial version

With Pino we were exploring the idea of allowing Users to load multiple
rule files with subsequent calls to yara_load API.
https://www.redhat.com/archives/libguestfs/2016-November/msg00119.html
It turns out impractical due to YARA API limitations. It is possible
to load multiple rule source files into the compiler. Yet once compiled
no further rule file can be added.

This would make the yara_load API difficult to understand for the end User.
The yara tool iself cannot scan files with more than a rule file.
To combine multiple rule files the User is recommended to use the yarac tool.

This makes the yara_load API more similar to the yara workflow.

- further small fixes according to the v5 comments

After further

Matteo Cafasso (7):
  daemon: expose file upload logic
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/daemon.h  |   3 +
 daemon/upload.c  |  70 +++
 daemon/yara.c| 303 +++
 generator/Makefile.am|   3 +
 generator/actions.ml |   6 +-
 generator/actions_yara.ml|  92 ++
 generator/actions_yara.mli   |  22 +++
 generator/proc_nr.ml |   3 +
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   2 +
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 lib/MAX_PROC_NR  |   2 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 127 +
 m4/guestfs_daemon.m4 |  14 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  61 +++
 23 files changed, 731 insertions(+), 35 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 generator/actions_yara.ml
 create mode 100644 generator/actions_yara.mli
 create mode 100644 lib/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH] python: check return value of Python APIs

2017-03-18 Thread Matteo Cafasso
Addressing issue #1406906.

When constructing the returned objects, check the return value of
Python APIs.

This is especially relevant when dealing with non UTF-8 strings.

A RuntimeError will be raised on failure pointing to the problematic
entry and the field name.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/python.ml | 143 +++-
 1 file changed, 97 insertions(+), 46 deletions(-)

diff --git a/generator/python.ml b/generator/python.ml
index 11dc48102..d03275276 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -152,12 +152,20 @@ and generate_python_structs () =
 pr "PyObject *\n";
 pr "guestfs_int_py_put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ 
typ;
 pr "{\n";
-pr "  PyObject *list;\n";
+pr "  PyObject *list, *element;\n";
 pr "  size_t i;\n";
 pr "\n";
 pr "  list = PyList_New (%ss->len);\n" typ;
-pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
-pr "PyList_SetItem (list, i, guestfs_int_py_put_%s (&%ss->val[i]));\n" 
typ typ;
+pr "  if (list == NULL)\n";
+pr "PyErr_SetString (PyExc_RuntimeError, \"PyList_New\");\n";
+pr "return NULL;\n";
+pr "  }\n";
+pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
+pr "element = guestfs_int_py_put_%s (&%ss->val[i]);\n" typ typ;
+pr "if (element == NULL)\n";
+pr "  return NULL;\n";
+pr "PyList_SetItem (list, i, element);\n";
+pr "  }\n";
 pr "  return list;\n";
 pr "};\n";
 pr "#endif\n";
@@ -171,73 +179,112 @@ and generate_python_structs () =
   pr "PyObject *\n";
   pr "guestfs_int_py_put_%s (struct guestfs_%s *%s)\n" typ typ typ;
   pr "{\n";
-  pr "  PyObject *dict;\n";
+  pr "  PyObject *dict, *value;\n";
   pr "\n";
   pr "  dict = PyDict_New ();\n";
+  pr "  if (dict == NULL) {\n";
+  pr "PyErr_SetString (PyExc_RuntimeError, \"PyDict_New\");\n";
+  pr "return NULL;\n";
+  pr "  }\n";
   List.iter (
 function
 | name, FString ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromString (%s->%s));\n"
-  typ name;
+pr "  value = PyString_FromString (%s->%s);\n" typ name;
 pr "#else\n";
-pr "PyUnicode_FromString (%s->%s));\n"
-  typ name;
-pr "#endif\n"
+pr "  value = PyUnicode_FromString (%s->%s);\n" typ name;
+pr "#endif\n";
+pr "  if (value == NULL) {\n";
+pr "PyErr_SetString (PyExc_RuntimeError,\n";
+pr " \"Error setting %s.%s\");\n" typ name;
+pr "return NULL;\n";
+pr "  }\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FBuffer ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromStringAndSize (%s->%s, 
%s->%s_len));\n"
+pr "  value = PyString_FromStringAndSize (%s->%s, %s->%s_len);\n"
   typ name typ name;
 pr "#else\n";
-pr "PyBytes_FromStringAndSize (%s->%s, 
%s->%s_len));\n"
+pr "  value = PyBytes_FromStringAndSize (%s->%s, %s->%s_len);\n"
   typ name typ name;
-pr "#endif\n"
+pr "#endif\n";
+pr "  if (value == NULL) {\n";
+pr "PyErr_SetString (PyExc_RuntimeError,\n";
+pr " \"Error setting %s.%s\");\n" typ name;
+pr "return NULL;\n";
+pr "  }\n";
+pr "  PyDict_SetItemString (dict, \"%s\", value);\n" name;
 | name, FUUID ->
-pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
 pr "#ifdef HAVE_PYSTRING_ASSTRING\n";
-pr "PyString_FromStringAndSize (%s->%s, 
32));\n"
-  typ name;
+  

[Libguestfs] [PATCH v4 0/7] Feature: Yara file scanning

2017-03-12 Thread Matteo Cafasso
Rebase patches on top of 1.37.1.

No changes since last series.

Matteo Cafasso (7):
  daemon: expose file upload logic
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/daemon.h  |   3 +
 daemon/upload.c  |  70 +++
 daemon/yara.c| 301 +++
 generator/Makefile.am|   3 +
 generator/actions.ml |   6 +-
 generator/proc_nr.ml |   3 +
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   8 +-
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 lib/MAX_PROC_NR  |   2 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 127 +
 m4/guestfs_daemon.m4 |  14 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  72 
 21 files changed, 630 insertions(+), 37 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 lib/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 6/7] New API: yara_scan

2017-03-12 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml |   3 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 127 +++
 3 files changed, 130 insertions(+), 1 deletion(-)
 create mode 100644 lib/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 4df3b2a32..d36a4f8a9 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -38,7 +38,8 @@ let non_daemon_functions =
   Actions_inspection_deprecated.non_daemon_functions @
   Actions_properties.non_daemon_functions @
   Actions_properties_deprecated.non_daemon_functions @
-  Actions_tsk.non_daemon_functions
+  Actions_tsk.non_daemon_functions @
+  Actions_yara.non_daemon_functions

 (* daemon_functions are any functions which cause some action
  * to take place in the daemon.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 063706f8f..fc55c2dcf 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -127,6 +127,7 @@ libguestfs_la_SOURCES = \
wait.c \
whole-file.c \
version.c \
+   yara.c \
libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/lib/yara.c b/lib/yara.c
new file mode 100644
index 0..864766e7a
--- /dev/null
+++ b/lib/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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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), );
+  if (ret == -1)
+return -1;
+
+  xdrstdio_create (, fp, XDR_DECODE);
+
+  for (index = 0; xdr_getpos () < statbuf.st_size; index++) {
+if (index == detections->

[Libguestfs] [PATCH v4 5/7] New API: internal_yara_scan

2017-03-12 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/proc_nr.ml |  1 +
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 lib/MAX_PROC_NR  |  2 +-
 7 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index cb49593c7..471547341 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -54,6 +54,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *, const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -119,6 +121,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (ret == ERROR_SUCCESS)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -170,6 +204,58 @@ compile_error_callback(int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int ret = 0;
+  size_t len = 0;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.name = (char *) name;
+  detection.rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  ret = xdr_guestfs_int_yara_detection (, );
+  if (ret == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d471b1a83..c7619638a 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -481,6 +481,7 @@ let proc_nr = [
 471, "mksquashfs";
 472, "yara_load";
 473, "yara_destroy";
+474, "internal_yara_scan";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/generator/structs.ml b/generator/structs.ml
index c1c9b668e..01aa3d371 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -469,6 +469,15 @@ let structs = [
 ];
 s_camel_name = "TSKDirent" };

+  (* Yara detection information. *)
+  { defaults with
+s_name = "yara_detection";
+s_cols = [
+"name", FString;
+"rule", FString;
+];
+s_camel_name = "YaraDetection" };
+
 ] (* end of structs *)

 let lookup_struct name =
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index b0ebf15d9..4b067d9e0 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -49,6 +49,7 @@ guestfs_gobject_headers= \
   include/guestfs-gobject/struct-version.h \
   include/guestfs-gobject/struct-xattr.h \
   include/guestfs-gobj

[Libguestfs] [PATCH v4 4/7] New API: yara_destroy

2017-03-12 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 14 ++
 generator/proc_nr.ml |  1 +
 lib/MAX_PROC_NR  |  2 +-
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 0e4128aed..cb49593c7 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -105,6 +105,20 @@ do_yara_load (const char *namespace)
   return (ret == ERROR_SUCCESS) ? 0 : -1;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index d50cc9efa..d471b1a83 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -480,6 +480,7 @@ let proc_nr = [
 470, "internal_find_inode";
 471, "mksquashfs";
 472, "yara_load";
+473, "yara_destroy";
 ]

 (* End of list.  If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index 68cfb10d1..8410b8b89 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-472
+473
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 3/7] New API: yara_load

2017-03-12 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am|   1 +
 daemon/cleanups.c |   9 +++
 daemon/cleanups.h |   2 +
 daemon/yara.c | 201 ++
 generator/Makefile.am |   3 +
 generator/actions.ml  |   3 +-
 generator/proc_nr.ml  |   1 +
 gobject/Makefile.inc  |   6 +-
 lib/MAX_PROC_NR   |   2 +-
 9 files changed, 224 insertions(+), 4 deletions(-)
 create mode 100644 daemon/yara.c

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 9d73bb805..563622cdb 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -164,6 +164,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493d7..3102cf94b 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e2744..a791244cb 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0..0e4128aed
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,201 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *, const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (const char *namespace)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  ret = upload_to_fd (fd);
+  if (ret < 0) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+ret = yr_initialize ();
+if (ret != ERROR_SUCCESS) {
+  reply_with_error ("failed initializing yara");
+  unlink (tmpfile);
+  return -1;
+}
+
+initialized = true;
+  }
+
+  /* Clear namespace if no optional parameter is given. */
+  if (!(optargs_bitmask & GUESTFS

[Libguestfs] [PATCH v4 2/7] appliance: add yara dependency

2017-03-12 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in |  4 
 daemon/Makefile.am   |  3 ++-
 m4/guestfs_daemon.m4 | 14 ++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 5cf22768a..8846ce846 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -52,6 +52,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -86,6 +87,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-journal0
   libtirpc1
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -129,6 +131,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -159,6 +162,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index e3ad05350..9d73bb805 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -187,7 +187,8 @@ guestfsd_LDADD = \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
$(TSK_LIBS) \
-   $(RPC_LIBS)
+   $(RPC_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index eb5a6d5cf..522cd5f0e 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 1/7] daemon: expose file upload logic

2017-03-12 Thread Matteo Cafasso
Allows other modules to use the same logic for uploading files.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/daemon.h |  3 +++
 daemon/upload.c | 70 -
 2 files changed, 42 insertions(+), 31 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index 793074dea..bc89f78dd 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -258,6 +258,9 @@ extern int64_t ntfs_minimum_size (const char *device);
 extern int swap_set_uuid (const char *device, const char *uuid);
 extern int swap_set_label (const char *device, const char *label);

+/*-- in upload.c --*/
+extern int upload_to_fd (int fd);
+
 /* ordinary daemon functions use these to indicate errors
  * NB: you don't need to prefix the string with the current command,
  * it is added automatically by the client-side RPC stubs.
diff --git a/daemon/upload.c b/daemon/upload.c
index 655baf29d..144bb246c 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -54,60 +54,68 @@ write_cb (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+int
+upload_to_fd (int fd)
+{
+  int ret = 0, err = 0;
+  struct write_cb_data data = { .fd = fd, .written = 0 };
+
+  ret = receive_file (write_cb, );
+  if (ret == -1) { /* write error */
+err = errno;
+ret = cancel_receive ();
+errno = err;
+reply_with_error ("write error");
+close (fd);
+return -1;
+  }
+  if (ret == -2) { /* cancellation from library */
+/* This error is ignored by the library since it initiated the
+ * cancel.  Nevertheless we must send an error reply here.
+ */
+reply_with_error ("file upload cancelled");
+close (fd);
+return -1;
+  }
+
+  if (close (fd) == -1) {
+reply_with_perror ("close");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Has one FileIn parameter. */
 static int
 upload (const char *filename, int flags, int64_t offset)
 {
-  struct write_cb_data data = { .written = 0 };
-  int err, r, is_dev;
+  int err, is_dev, fd;

   is_dev = STRPREFIX (filename, "/dev/");

   if (!is_dev) CHROOT_IN;
-  data.fd = open (filename, flags, 0666);
+  fd = open (filename, flags, 0666);
   if (!is_dev) CHROOT_OUT;
-  if (data.fd == -1) {
+  if (fd == -1) {
 err = errno;
-r = cancel_receive ();
+cancel_receive ();
 errno = err;
 reply_with_perror ("%s", filename);
 return -1;
   }

   if (offset) {
-if (lseek (data.fd, offset, SEEK_SET) == -1) {
+if (lseek (fd, offset, SEEK_SET) == -1) {
   err = errno;
-  r = cancel_receive ();
+  cancel_receive ();
   errno = err;
   reply_with_perror ("lseek: %s", filename);
   return -1;
 }
   }

-  r = receive_file (write_cb, );
-  if (r == -1) {   /* write error */
-err = errno;
-r = cancel_receive ();
-errno = err;
-reply_with_error ("write error: %s", filename);
-close (data.fd);
-return -1;
-  }
-  if (r == -2) {   /* cancellation from library */
-/* This error is ignored by the library since it initiated the
- * cancel.  Nevertheless we must send an error reply here.
- */
-reply_with_error ("file upload cancelled");
-close (data.fd);
-return -1;
-  }
-
-  if (close (data.fd) == -1) {
-reply_with_perror ("close: %s", filename);
-return -1;
-  }
-
-  return 0;
+  return upload_to_fd (fd);
 }

 /* Has one FileIn parameter. */
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 7/7] yara_scan: added API tests

2017-03-12 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 
 tests/yara/test-yara-scan.sh | 72 
 3 files changed, 99 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index ecb2dca3c..6e7f4c540 100644
--- a/configure.ac
+++ b/configure.ac
@@ -296,6 +296,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 0..e23d94e4c
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 0..a899e33e4
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+if [ -n "$SKIP_TEST_YARA_SCAN_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+rm -f test-yara-rules.yar
+
+# Skip if Yara is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libyara"; then
+echo "$0: skipped because Yara is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/blank-fs.img ]; then
+echo "$0: skipped because blank-fs.img is zero-sized"
+exit 77
+fi
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 0/7] Feature: Yara file scanning

2017-02-19 Thread Matteo Cafasso
Rebase patches on top of 1.35.25.

No changes since last series.

Matteo Cafasso (7):
  daemon: expose file upload logic
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/daemon.h  |   3 +
 daemon/upload.c  |  70 +++
 daemon/yara.c| 301 +++
 generator/actions.ml |  64 +++
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   8 +-
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 lib/MAX_PROC_NR  |   2 +-
 lib/Makefile.am  |   1 +
 lib/yara.c   | 127 +
 m4/guestfs_daemon.m4 |  14 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  72 
 19 files changed, 684 insertions(+), 35 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 lib/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 3/7] New API: yara_load

2017-02-19 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am   |   1 +
 daemon/cleanups.c|   9 +++
 daemon/cleanups.h|   2 +
 daemon/yara.c| 201 +++
 generator/actions.ml |  21 ++
 gobject/Makefile.inc |   6 +-
 6 files changed, 238 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 2236abdd0..ba4256060 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -164,6 +164,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493d7..3102cf94b 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e2744..a791244cb 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 0..0e4128aed
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,201 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *, const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (const char *namespace)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  ret = upload_to_fd (fd);
+  if (ret < 0) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+ret = yr_initialize ();
+if (ret != ERROR_SUCCESS) {
+  reply_with_error ("failed initializing yara");
+  unlink (tmpfile);
+  return -1;
+}
+
+initialized = true;
+  }
+
+  /* Clear namespace if no optional parameter is given. */
+  if (!(optargs_bitmask & GUESTFS_YARA_LOAD_NAMESPACE_BITMASK))
+namespace = NULL;
+
+  /* Try to load the rules as co

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

2017-02-19 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml |  25 ++
 lib/Makefile.am  |   1 +
 lib/yara.c   | 127 +++
 3 files changed, 153 insertions(+)
 create mode 100644 lib/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 7e62e21af..5eddc2032 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3756,6 +3756,31 @@ Searches all the entries associated with the given inode.
 For each entry, a C structure is returned.
 See C for more information about C structures." };

+  { defaults with
+name = "yara_scan"; added = (1, 35, 26);
+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 structure is returned.
+
+The C 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/lib/Makefile.am b/lib/Makefile.am
index e1ab1bff9..7a3b854cd 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -126,6 +126,7 @@ libguestfs_la_SOURCES = \
wait.c \
whole-file.c \
version.c \
+   yara.c \
libguestfs.syms

 libguestfs_la_CPPFLAGS = \
diff --git a/lib/yara.c b/lib/yara.c
new file mode 100644
index 0..864766e7a
--- /dev/null
+++ b/lib/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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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.

[Libguestfs] [PATCH v3 1/7] daemon: expose file upload logic

2017-02-19 Thread Matteo Cafasso
Allows other modules to use the same logic for uploading files.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/daemon.h |  3 +++
 daemon/upload.c | 70 -
 2 files changed, 42 insertions(+), 31 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index 793074dea..bc89f78dd 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -258,6 +258,9 @@ extern int64_t ntfs_minimum_size (const char *device);
 extern int swap_set_uuid (const char *device, const char *uuid);
 extern int swap_set_label (const char *device, const char *label);

+/*-- in upload.c --*/
+extern int upload_to_fd (int fd);
+
 /* ordinary daemon functions use these to indicate errors
  * NB: you don't need to prefix the string with the current command,
  * it is added automatically by the client-side RPC stubs.
diff --git a/daemon/upload.c b/daemon/upload.c
index 655baf29d..144bb246c 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -54,60 +54,68 @@ write_cb (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+int
+upload_to_fd (int fd)
+{
+  int ret = 0, err = 0;
+  struct write_cb_data data = { .fd = fd, .written = 0 };
+
+  ret = receive_file (write_cb, );
+  if (ret == -1) { /* write error */
+err = errno;
+ret = cancel_receive ();
+errno = err;
+reply_with_error ("write error");
+close (fd);
+return -1;
+  }
+  if (ret == -2) { /* cancellation from library */
+/* This error is ignored by the library since it initiated the
+ * cancel.  Nevertheless we must send an error reply here.
+ */
+reply_with_error ("file upload cancelled");
+close (fd);
+return -1;
+  }
+
+  if (close (fd) == -1) {
+reply_with_perror ("close");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Has one FileIn parameter. */
 static int
 upload (const char *filename, int flags, int64_t offset)
 {
-  struct write_cb_data data = { .written = 0 };
-  int err, r, is_dev;
+  int err, is_dev, fd;

   is_dev = STRPREFIX (filename, "/dev/");

   if (!is_dev) CHROOT_IN;
-  data.fd = open (filename, flags, 0666);
+  fd = open (filename, flags, 0666);
   if (!is_dev) CHROOT_OUT;
-  if (data.fd == -1) {
+  if (fd == -1) {
 err = errno;
-r = cancel_receive ();
+cancel_receive ();
 errno = err;
 reply_with_perror ("%s", filename);
 return -1;
   }

   if (offset) {
-if (lseek (data.fd, offset, SEEK_SET) == -1) {
+if (lseek (fd, offset, SEEK_SET) == -1) {
   err = errno;
-  r = cancel_receive ();
+  cancel_receive ();
   errno = err;
   reply_with_perror ("lseek: %s", filename);
   return -1;
 }
   }

-  r = receive_file (write_cb, );
-  if (r == -1) {   /* write error */
-err = errno;
-r = cancel_receive ();
-errno = err;
-reply_with_error ("write error: %s", filename);
-close (data.fd);
-return -1;
-  }
-  if (r == -2) {   /* cancellation from library */
-/* This error is ignored by the library since it initiated the
- * cancel.  Nevertheless we must send an error reply here.
- */
-reply_with_error ("file upload cancelled");
-close (data.fd);
-return -1;
-  }
-
-  if (close (data.fd) == -1) {
-reply_with_perror ("close: %s", filename);
-return -1;
-  }
-
-  return 0;
+  return upload_to_fd (fd);
 }

 /* Has one FileIn parameter. */
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 5/7] New API: internal_yara_scan

2017-02-19 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/actions.ml | 10 
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 lib/MAX_PROC_NR  |  2 +-
 7 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index cb49593c7..471547341 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -54,6 +54,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *, const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -119,6 +121,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (ret == ERROR_SUCCESS)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -170,6 +204,58 @@ compile_error_callback(int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int ret = 0;
+  size_t len = 0;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.name = (char *) name;
+  detection.rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  ret = xdr_guestfs_int_yara_detection (, );
+  if (ret == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/actions.ml b/generator/actions.ml
index 149c4a938..7e62e21af 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13338,6 +13338,16 @@ but belonging to different files." };
 shortdesc = "destroy previously loaded yara rules";
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
+  { defaults with
+name = "internal_yara_scan"; added = (1, 35, 26);
+style = RErr, [Pathname "path"; FileOut "filename";], [];
+proc_nr = Some 474;
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/generator/structs.ml b/generator/structs.ml
index c1c9b668e..01aa3d371 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -469,6 +469,15 @@ let structs = [
 ];
 s_camel_name = "TSKDirent" };

+  (* Yara detection information. *)
+  { defaults with
+s_name = "yara_detection";
+s_cols = [
+"

[Libguestfs] [PATCH v3 4/7] New API: yara_destroy

2017-02-19 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 14 ++
 generator/actions.ml |  8 
 lib/MAX_PROC_NR  |  2 +-
 3 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 0e4128aed..cb49593c7 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -105,6 +105,20 @@ do_yara_load (const char *namespace)
   return (ret == ERROR_SUCCESS) ? 0 : -1;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
diff --git a/generator/actions.ml b/generator/actions.ml
index 285c450bb..149c4a938 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13330,6 +13330,14 @@ Different rules files can be loaded sequentially. The 
optional parameter
 C can be used to distinguish rules with the same identifier
 but belonging to different files." };

+  { defaults with
+name = "yara_destroy"; added = (1, 35, 26);
+style = RErr, [], [];
+proc_nr = Some 473;
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index c305aa5ae..68cfb10d1 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-471
+472
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 7/7] yara_scan: added API tests

2017-02-19 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 
 tests/yara/test-yara-scan.sh | 72 
 3 files changed, 99 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index 1e25846e0..999c31184 100644
--- a/configure.ac
+++ b/configure.ac
@@ -295,6 +295,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 0..e23d94e4c
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 0..a899e33e4
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+if [ -n "$SKIP_TEST_YARA_SCAN_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+rm -f test-yara-rules.yar
+
+# Skip if Yara is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libyara"; then
+echo "$0: skipped because Yara is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/blank-fs.img ]; then
+echo "$0: skipped because blank-fs.img is zero-sized"
+exit 77
+fi
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 2/7] appliance: add yara dependency

2017-02-19 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in |  4 
 daemon/Makefile.am   |  3 ++-
 m4/guestfs_daemon.m4 | 14 ++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index 8ed3afedc..0b9e786d9 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -51,6 +51,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -84,6 +85,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-id128-0
   libsystemd-journal0
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -126,6 +128,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -155,6 +158,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 5c4ae8e0a..2236abdd0 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -186,7 +186,8 @@ guestfsd_LDADD = \
$(LIBINTL) \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
-   $(TSK_LIBS)
+   $(TSK_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index eb5a6d5cf..522cd5f0e 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 4/6] New API: internal_yara_scan

2016-12-18 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 86 
 generator/actions.ml | 10 
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 src/MAX_PROC_NR  |  2 +-
 7 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index cb49593..4715473 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -54,6 +54,8 @@ static bool initialized = false;
 static int compile_rules_file (const char *, const char *);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
 static void cleanup_destroy_yara_compiler (void *ptr);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter.
  * Takes optional arguments, consult optargs_bitmask.
@@ -119,6 +121,38 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (ret == ERROR_SUCCESS)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Compile source code rules and load them.
  * Return ERROR_SUCCESS on success, Yara error code type on error.
  */
@@ -170,6 +204,58 @@ compile_error_callback(int level, const char *name, int 
line,
 fprintf (stderr, "Yara warning (line %d): %s\n", line, message);
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int ret = 0;
+  size_t len = 0;
+  CLEANUP_FREE char *buf = NULL;
+  struct guestfs_int_yara_detection detection;
+
+  detection.name = (char *) name;
+  detection.rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  ret = xdr_guestfs_int_yara_detection (, );
+  if (ret == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised yara_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));

diff --git a/generator/actions.ml b/generator/actions.ml
index b9055c4..75da607 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13295,4 +13295,14 @@ but belonging to different files." };
 shortdesc = "destroy previously loaded yara rules";
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
+  { defaults with
+name = "internal_yara_scan"; added = (1, 35, 19);
+style = RErr, [Pathname "path"; FileOut "filename";], [];
+proc_nr = Some 473;
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/generator/structs.ml b/generator/structs.ml
index 029bc3a..3fa2ebc 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -468,6 +468,15 @@ let structs = [
 ];
 s_camel_name = "TSKDirent" };

+  (* Yara detection information. *)
+  { defaults with
+s_name = "yara_detection";
+s_cols = [
+"name"

[Libguestfs] [PATCH v3 2/6] New API: yara_load

2016-12-18 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am   |   1 +
 daemon/cleanups.c|   9 +++
 daemon/cleanups.h|   2 +
 daemon/yara.c| 201 +++
 generator/actions.ml |  20 +
 gobject/Makefile.inc |   6 +-
 src/MAX_PROC_NR  |   2 +-
 7 files changed, 238 insertions(+), 3 deletions(-)
 create mode 100644 daemon/yara.c

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3a25f43..c385edc 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -200,6 +200,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493..3102cf9 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -62,6 +62,15 @@ cleanup_close (void *ptr)
 }

 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e27..a791244 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,6 +26,7 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);

@@ -35,6 +36,7 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
 #else
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 000..0e4128a
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,201 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int compile_rules_file (const char *, const char *);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static void cleanup_destroy_yara_compiler (void *ptr);
+
+/* Has one FileIn parameter.
+ * Takes optional arguments, consult optargs_bitmask.
+ */
+int
+do_yara_load (const char *namespace)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = -1;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  fd = mkstemp (tmpfile);
+  if (fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  ret = upload_to_fd (fd);
+  if (ret < 0) {
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Initialize yara only once. */
+  if (!initialized) {
+ret = yr_initialize ();
+if (ret != ERROR_SUCCESS) {
+  reply_with_error ("failed initializing yara");
+  unlink (tmpfile);
+  return -1;
+}
+
+initialized = true;
+  }
+
+  /* Clear namespace if no optional parameter is given. */
+  if (!(optargs_bitmask & GUESTFS_YARA_LOAD_NAMESPACE_BITMASK))
+namespace = NULL;
+
+  /* Try to load 

[Libguestfs] [PATCH v3 0/6] Feature: Yara file scanning

2016-12-18 Thread Matteo Cafasso
v3:

 - allow to load multiple rule files
 - added optional namespace parameter to yara_load
 - move destructor logic in yara module
 - use generic file upload logic
 - use generic temporary path function

Matteo Cafasso (6):
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|   9 +
 daemon/cleanups.h|   2 +
 daemon/yara.c| 301 +++
 generator/actions.ml |  64 +++
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   8 +-
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 m4/guestfs_daemon.m4 |  14 ++
 src/MAX_PROC_NR  |   2 +-
 src/Makefile.am  |   1 +
 src/yara.c   | 127 +
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  72 
 17 files changed, 642 insertions(+), 4 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 src/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.11.0

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 6/6] yara_scan: added API tests

2016-12-18 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 
 tests/yara/test-yara-scan.sh | 72 
 3 files changed, 99 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index 495c9f8..0fc7ba4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -285,6 +285,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 000..e23d94e
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 000..a899e33
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+if [ -n "$SKIP_TEST_YARA_SCAN_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+rm -f test-yara-rules.yar
+
+# Skip if Yara is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libyara"; then
+echo "$0: skipped because Yara is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/blank-fs.img ]; then
+echo "$0: skipped because blank-fs.img is zero-sized"
+exit 77
+fi
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


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

2016-12-18 Thread Matteo Cafasso
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 <noxda...@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 structure is returned.
 See C for more information about C 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 structure is returned.
+
+The C 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 000..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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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.

[Libguestfs] [PATCH v3 1/6] appliance: add yara dependency

2016-12-18 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in |  4 
 daemon/Makefile.am   |  3 ++-
 m4/guestfs_daemon.m4 | 14 ++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index bbbe4b2..352133c 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -51,6 +51,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )

@@ -83,6 +84,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-id128-0
   libsystemd-journal0
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -125,6 +127,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )

 ifelse(SUSE,1,
@@ -153,6 +156,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )

 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 23f60eb..3a25f43 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -222,7 +222,8 @@ guestfsd_LDADD = \
$(LIBINTL) \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
-   $(TSK_LIBS)
+   $(TSK_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index 12123df..0018930 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH] daemon: expose file upload logic

2016-12-14 Thread Matteo Cafasso
Allows other modules to use the same logic for uploading files.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/daemon.h |  3 +++
 daemon/upload.c | 70 -
 2 files changed, 42 insertions(+), 31 deletions(-)

diff --git a/daemon/daemon.h b/daemon/daemon.h
index 2379e31..1723b68 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -256,6 +256,9 @@ extern int64_t ntfs_minimum_size (const char *device);
 extern int swap_set_uuid (const char *device, const char *uuid);
 extern int swap_set_label (const char *device, const char *label);

+/*-- in upload.c --*/
+extern int upload_to_fd (int fd);
+
 /* ordinary daemon functions use these to indicate errors
  * NB: you don't need to prefix the string with the current command,
  * it is added automatically by the client-side RPC stubs.
diff --git a/daemon/upload.c b/daemon/upload.c
index 8b4f600..0f385b6 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -54,60 +54,68 @@ write_cb (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+int
+upload_to_fd (int fd)
+{
+  int ret = 0, err = 0;
+  struct write_cb_data data = { .fd = fd, .written = 0 };
+
+  ret = receive_file (write_cb, );
+  if (ret == -1) { /* write error */
+err = errno;
+ret = cancel_receive ();
+errno = err;
+reply_with_error ("write error");
+close (fd);
+return -1;
+  }
+  if (ret == -2) { /* cancellation from library */
+/* This error is ignored by the library since it initiated the
+ * cancel.  Nevertheless we must send an error reply here.
+ */
+reply_with_error ("file upload cancelled");
+close (fd);
+return -1;
+  }
+
+  if (close (fd) == -1) {
+reply_with_perror ("close");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Has one FileIn parameter. */
 static int
 upload (const char *filename, int flags, int64_t offset)
 {
-  struct write_cb_data data = { .written = 0 };
-  int err, r, is_dev;
+  int err, is_dev, fd;

   is_dev = STRPREFIX (filename, "/dev/");

   if (!is_dev) CHROOT_IN;
-  data.fd = open (filename, flags, 0666);
+  fd = open (filename, flags, 0666);
   if (!is_dev) CHROOT_OUT;
-  if (data.fd == -1) {
+  if (fd == -1) {
 err = errno;
-r = cancel_receive ();
+cancel_receive ();
 errno = err;
 reply_with_perror ("%s", filename);
 return -1;
   }

   if (offset) {
-if (lseek (data.fd, offset, SEEK_SET) == -1) {
+if (lseek (fd, offset, SEEK_SET) == -1) {
   err = errno;
-  r = cancel_receive ();
+  cancel_receive ();
   errno = err;
   reply_with_perror ("lseek: %s", filename);
   return -1;
 }
   }

-  r = receive_file (write_cb, );
-  if (r == -1) {   /* write error */
-err = errno;
-r = cancel_receive ();
-errno = err;
-reply_with_error ("write error: %s", filename);
-close (data.fd);
-return -1;
-  }
-  if (r == -2) {   /* cancellation from library */
-/* This error is ignored by the library since it initiated the
- * cancel.  Nevertheless we must send an error reply here.
- */
-reply_with_error ("file upload cancelled");
-close (data.fd);
-return -1;
-  }
-
-  if (close (data.fd) == -1) {
-reply_with_perror ("close: %s", filename);
-return -1;
-  }
-
-  return 0;
+  return upload_to_fd (fd);
 }

 /* Has one FileIn parameter. */
--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH] daemon: expose file upload logic

2016-12-14 Thread Matteo Cafasso
Exposing file upload logic as suggested in previous patch:
https://www.redhat.com/archives/libguestfs/2016-November/msg00109.html

Matteo Cafasso (1):
  daemon: expose upload logic

 daemon/daemon.h |  3 +++
 daemon/upload.c | 70 -
 2 files changed, 42 insertions(+), 31 deletions(-)

--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 2/2] lib: use guestfs_int_make_temp_path to generate temporary files

2016-12-11 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 src/drives.c  |  5 ++---
 src/file.c| 22 +-
 src/journal.c |  4 ++--
 src/tsk.c | 17 ++---
 4 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/src/drives.c b/src/drives.c
index 1e3b0af..1e04f81 100644
--- a/src/drives.c
+++ b/src/drives.c
@@ -421,7 +421,8 @@ create_drive_dev_null (guestfs_h *g,
 data->format = "raw";
   }

-  if (guestfs_int_lazy_make_tmpdir (g) == -1)
+  tmpfile = guestfs_int_make_temp_path (g, "devnull");
+  if (tmpfile == NULL)
 return NULL;

   /* Because we create a special file, there is no point forcing qemu
@@ -429,8 +430,6 @@ create_drive_dev_null (guestfs_h *g,
*/
   data->readonly = false;

-  tmpfile = safe_asprintf (g, "%s/devnull%d", g->tmpdir, ++g->unique);
-
   if (guestfs_disk_create (g, tmpfile, "raw", 4096, -1) == -1)
 return NULL;

diff --git a/src/file.c b/src/file.c
index d57c4e1..53b859d 100644
--- a/src/file.c
+++ b/src/file.c
@@ -86,11 +86,10 @@ guestfs_impl_read_file (guestfs_h *g, const char *path, 
size_t *size_r)
   char *ret = NULL;
   struct stat statbuf;

-  if (guestfs_int_lazy_make_tmpdir (g) == -1)
+  tmpfile = guestfs_int_make_temp_path (g, "cat");
+  if (tmpfile == NULL)
 goto err;

-  tmpfile = safe_asprintf (g, "%s/cat%d", g->tmpdir, ++g->unique);
-
   if (guestfs_download (g, path, tmpfile) == -1)
 goto err;

@@ -213,11 +212,10 @@ guestfs_impl_find (guestfs_h *g, const char *directory)
   char **ret = NULL;
   size_t i, count, size;

-  if (guestfs_int_lazy_make_tmpdir (g) == -1)
+  tmpfile = guestfs_int_make_temp_path (g, "find");
+  if (tmpfile == NULL)
 goto err;

-  tmpfile = safe_asprintf (g, "%s/find%d", g->tmpdir, ++g->unique);
-
   if (guestfs_find0 (g, directory, tmpfile) == -1)
 goto err;

@@ -317,11 +315,10 @@ write_or_append (guestfs_h *g, const char *path,
   (!append ? guestfs_internal_write : guestfs_internal_write_append)
   (g, path, content, size);

-  if (guestfs_int_lazy_make_tmpdir (g) == -1)
-goto err;
-
   /* Write the content out to a temporary file. */
-  tmpfile = safe_asprintf (g, "%s/write%d", g->tmpdir, ++g->unique);
+  tmpfile = guestfs_int_make_temp_path (g, "write");
+  if (tmpfile == NULL)
+goto err;

   fd = open (tmpfile, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0600);
   if (fd == -1) {
@@ -515,11 +512,10 @@ guestfs_impl_ls (guestfs_h *g, const char *directory)
   char **ret = NULL;
   size_t i, count, size;

-  if (guestfs_int_lazy_make_tmpdir (g) == -1)
+  tmpfile = guestfs_int_make_temp_path (g, "ls");
+  if (tmpfile == NULL)
 goto err;

-  tmpfile = safe_asprintf (g, "%s/ls%d", g->tmpdir, ++g->unique);
-
   if (guestfs_ls0 (g, directory, tmpfile) == -1)
 goto err;

diff --git a/src/journal.c b/src/journal.c
index 22b81de..f36e661 100644
--- a/src/journal.c
+++ b/src/journal.c
@@ -66,10 +66,10 @@ guestfs_impl_journal_get (guestfs_h *g)
   size_t i, j, size;
   uint64_t len;

-  if (guestfs_int_lazy_make_tmpdir (g) == -1)
+  tmpfile = guestfs_int_make_temp_path (g, "journal");
+  if (tmpfile == NULL)
 goto err;

-  tmpfile = safe_asprintf (g, "%s/journal%d", g->tmpdir, ++g->unique);
   if (guestfs_internal_journal_get (g, tmpfile) == -1)
 goto err;

diff --git a/src/tsk.c b/src/tsk.c
index 1def9c9..da9ca8d 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -36,7 +36,6 @@

 static struct guestfs_tsk_dirent_list *parse_dirent_file (guestfs_h *, const 
char *);
 static int deserialise_dirent_list (guestfs_h *, FILE *, struct 
guestfs_tsk_dirent_list *);
-static char *make_temp_file (guestfs_h *, const char *);

 struct guestfs_tsk_dirent_list *
 guestfs_impl_filesystem_walk (guestfs_h *g, const char *mountable)
@@ -44,7 +43,7 @@ guestfs_impl_filesystem_walk (guestfs_h *g, const char 
*mountable)
   int ret = 0;
   CLEANUP_UNLINK_FREE char *tmpfile = NULL;

-  tmpfile = make_temp_file (g, "filesystem_walk");
+  tmpfile = guestfs_int_make_temp_path (g, "filesystem_walk");
   if (tmpfile == NULL)
 return NULL;

@@ -61,7 +60,7 @@ guestfs_impl_find_inode (guestfs_h *g, const char *mountable, 
int64_t inode)
   int ret = 0;
   CLEANUP_UNLINK_FREE char *tmpfile = NULL;

-  tmpfile = make_temp_file (g, "find_inode");
+  tmpfile = guestfs_int_make_temp_path (g, "find_inode");
   if (tmpfile == NULL)
 return NULL;

@@ -142,15 +141,3 @@ deserialise_dirent_list (guestfs_h *g, FILE *fp,

   return ret ? 0 : -1;
 }
-
-static char *
-make_temp_file (guestfs_h *g, const char *name)
-{
-  int ret = 0;
-
-  ret = guestfs_int_lazy_make_tmpdir (g);
-  if (ret < 0)
-return NULL;
-
-  return safe_asprintf (g, "%s/%s%d", g->tmpdir, name, ++g->unique);
-}
--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 0/2] generic function for temporary path generation

2016-12-11 Thread Matteo Cafasso
Cosmetic change as suggested in this previous patch:
https://www.redhat.com/archives/libguestfs/2016-November/msg00111.html


Matteo Cafasso (2):
  lib: generic function for temporary path generation
  lib: use guestfs_int_make_temp_path to generate temporary files

 src/drives.c   |  5 ++---
 src/file.c | 22 +-
 src/guestfs-internal.h |  1 +
 src/journal.c  |  4 ++--
 src/tmpdirs.c  | 17 +
 src/tsk.c  | 17 ++---
 6 files changed, 33 insertions(+), 33 deletions(-)

--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 1/2] lib: generic function for temporary path generation

2016-12-11 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 src/guestfs-internal.h |  1 +
 src/tmpdirs.c  | 17 +
 2 files changed, 18 insertions(+)

diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index fbbfb90..51d3512 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -813,6 +813,7 @@ extern int guestfs_int_set_env_tmpdir (guestfs_h *g, const 
char *envname, const
 extern int guestfs_int_set_env_runtimedir (guestfs_h *g, const char *envname, 
const char *runtimedir);
 extern int guestfs_int_lazy_make_tmpdir (guestfs_h *g);
 extern int guestfs_int_lazy_make_sockdir (guestfs_h *g);
+extern char *guestfs_int_make_temp_path (guestfs_h *g, const char *name);
 extern char *guestfs_int_lazy_make_supermin_appliance_dir (guestfs_h *g);
 extern void guestfs_int_remove_tmpdir (guestfs_h *g);
 extern void guestfs_int_remove_sockdir (guestfs_h *g);
diff --git a/src/tmpdirs.c b/src/tmpdirs.c
index 725f683..7d289a6 100644
--- a/src/tmpdirs.c
+++ b/src/tmpdirs.c
@@ -223,6 +223,23 @@ guestfs_int_lazy_make_sockdir (guestfs_h *g)
 }

 /**
+ * Generate unique temporary paths for temporary files.
+ *
+ * Returns a unique path or NULL on error.
+ */
+char *
+guestfs_int_make_temp_path (guestfs_h *g, const char *name)
+{
+  int ret = 0;
+
+  ret = guestfs_int_lazy_make_tmpdir (g);
+  if (ret < 0)
+return NULL;
+
+  return safe_asprintf (g, "%s/%s%d", g->tmpdir, name, ++g->unique);
+}
+
+/**
  * Create the supermin appliance directory under cachedir, if it does
  * not exist.
  *
--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH] upload: improve file write callback

2016-11-09 Thread Matteo Cafasso
As noted by Pino in another patch, the logic passes the first member of
the struct which happens to be the right address to the callback
function.

This will break the callback if order of the members of the struct will
change.

As the callback is using the entire struct, better to pass the pointer
to the struct itself.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/upload.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/daemon/upload.c b/daemon/upload.c
index f034627..8b4f600 100644
--- a/daemon/upload.c
+++ b/daemon/upload.c
@@ -84,7 +84,7 @@ upload (const char *filename, int flags, int64_t offset)
 }
   }

-  r = receive_file (write_cb, );
+  r = receive_file (write_cb, );
   if (r == -1) {   /* write error */
 err = errno;
 r = cancel_receive ();
--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 2/6] New API: yara_load

2016-11-09 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am   |   1 +
 daemon/cleanups.c|  28 +++
 daemon/cleanups.h|   9 ++
 daemon/yara.c| 227 +++
 generator/actions.ml |  18 
 src/MAX_PROC_NR  |   2 +-
 6 files changed, 284 insertions(+), 1 deletion(-)
 create mode 100644 daemon/yara.c

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3a25f43..c385edc 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -200,6 +200,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c
 
diff --git a/daemon/cleanups.c b/daemon/cleanups.c
index 092e493..a02e521 100644
--- a/daemon/cleanups.c
+++ b/daemon/cleanups.c
@@ -24,6 +24,12 @@
 
 #include 
 
+#ifdef HAVE_YARA
+
+#include 
+
+#endif  /* !HAVE_YARA */
+
 #include "cleanups.h"
 
 /* Use by the CLEANUP_* macros.  Do not call these directly. */
@@ -62,6 +68,15 @@ cleanup_close (void *ptr)
 }
 
 void
+cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+fclose (f);
+}
+
+void
 cleanup_aug_close (void *ptr)
 {
   augeas *aug = * (augeas **) ptr;
@@ -78,3 +93,16 @@ cleanup_free_stringsbuf (void *ptr)
 {
   free_stringsbuf ((struct stringsbuf *) ptr);
 }
+
+#ifdef HAVE_YARA
+
+void
+cleanup_destroy_yara_compiler (void *ptr)
+{
+  YR_COMPILER *compiler = * (YR_COMPILER **) ptr;
+
+  if (compiler != NULL)
+yr_compiler_destroy (compiler);
+}
+
+#endif  /* !HAVE_YARA */
diff --git a/daemon/cleanups.h b/daemon/cleanups.h
index 6746e27..c61f646 100644
--- a/daemon/cleanups.h
+++ b/daemon/cleanups.h
@@ -26,8 +26,12 @@ extern void cleanup_free (void *ptr);
 extern void cleanup_free_string_list (void *ptr);
 extern void cleanup_unlink_free (void *ptr);
 extern void cleanup_close (void *ptr);
+extern void cleanup_fclose (void *ptr);
 extern void cleanup_aug_close (void *ptr);
 extern void cleanup_free_stringsbuf (void *ptr);
+#ifdef HAVE_YARA
+extern void cleanup_destroy_yara_compiler (void *ptr);
+#endif  /* !HAVE_YARA */
 
 #ifdef HAVE_ATTRIBUTE_CLEANUP
 #define CLEANUP_FREE __attribute__((cleanup(cleanup_free)))
@@ -35,8 +39,13 @@ extern void cleanup_free_stringsbuf (void *ptr);
 __attribute__((cleanup(cleanup_free_string_list)))
 #define CLEANUP_UNLINK_FREE __attribute__((cleanup(cleanup_unlink_free)))
 #define CLEANUP_CLOSE __attribute__((cleanup(cleanup_close)))
+#define CLEANUP_FCLOSE __attribute__((cleanup(cleanup_fclose)))
 #define CLEANUP_AUG_CLOSE __attribute__((cleanup(cleanup_aug_close)))
 #define CLEANUP_FREE_STRINGSBUF 
__attribute__((cleanup(cleanup_free_stringsbuf)))
+#ifdef HAVE_YARA
+#define CLEANUP_DESTROY_YARA_COMPILER   \
+  __attribute__((cleanup(cleanup_destroy_yara_compiler)))
+#endif  /* !HAVE_YARA */
 #else
 #define CLEANUP_FREE
 #define CLEANUP_FREE_STRING_LIST
diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 000..be53322
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,227 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_YARA
+
+#include 
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+static bool initialized = false;
+
+static int upload_rules_file (char *);
+static int compile_rules_file (const char *);
+static int write_callback (void *, const void *, size_t);
+static void compile_error_callback (int, const char *, int, const char *, void 
*);
+
+/* Has one FileIn parameter. */
+int
+do_yara_load (void)
+{
+  int 

[Libguestfs] [PATCH v2 1/6] appliance: add yara dependency

2016-11-09 Thread Matteo Cafasso
libyara3 on Debian/Ubuntu
yara on SUSE/RedHat

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in |  4 
 daemon/Makefile.am   |  3 ++-
 m4/guestfs_daemon.m4 | 14 ++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index f278f66..2da7533 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -51,6 +51,7 @@ ifelse(REDHAT,1,
   vim-minimal
   xz
   yajl
+  yara
   zfs-fuse
 )
 
@@ -83,6 +84,7 @@ dnl iproute has been renamed to iproute2
   libsystemd-id128-0
   libsystemd-journal0
   libyajl2
+  libyara3
   linux-image
   dnl syslinux 'suggests' mtools, but in reality it's a hard dependency:
   mtools
@@ -125,6 +127,7 @@ ifelse(ARCHLINUX,1,
   vim
   xz
   yajl
+  yara
 )
 
 ifelse(SUSE,1,
@@ -152,6 +155,7 @@ ifelse(SUSE,1,
   systemd
   vim
   xz
+  yara
 )
 
 ifelse(FRUGALWARE,1,
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 23f60eb..3a25f43 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -222,7 +222,8 @@ guestfsd_LDADD = \
$(LIBINTL) \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
-   $(TSK_LIBS)
+   $(TSK_LIBS) \
+   $(YARA_LIBS)
 
 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index 12123df..0018930 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,17 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+PKG_CHECK_MODULES([YARA], [libyara],[
+AC_SUBST([YARA_CFLAGS])
+AC_SUBST([YARA_LIBS])
+AC_DEFINE([HAVE_YARA],[1],[yara library found at compile time.])
+],[
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_YARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
+])
-- 
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


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

2016-11-09 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml |  25 +
 src/Makefile.am  |   1 +
 src/yara.c   | 140 +++
 3 files changed, 166 insertions(+)
 create mode 100644 src/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index d9006f2..8595b38 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3729,6 +3729,31 @@ Searches all the entries associated with the given inode.
 For each entry, a C structure is returned.
 See C for more information about C structures." };
 
+  { defaults with
+name = "yara_scan"; added = (1, 35, 15);
+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 structure is returned.
+
+The C 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 000..0b924a2
--- /dev/null
+++ b/src/yara.c
@@ -0,0 +1,140 @@
+/* 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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 *);
+static char *make_temp_file (guestfs_h *, const char *);
+
+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 = make_temp_file (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 fil

[Libguestfs] [PATCH v2 3/6] New API: yara_destroy

2016-11-09 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 14 ++
 generator/actions.ml |  9 +
 src/MAX_PROC_NR  |  2 +-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index be53322..fe1f69a 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -93,6 +93,20 @@ do_yara_load (void)
   return (ret == ERROR_SUCCESS) ? 0 : -1;
 }
 
+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Upload rules file on a temporary file.
  * Return 0 on success, -1 on error.
  */
diff --git a/generator/actions.ml b/generator/actions.ml
index f69564a..152c651 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13271,6 +13271,15 @@ Rules in source code format cannot include external 
files. In such cases,
 it is recommended to compile them first.
 
 Previously loaded rules will be destroyed." };
+
+  { defaults with
+name = "yara_destroy"; added = (1, 35, 15);
+style = RErr, [], [];
+proc_nr = Some 472;
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
 ]
 
 (* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index c305aa5..68cfb10 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-471
+472
-- 
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 6/6] yara_scan: added API tests

2016-11-09 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 
 tests/yara/test-yara-scan.sh | 72 
 3 files changed, 99 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index 45bb935..0681010 100644
--- a/configure.ac
+++ b/configure.ac
@@ -285,6 +285,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 000..e23d94e
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 000..a899e33
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+if [ -n "$SKIP_TEST_YARA_SCAN_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+rm -f test-yara-rules.yar
+
+# Skip if Yara is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libyara"; then
+echo "$0: skipped because Yara is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/blank-fs.img ]; then
+echo "$0: skipped because blank-fs.img is zero-sized"
+exit 77
+fi
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 0/6] Feature: Yara file scanning

2016-11-09 Thread Matteo Cafasso
v2:

 - Fix yara dependency in packagelist
 - Use pkg-config where available
 - Improve longdesc of yara_load API
 - Fix libyara initialization and finalization
 - Import CLEANUP_FCLOSE
 - Add custom CLEANUP_DESTROY_YARA_COMPILER
 - Add rules compilation error callback
 - Other small fixes according to comments


Matteo Cafasso (6):
  appliance: add yara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   4 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/cleanups.c|  28 +++
 daemon/cleanups.h|   9 +
 daemon/yara.c| 328 +++
 generator/actions.ml |  62 ++
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   2 +
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 m4/guestfs_daemon.m4 |  14 ++
 src/MAX_PROC_NR  |   2 +-
 src/Makefile.am  |   1 +
 src/yara.c   | 140 +
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  72 +++
 17 files changed, 702 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 src/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.10.2

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 4/6] New API: internal_yara_scan

2016-11-09 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 87 
 generator/actions.ml | 10 
 generator/structs.ml |  9 
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 src/MAX_PROC_NR  |  2 +-
 7 files changed, 111 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index fe1f69a..8e7d328 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -52,6 +52,8 @@ static int upload_rules_file (char *);
 static int compile_rules_file (const char *);
 static int write_callback (void *, const void *, size_t);
 static void compile_error_callback (int, const char *, int, const char *, void 
*);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);
 
 /* Has one FileIn parameter. */
 int
@@ -107,6 +109,39 @@ do_yara_destroy (void)
   return 0;
 }
 
+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = 0;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+yr_finalize ();
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (ret == ERROR_SUCCESS)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  return 0;
+}
+
 /* Upload rules file on a temporary file.
  * Return 0 on success, -1 on error.
  */
@@ -209,6 +244,58 @@ compile_error_callback(int level, const char *name, int 
line,
 fprintf (stderr, "(%d): Yara warning: %s\n", line, message);
 }
 
+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int ret = 0;
+  size_t len = 0;
+  struct guestfs_int_yara_detection detection;
+  CLEANUP_FREE char *buf = NULL, *fname = NULL;
+
+  detection.name = (char *) name;
+  detection.rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  ret = xdr_guestfs_int_yara_detection (, );
+  if (ret == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised tsk_detection out. */
+  return send_file_write (buf, len);
+}
+
 /* Clean up yara handle on daemon exit. */
 void yara_finalize (void) __attribute__((destructor));
 void
diff --git a/generator/actions.ml b/generator/actions.ml
index 152c651..d9006f2 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13280,6 +13280,16 @@ Previously loaded rules will be destroyed." };
 shortdesc = "destroy previously loaded yara rules";
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
+  { defaults with
+name = "internal_yara_scan"; added = (1, 35, 15);
+style = RErr, [Pathname "path"; FileOut "filename";], [];
+proc_nr = Some 473;
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]
 
 (* Non-API meta-commands available only in guestfish.
diff --git a/generator/structs.ml b/generator/structs.ml
index 029bc3a..3fa2ebc 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -468,6 +468,15 @@ let structs = [
 ];
 s_camel_name = "TSKDirent" };
 
+  (* Yara detection information. *)
+  { defaults with
+s_name = "yara_detection";
+s_cols = [
+"name", FString;
+"rule", FS

[Libguestfs] [PATCH 0/6] Feature: Yara file scanning

2016-11-02 Thread Matteo Cafasso
Yara is a rule based scanning engine aimed to help malware analysts in finding 
and classifying interesting samples.

https://github.com/VirusTotal/yara

This series adds Yara support to Libguestfs allowing to upload sets of rules 
and scanning files against them.

Currently provided APIs:

 - yara_load: loads a set of rules
 - yara_destroy: free resources allocated by loaded rules
 - yara_scan: scans a file with the loaded rules

Future APIs:

 - yara_scan_recursive: scan the entire FS starting from the given point (could 
it be a flag in yara_scan?)
 - yara_scan_inode: use TSK to scan files by inodes allowing to scan deleted or 
hidden files

Code ready for review, available here:

https://github.com/noxdafox/libguestfs/tree/yara


Matteo Cafasso (6):
  appliance: add libyara dependency
  New API: yara_load
  New API: yara_destroy
  New API: internal_yara_scan
  New API: yara_scan
  yara_scan: added API tests

 appliance/packagelist.in |   1 +
 configure.ac |   1 +
 daemon/Makefile.am   |   4 +-
 daemon/yara.c| 318 +++
 generator/actions.ml |  59 ++
 generator/structs.ml |   9 +
 gobject/Makefile.inc |   2 +
 java/Makefile.inc|   1 +
 java/com/redhat/et/libguestfs/.gitignore |   1 +
 m4/guestfs_daemon.m4 |   8 +
 src/MAX_PROC_NR  |   2 +-
 src/Makefile.am  |   1 +
 src/yara.c   | 140 ++
 tests/yara/Makefile.am   |  26 +++
 tests/yara/test-yara-scan.sh |  72 +++
 15 files changed, 643 insertions(+), 2 deletions(-)
 create mode 100644 daemon/yara.c
 create mode 100644 src/yara.c
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

--
2.10.1

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 3/6] New API: yara_destroy

2016-11-02 Thread Matteo Cafasso
The yara_destroy API allows to claim resources back via the removal of
the previously loaded Yara rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 14 ++
 generator/actions.ml |  9 +
 src/MAX_PROC_NR  |  2 +-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index 0d085a8..a6b9fe2 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -98,6 +98,20 @@ do_yara_load (void)
   return 0;
 }

+int
+do_yara_destroy (void)
+{
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  yr_rules_destroy (rules);
+  rules = NULL;
+
+  return 0;
+}
+
 /* Upload rules file on a temporary file.
  * Return 0 on success, -1 on error.
  */
diff --git a/generator/actions.ml b/generator/actions.ml
index 14659bd..966e012 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13268,6 +13268,15 @@ Rules in source code format cannot include external 
files. In such cases,
 it is recommended to compile them first.

 Previously loaded rules will be destroyed." };
+
+  { defaults with
+name = "yara_destroy"; added = (1, 35, 15);
+style = RErr, [], [];
+proc_nr = Some 472;
+optional = Some "libyara";
+shortdesc = "destroy previously loaded yara rules";
+longdesc = "\
+Destroy previously loaded Yara rules in order to free libguestfs resources." };
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index c305aa5..68cfb10 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-471
+472
--
2.10.1

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 6/6] yara_scan: added API tests

2016-11-02 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 configure.ac |  1 +
 tests/yara/Makefile.am   | 26 
 tests/yara/test-yara-scan.sh | 72 
 3 files changed, 99 insertions(+)
 create mode 100644 tests/yara/Makefile.am
 create mode 100755 tests/yara/test-yara-scan.sh

diff --git a/configure.ac b/configure.ac
index 45bb935..0681010 100644
--- a/configure.ac
+++ b/configure.ac
@@ -285,6 +285,7 @@ AC_CONFIG_FILES([Makefile
  tests/tsk/Makefile
  tests/xfs/Makefile
  tests/xml/Makefile
+ tests/yara/Makefile
  tools/Makefile
  utils/boot-analysis/Makefile
  utils/boot-benchmark/Makefile
diff --git a/tests/yara/Makefile.am b/tests/yara/Makefile.am
new file mode 100644
index 000..e23d94e
--- /dev/null
+++ b/tests/yara/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+   test-yara-scan.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+   $(TESTS)
diff --git a/tests/yara/test-yara-scan.sh b/tests/yara/test-yara-scan.sh
new file mode 100755
index 000..a899e33
--- /dev/null
+++ b/tests/yara/test-yara-scan.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the yara_scan command.
+
+set -e
+
+if [ -n "$SKIP_TEST_YARA_SCAN_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+rm -f test-yara-rules.yar
+
+# Skip if Yara is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libyara"; then
+echo "$0: skipped because Yara is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/blank-fs.img ]; then
+echo "$0: skipped because blank-fs.img is zero-sized"
+exit 77
+fi
+
+/bin/cat << EOF > test-yara-rules.yar
+rule TestRule
+{
+strings:
+\$my_text_string = "some text"
+
+condition:
+\$my_text_string
+}
+EOF
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/blank-fs.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 4/6] New API: internal_yara_scan

2016-11-02 Thread Matteo Cafasso
The internal_yara_scan runs the Yara engine with the previously loaded
rules against the given file.

For each rule matching against the scanned file, a struct containing
the file name and the rule identifier is returned.

The gathered list of yara_detection structs is serialised into XDR format
and written to a file.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/yara.c| 99 
 generator/actions.ml | 10 
 generator/structs.ml |  9 +++
 gobject/Makefile.inc |  2 +
 java/Makefile.inc|  1 +
 java/com/redhat/et/libguestfs/.gitignore |  1 +
 src/MAX_PROC_NR  |  2 +-
 7 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/daemon/yara.c b/daemon/yara.c
index a6b9fe2..099401c 100644
--- a/daemon/yara.c
+++ b/daemon/yara.c
@@ -49,6 +49,8 @@ static YR_RULES *rules = NULL;
 static int upload_rules_file (char *);
 static int compile_rules_file (const char *);
 static int write_callback (void *, const void *, size_t);
+static int yara_rules_callback (int , void *, void *);
+static int send_detection_info (const char *, YR_RULE *);

 /* Has one FileIn parameter. */
 int
@@ -112,6 +114,51 @@ do_yara_destroy (void)
   return 0;
 }

+/* Has one FileOut parameter. */
+int
+do_internal_yara_scan (const char *path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = 0;
+
+  if (rules == NULL) {
+reply_with_error ("no yara rules loaded");
+return -1;
+  }
+
+  ret = yr_initialize ();
+  if (ret != ERROR_SUCCESS) {
+reply_with_error ("failed initializing yara");
+return -1;
+  }
+
+  CHROOT_IN;
+  fd = open (path, O_RDONLY|O_CLOEXEC);
+  CHROOT_OUT;
+
+  if (fd < 0) {
+reply_with_perror ("%s", path);
+yr_finalize ();
+return -1;
+  }
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = yr_rules_scan_fd (rules, fd, 0, yara_rules_callback, (void *) path, 0);
+  if (ret == ERROR_SUCCESS)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  ret = yr_finalize ();
+  if (ret != ERROR_SUCCESS) {
+reply_with_error ("failed finalizing yara");
+return -1;
+  }
+
+  return 0;
+}
+
 /* Upload rules file on a temporary file.
  * Return 0 on success, -1 on error.
  */
@@ -206,6 +253,58 @@ write_callback (void *data_vp, const void *buf, size_t len)
   return 0;
 }

+/* Yara scan callback, called by yr_rules_scan_file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+yara_rules_callback (int code, void *message, void *data)
+{
+  int ret = 0;
+
+  if (code == CALLBACK_MSG_RULE_MATCHING)
+ret = send_detection_info ((const char *)data, (YR_RULE *) message);
+
+  return (ret == 0) ? CALLBACK_CONTINUE : CALLBACK_ERROR;
+}
+
+/* Serialize file path and rule name and send it out.
+ * Return 0 on success, -1 on error.
+ */
+static int
+send_detection_info (const char *name, YR_RULE *rule)
+{
+  XDR xdr;
+  int ret = 0;
+  size_t len = 0;
+  struct guestfs_int_yara_detection detection;
+  CLEANUP_FREE char *buf = NULL, *fname = NULL;
+
+  detection.name = (char *) name;
+  detection.rule = (char *) rule->identifier;
+
+  /* Serialize detection struct. */
+  buf = malloc (GUESTFS_MAX_CHUNK_SIZE);
+  if (buf == NULL) {
+perror ("malloc");
+return -1;
+  }
+
+  xdrmem_create (, buf, GUESTFS_MAX_CHUNK_SIZE, XDR_ENCODE);
+
+  ret = xdr_guestfs_int_yara_detection (, );
+  if (ret == 0) {
+perror ("xdr_guestfs_int_yara_detection");
+return -1;
+  }
+
+  len = xdr_getpos ();
+
+  xdr_destroy ();
+
+  /* Send serialised tsk_detection out. */
+  return send_file_write (buf, len);
+}
+
 int
 optgroup_libyara_available (void)
 {
diff --git a/generator/actions.ml b/generator/actions.ml
index 966e012..61211f4 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13277,6 +13277,16 @@ Previously loaded rules will be destroyed." };
 shortdesc = "destroy previously loaded yara rules";
 longdesc = "\
 Destroy previously loaded Yara rules in order to free libguestfs resources." };
+
+  { defaults with
+name = "internal_yara_scan"; added = (1, 35, 15);
+style = RErr, [Pathname "path"; FileOut "filename";], [];
+proc_nr = Some 473;
+visibility = VInternal;
+optional = Some "libyara";
+shortdesc = "scan a file with the loaded yara rules";
+longdesc = "Internal function for yara_scan." };
+
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/generator/structs.ml b/generator/structs.ml
index 029bc3a..3fa2ebc 100644
--- a/generator/structs.ml
+++ b/generator/structs.ml
@@ -468,6 +468,15 @@ let structs = [
 ];
 s_camel_name = "TSKDirent" };

+  (* Yara detection information. *)
+  { defaults with
+s_name = "ya

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

2016-11-02 Thread Matteo Cafasso
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 <noxda...@gmail.com>
---
 generator/actions.ml |  25 +
 src/Makefile.am  |   1 +
 src/yara.c   | 140 +++
 3 files changed, 166 insertions(+)
 create mode 100644 src/yara.c

diff --git a/generator/actions.ml b/generator/actions.ml
index 61211f4..59a75fc 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3729,6 +3729,31 @@ Searches all the entries associated with the given inode.
 For each entry, a C structure is returned.
 See C for more information about C structures." };

+  { defaults with
+name = "yara_scan"; added = (1, 35, 15);
+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 structure is returned.
+
+The C 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 000..0b924a2
--- /dev/null
+++ b/src/yara.c
@@ -0,0 +1,140 @@
+/* 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 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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 *);
+static char *make_temp_file (guestfs_h *, const char *);
+
+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 = make_temp_file (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 fil

[Libguestfs] [PATCH 2/6] New API: yara_load

2016-11-02 Thread Matteo Cafasso
The yara_load API allows to load a set of Yara rules contained within a
file on the host.

Rules can be in binary format, as when compiled with yarac command, or
in source code format. In the latter case, the rules will be first
compiled and then loaded.

Subsequent calls of the yara_load API will result in the discard of the
previously loaded rules.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/Makefile.am   |   1 +
 daemon/yara.c| 205 +++
 generator/actions.ml |  15 
 src/MAX_PROC_NR  |   2 +-
 4 files changed, 222 insertions(+), 1 deletion(-)
 create mode 100644 daemon/yara.c

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3a25f43..c385edc 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -200,6 +200,7 @@ guestfsd_SOURCES = \
wc.c \
xattr.c \
xfs.c \
+   yara.c \
zero.c \
zerofree.c

diff --git a/daemon/yara.c b/daemon/yara.c
new file mode 100644
index 000..0d085a8
--- /dev/null
+++ b/daemon/yara.c
@@ -0,0 +1,205 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2016 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 
USA.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+#include "guestfs_protocol.h"
+
+#ifdef HAVE_LIBYARA
+
+#include 
+
+struct write_callback_data {
+  int fd;
+  uint64_t written;
+};
+
+/* Yara compiled rules. */
+static YR_RULES *rules = NULL;
+
+static int upload_rules_file (char *);
+static int compile_rules_file (const char *);
+static int write_callback (void *, const void *, size_t);
+
+/* Has one FileIn parameter. */
+int
+do_yara_load (void)
+{
+  int ret = 0;
+  char tmpfile[] = "/tmp/yaraXX";
+
+  ret = upload_rules_file (tmpfile);
+  if (ret < 0)
+return -1;
+
+  ret = yr_initialize ();
+  if (ret != ERROR_SUCCESS) {
+reply_with_error ("failed initializing yara");
+unlink (tmpfile);
+return -1;
+  }
+
+  /* Destroy previously loaded rules. */
+  if (rules != NULL) {
+yr_rules_destroy (rules);
+rules = NULL;
+  }
+
+  /* Try to load the rules as compiled.
+   * If their are in source code format, compile them first.
+   */
+  ret = yr_rules_load (tmpfile, );
+  if (ret == ERROR_INVALID_FILE)
+ret = compile_rules_file (tmpfile);
+
+  unlink (tmpfile);
+
+  if (ret != ERROR_SUCCESS) {
+reply_with_error ("failed loading the rules");
+yr_finalize ();
+return -1;
+  }
+
+  ret = yr_finalize ();
+  if (ret != ERROR_SUCCESS) {
+reply_with_error ("failed finalizing yara");
+return -1;
+  }
+
+  return 0;
+}
+
+/* Upload rules file on a temporary file.
+ * Return 0 on success, -1 on error.
+ */
+static int
+upload_rules_file (char *rules_path)
+{
+  int ret = 0;
+  CLEANUP_CLOSE int fd = 0;
+  struct write_callback_data data = { .written = 0 };
+
+  data.fd = mkstemp (rules_path);
+  if (data.fd == -1) {
+reply_with_perror ("mkstemp");
+return -1;
+  }
+
+  ret = receive_file (write_callback, );
+  if (ret == -1) {
+/* Write error. */
+cancel_receive ();
+reply_with_error ("write error: %s", rules_path);
+return -1;
+  }
+  if (ret == -2) {
+/* Cancellation from library */
+reply_with_error ("file upload cancelled");
+return -1;
+  }
+
+  return 0;
+}
+
+/* Compile source code rules and load them.
+ * Return ERROR_SUCCESS on success, Yara error code type on error.
+ */
+static int
+compile_rules_file (const char *rules_path)
+{
+  int ret = 0;
+  FILE *rule_file = NULL;
+  YR_COMPILER *compiler = NULL;
+
+  ret = yr_compiler_create ();
+  if (ret != ERROR_SUCCESS) {
+perror ("yr_compiler_create");
+return ret;
+  }
+
+  rule_file = fopen (rules_path, "r");
+  if (rule_file == NULL) {
+yr_compiler_destroy (compiler);
+perror ("unable to open rules file");
+return ret;
+  }
+
+  ret = yr_compiler_add_file (compiler, rule_file, NULL, rules_path);
+  if (ret > 0) {
+yr_compiler_destroy (compiler);
+fclose (rule_file);
+perro

[Libguestfs] [PATCH 1/6] appliance: add libyara dependency

2016-11-02 Thread Matteo Cafasso
Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 appliance/packagelist.in | 1 +
 daemon/Makefile.am   | 3 ++-
 m4/guestfs_daemon.m4 | 8 
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/appliance/packagelist.in b/appliance/packagelist.in
index f278f66..5982df8 100644
--- a/appliance/packagelist.in
+++ b/appliance/packagelist.in
@@ -232,6 +232,7 @@ jfsutils
 kmod
 less
 libxml2
+libyara3
 lsof
 lsscsi
 lvm2
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 23f60eb..3a25f43 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -222,7 +222,8 @@ guestfsd_LDADD = \
$(LIBINTL) \
$(SERVENT_LIB) \
$(PCRE_LIBS) \
-   $(TSK_LIBS)
+   $(TSK_LIBS) \
+   $(YARA_LIBS)

 guestfsd_CPPFLAGS = \
-I$(top_srcdir)/gnulib/lib \
diff --git a/m4/guestfs_daemon.m4 b/m4/guestfs_daemon.m4
index 12123df..9dc7c6c 100644
--- a/m4/guestfs_daemon.m4
+++ b/m4/guestfs_daemon.m4
@@ -126,3 +126,11 @@ AC_CHECK_LIB([tsk],[tsk_version_print],[
 AC_DEFINE([HAVE_LIBTSK], [1], [Define to 1 if The Sleuth Kit library 
(libtsk) is available.])
 ], [])
 ],[AC_MSG_WARN([The Sleuth Kit library (libtsk) not found])])
+
+dnl yara library (optional)
+AC_CHECK_LIB([yara],[yr_initialize],[
+AC_CHECK_HEADER([yara.h],[
+AC_SUBST([YARA_LIBS], [-lyara])
+AC_DEFINE([HAVE_LIBYARA], [1], [Define to 1 if Yara library is 
available.])
+], [])
+],[AC_MSG_WARN([Yara library not found])])
--
2.10.1

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 0/3] New API - find_block

2016-10-08 Thread Matteo Cafasso
Patch ready for merging.

v4:

 - check return code of tsk_fs_attr_walk
 - pass TSK_FS_FILE_WALK_FLAG_NOSPARSE as additional flag to tsk_fs_attr_walk

After discussing with TSK authors the behaviour is clear. [1]

In case of COMPRESSED blocks, the callback will be called for all the 
attributes no matter whether they are on disk or not (sparse). In such cases, 
the block address will be 0. [2]

So we do not have to enforce the blocks to be RAW as we would be missing 
COMPRESSED ones (NTFS only).

[1] https://github.com/sleuthkit/sleuthkit/pull/721
[2] 
http://www.sleuthkit.org/sleuthkit/docs/api-docs/4.2/group__fslib.html#ga3ce8349107b00e1b1502c86a5d6c0727

Matteo Cafasso (3):
  New API: internal_find_block
  New API: find_block
  find_block: added API tests

 daemon/tsk.c | 96 
 generator/actions.ml | 25 
 src/MAX_PROC_NR  |  2 +-
 src/tsk.c| 17 
 tests/tsk/Makefile.am|  1 +
 tests/tsk/test-find-block.sh | 66 ++
 6 files changed, 206 insertions(+), 1 deletion(-)
 create mode 100755 tests/tsk/test-find-block.sh

--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 3/3] find_block: added API tests

2016-10-08 Thread Matteo Cafasso
NTFS file system always has the Boot file at block 0. This reliable
information helps testing the API.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 tests/tsk/Makefile.am|  1 +
 tests/tsk/test-find-block.sh | 66 
 2 files changed, 67 insertions(+)
 create mode 100755 tests/tsk/test-find-block.sh

diff --git a/tests/tsk/Makefile.am b/tests/tsk/Makefile.am
index 07c74f9..44a893e 100644
--- a/tests/tsk/Makefile.am
+++ b/tests/tsk/Makefile.am
@@ -21,6 +21,7 @@ TESTS = \
test-download-inode.sh \
test-download-blocks.sh \
test-filesystem-walk.sh \
+   test-find-block.sh \
test-find-inode.sh

 TESTS_ENVIRONMENT = $(top_builddir)/run --test
diff --git a/tests/tsk/test-find-block.sh b/tests/tsk/test-find-block.sh
new file mode 100755
index 000..984947d
--- /dev/null
+++ b/tests/tsk/test-find-block.sh
@@ -0,0 +1,66 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the find-block command.
+
+if [ -n "$SKIP_TEST_FIND_BLOCK_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+# Skip if TSK is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libtsk"; then
+echo "$0: skipped because TSK is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/windows.img ]; then
+echo "$0: skipped because windows.img is zero-sized"
+exit 77
+fi
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/windows.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v4 2/3] New API: find_block

2016-10-08 Thread Matteo Cafasso
Library's counterpart of the daemon's internal_find_block command.

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

It returns to the caller the list of tsk_dirent structs generated by the
internal_find_block command.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/actions.ml | 16 
 src/tsk.c| 17 +
 2 files changed, 33 insertions(+)

diff --git a/generator/actions.ml b/generator/actions.ml
index b38a30f..8947551 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3729,6 +3729,22 @@ Searches all the entries associated with the given inode.
 For each entry, a C structure is returned.
 See C for more information about C structures." };

+  { defaults with
+name = "find_block"; added = (1, 35, 6);
+style = RStructList ("dirents", "tsk_dirent"), [Mountable "device"; Int64 
"block";], [];
+optional = Some "libtsk";
+progress = true; cancellable = true;
+shortdesc = "search the entries referring to the given data block";
+longdesc = "\
+Searches all the entries referring to the given data block.
+
+Certain filesystems preserve the block mapping when deleting a file.
+Therefore, it is possible to see multiple deleted files referring
+to the same block.
+
+For each entry, a C structure is returned.
+See C for more information about C structures." };
+
 ]

 (* daemon_functions are any functions which cause some action
diff --git a/src/tsk.c b/src/tsk.c
index 1def9c9..7db6f71 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -72,6 +72,23 @@ guestfs_impl_find_inode (guestfs_h *g, const char 
*mountable, int64_t inode)
   return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

+struct guestfs_tsk_dirent_list *
+guestfs_impl_find_block (guestfs_h *g, const char *mountable, int64_t block)
+{
+  int ret = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = make_temp_file (g, "find_block");
+  if (tmpfile == NULL)
+return NULL;
+
+  ret = guestfs_internal_find_block (g, mountable, block, tmpfile);
+  if (ret < 0)
+return NULL;
+
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
+}
+
 /* Parse the file content and return dirents list.
  * Return a list of tsk_dirent on success, NULL on error.
  */
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 1/3] New API: internal_find_block

2016-09-20 Thread Matteo Cafasso
The internal_find_block command searches all entries referring to the
given filesystem data block and returns a tsk_dirent structure
for each of them.

For filesystems such as NTFS which do not delete the block mapping
when removing files, it is possible to get multiple non-allocated
entries for the same block.

The gathered list of tsk_dirent structs is serialised into XDR format
and written to a file by the appliance.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/tsk.c | 91 
 generator/actions.ml |  9 ++
 src/MAX_PROC_NR  |  2 +-
 3 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/daemon/tsk.c b/daemon/tsk.c
index af803d7..f971840 100644
--- a/daemon/tsk.c
+++ b/daemon/tsk.c
@@ -20,6 +20,7 @@

 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -42,9 +43,16 @@ enum tsk_dirent_flags {
   DIRENT_COMPRESSED = 0x04
 };

+typedef struct {
+  bool found;
+  uint64_t block;
+} findblk_data;
+
 static int open_filesystem (const char *, TSK_IMG_INFO **, TSK_FS_INFO **);
 static TSK_WALK_RET_ENUM fswalk_callback (TSK_FS_FILE *, const char *, void *);
 static TSK_WALK_RET_ENUM findino_callback (TSK_FS_FILE *, const char *, void 
*);
+static TSK_WALK_RET_ENUM findblk_callback (TSK_FS_FILE *, const char *, void 
*);
+static TSK_WALK_RET_ENUM attrwalk_callback (TSK_FS_FILE *, TSK_OFF_T , 
TSK_DADDR_T , char *, size_t , TSK_FS_BLOCK_FLAG_ENUM , void *);
 static int send_dirent_info (TSK_FS_FILE *, const char *);
 static char file_type (TSK_FS_FILE *);
 static int file_flags (TSK_FS_FILE *fsfile);
@@ -109,6 +117,35 @@ do_internal_find_inode (const mountable_t *mountable, 
int64_t inode)
   return ret;
 }

+int
+do_internal_find_block (const mountable_t *mountable, int64_t block)
+{
+  int ret = -1;
+  TSK_FS_INFO *fs = NULL;
+  TSK_IMG_INFO *img = NULL;  /* Used internally by tsk_fs_dir_walk */
+  const int flags =
+TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC |
+TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN;
+
+  ret = open_filesystem (mountable->device, , );
+  if (ret < 0)
+return ret;
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = tsk_fs_dir_walk (fs, fs->root_inum, flags,
+ findblk_callback, (void *) );
+  if (ret == 0)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  fs->close (fs);
+  img->close (img);
+
+  return ret;
+}
+
 /* Inspect the device and initialises the img and fs structures.
  * Return 0 on success, -1 on error.
  */
@@ -172,6 +209,60 @@ findino_callback (TSK_FS_FILE *fsfile, const char *path, 
void *data)
   return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR;
 }

+/* Find block, it gets called on every FS node.
+ *
+ * Return TSK_WALK_CONT on success, TSK_WALK_ERROR on error.
+ */
+static TSK_WALK_RET_ENUM
+findblk_callback (TSK_FS_FILE *fsfile, const char *path, void *data)
+{
+  findblk_data blkdata;
+  const TSK_FS_ATTR *fsattr = NULL;
+  int ret = 0, count = 0, index = 0;
+  const int flags = TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK;
+
+  if (entry_is_dot (fsfile))
+return TSK_WALK_CONT;
+
+  blkdata.found = false;
+  blkdata.block = * (uint64_t *) data;
+
+  /* Retrieve block list */
+  count = tsk_fs_file_attr_getsize (fsfile);
+
+  for (index = 0; index < count; index++) {
+fsattr = tsk_fs_file_attr_get_idx (fsfile, index);
+
+if (fsattr != NULL && fsattr->flags & TSK_FS_ATTR_NONRES)
+  tsk_fs_attr_walk (fsattr, flags, attrwalk_callback, (void *) );
+  }
+
+  if (blkdata.found)
+ret = send_dirent_info (fsfile, path);
+
+  return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR;
+}
+
+/* Attribute walk, searches the given block within the FS node attributes.
+ *
+ * Return TSK_WALK_CONT on success, TSK_WALK_ERROR on error.
+ */
+static TSK_WALK_RET_ENUM
+attrwalk_callback (TSK_FS_FILE *fsfile, TSK_OFF_T offset,
+   TSK_DADDR_T blkaddr, char *buf, size_t size,
+   TSK_FS_BLOCK_FLAG_ENUM flags, void *data)
+{
+  findblk_data *blkdata = (findblk_data *) data;
+
+  if (!(flags & TSK_FS_BLOCK_FLAG_SPARSE) && blkaddr == blkdata->block) {
+blkdata->found = true;
+
+return TSK_WALK_STOP;
+  }
+
+  return TSK_WALK_CONT;
+}
+
 /* Extract the information from the entry, serialize and send it out.
  * Return 0 on success, -1 on error.
  */
diff --git a/generator/actions.ml b/generator/actions.ml
index 91a1819..b38a30f 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13253,6 +13253,15 @@ is removed." };
 shortdesc = "search the entries associated to the given inode";
 longdesc = "Internal function for find_inode." };

+  { defaults with
+name = "internal_find_block"; added = (1, 35, 6);
+style = RErr, [Mountable "device"; Int64 "block&quo

[Libguestfs] [PATCH v3 2/3] New API: find_block

2016-09-20 Thread Matteo Cafasso
Library's counterpart of the daemon's internal_find_block command.

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

It returns to the caller the list of tsk_dirent structs generated by the
internal_find_block command.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/actions.ml | 16 
 src/tsk.c| 17 +
 2 files changed, 33 insertions(+)

diff --git a/generator/actions.ml b/generator/actions.ml
index b38a30f..8947551 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3729,6 +3729,22 @@ Searches all the entries associated with the given inode.
 For each entry, a C structure is returned.
 See C for more information about C structures." };

+  { defaults with
+name = "find_block"; added = (1, 35, 6);
+style = RStructList ("dirents", "tsk_dirent"), [Mountable "device"; Int64 
"block";], [];
+optional = Some "libtsk";
+progress = true; cancellable = true;
+shortdesc = "search the entries referring to the given data block";
+longdesc = "\
+Searches all the entries referring to the given data block.
+
+Certain filesystems preserve the block mapping when deleting a file.
+Therefore, it is possible to see multiple deleted files referring
+to the same block.
+
+For each entry, a C structure is returned.
+See C for more information about C structures." };
+
 ]

 (* daemon_functions are any functions which cause some action
diff --git a/src/tsk.c b/src/tsk.c
index 1def9c9..7db6f71 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -72,6 +72,23 @@ guestfs_impl_find_inode (guestfs_h *g, const char 
*mountable, int64_t inode)
   return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

+struct guestfs_tsk_dirent_list *
+guestfs_impl_find_block (guestfs_h *g, const char *mountable, int64_t block)
+{
+  int ret = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = make_temp_file (g, "find_block");
+  if (tmpfile == NULL)
+return NULL;
+
+  ret = guestfs_internal_find_block (g, mountable, block, tmpfile);
+  if (ret < 0)
+return NULL;
+
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
+}
+
 /* Parse the file content and return dirents list.
  * Return a list of tsk_dirent on success, NULL on error.
  */
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 0/3] New API - find_block

2016-09-20 Thread Matteo Cafasso
v3:

 - fixed attribute walk callback: checking against TSK_FS_BLOCK_FLAG_RAW flag 
would
   exclude compressed data blocks which are still important.
   Yet we want to exclude sparse blocks (TSK_FS_BLOCK_FLAG_SPARSE) as they are 
not stored
   on the disk.

Matteo Cafasso (3):
  New API: internal_find_block
  New API: find_block
  find_block: added API tests

 daemon/tsk.c | 91 
 generator/actions.ml | 25 
 src/MAX_PROC_NR  |  2 +-
 src/tsk.c| 17 +
 tests/tsk/Makefile.am|  1 +
 tests/tsk/test-find-block.sh | 66 
 6 files changed, 201 insertions(+), 1 deletion(-)
 create mode 100755 tests/tsk/test-find-block.sh

--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v3 3/3] find_block: added API tests

2016-09-20 Thread Matteo Cafasso
NTFS file system always has the Boot file at block 0. This reliable
information helps testing the API.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 tests/tsk/Makefile.am|  1 +
 tests/tsk/test-find-block.sh | 66 
 2 files changed, 67 insertions(+)
 create mode 100755 tests/tsk/test-find-block.sh

diff --git a/tests/tsk/Makefile.am b/tests/tsk/Makefile.am
index 07c74f9..44a893e 100644
--- a/tests/tsk/Makefile.am
+++ b/tests/tsk/Makefile.am
@@ -21,6 +21,7 @@ TESTS = \
test-download-inode.sh \
test-download-blocks.sh \
test-filesystem-walk.sh \
+   test-find-block.sh \
test-find-inode.sh

 TESTS_ENVIRONMENT = $(top_builddir)/run --test
diff --git a/tests/tsk/test-find-block.sh b/tests/tsk/test-find-block.sh
new file mode 100755
index 000..984947d
--- /dev/null
+++ b/tests/tsk/test-find-block.sh
@@ -0,0 +1,66 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the find-block command.
+
+if [ -n "$SKIP_TEST_FIND_BLOCK_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+# Skip if TSK is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libtsk"; then
+echo "$0: skipped because TSK is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/windows.img ]; then
+echo "$0: skipped because windows.img is zero-sized"
+exit 77
+fi
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/windows.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 3/3] find_block: added API tests

2016-09-19 Thread Matteo Cafasso
NTFS file system always has the Boot file at block 0. This reliable
information helps testing the API.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 tests/tsk/Makefile.am|  1 +
 tests/tsk/test-find-block.sh | 66 
 2 files changed, 67 insertions(+)
 create mode 100755 tests/tsk/test-find-block.sh

diff --git a/tests/tsk/Makefile.am b/tests/tsk/Makefile.am
index 07c74f9..44a893e 100644
--- a/tests/tsk/Makefile.am
+++ b/tests/tsk/Makefile.am
@@ -21,6 +21,7 @@ TESTS = \
test-download-inode.sh \
test-download-blocks.sh \
test-filesystem-walk.sh \
+   test-find-block.sh \
test-find-inode.sh

 TESTS_ENVIRONMENT = $(top_builddir)/run --test
diff --git a/tests/tsk/test-find-block.sh b/tests/tsk/test-find-block.sh
new file mode 100755
index 000..984947d
--- /dev/null
+++ b/tests/tsk/test-find-block.sh
@@ -0,0 +1,66 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the find-block command.
+
+if [ -n "$SKIP_TEST_FIND_BLOCK_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+# Skip if TSK is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libtsk"; then
+echo "$0: skipped because TSK is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/windows.img ]; then
+echo "$0: skipped because windows.img is zero-sized"
+exit 77
+fi
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/windows.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 1/3] New API: internal_find_block

2016-09-19 Thread Matteo Cafasso
The internal_find_block command searches all entries referring to the
given filesystem data block and returns a tsk_dirent structure
for each of them.

For filesystems such as NTFS which do not delete the block mapping
when removing files, it is possible to get multiple non-allocated
entries for the same block.

The gathered list of tsk_dirent structs is serialised into XDR format
and written to a file by the appliance.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/tsk.c | 90 
 generator/actions.ml |  9 ++
 src/MAX_PROC_NR  |  2 +-
 3 files changed, 100 insertions(+), 1 deletion(-)

diff --git a/daemon/tsk.c b/daemon/tsk.c
index af803d7..38d7c3f 100644
--- a/daemon/tsk.c
+++ b/daemon/tsk.c
@@ -20,6 +20,7 @@

 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -42,9 +43,16 @@ enum tsk_dirent_flags {
   DIRENT_COMPRESSED = 0x04
 };

+typedef struct {
+  bool found;
+  uint64_t block;
+} findblk_data;
+
 static int open_filesystem (const char *, TSK_IMG_INFO **, TSK_FS_INFO **);
 static TSK_WALK_RET_ENUM fswalk_callback (TSK_FS_FILE *, const char *, void *);
 static TSK_WALK_RET_ENUM findino_callback (TSK_FS_FILE *, const char *, void 
*);
+static TSK_WALK_RET_ENUM findblk_callback (TSK_FS_FILE *, const char *, void 
*);
+static TSK_WALK_RET_ENUM attrwalk_callback (TSK_FS_FILE *, TSK_OFF_T , 
TSK_DADDR_T , char *, size_t , TSK_FS_BLOCK_FLAG_ENUM , void *);
 static int send_dirent_info (TSK_FS_FILE *, const char *);
 static char file_type (TSK_FS_FILE *);
 static int file_flags (TSK_FS_FILE *fsfile);
@@ -109,6 +117,36 @@ do_internal_find_inode (const mountable_t *mountable, 
int64_t inode)
   return ret;
 }

+int
+do_internal_find_block (const mountable_t *mountable, int64_t block)
+{
+  int ret = -1;
+  TSK_FS_INFO *fs = NULL;
+  TSK_IMG_INFO *img = NULL;  /* Used internally by tsk_fs_dir_walk */
+  const int flags =
+TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC |
+TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN;
+
+  ret = open_filesystem (mountable->device, , );
+  if (ret < 0)
+return ret;
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = tsk_fs_dir_walk (fs, fs->root_inum, flags,
+ findblk_callback, (void *) );
+  if (ret == 0)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  fs->close (fs);
+  img->close (img);
+
+  return ret;
+}
+
+
 /* Inspect the device and initialises the img and fs structures.
  * Return 0 on success, -1 on error.
  */
@@ -172,6 +210,58 @@ findino_callback (TSK_FS_FILE *fsfile, const char *path, 
void *data)
   return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR;
 }

+/* Find block, it gets called on every FS node.
+ *
+ * Return TSK_WALK_CONT on success, TSK_WALK_ERROR on error.
+ */
+static TSK_WALK_RET_ENUM
+findblk_callback (TSK_FS_FILE *fsfile, const char *path, void *data)
+{
+  findblk_data blkdata;
+  const TSK_FS_ATTR *fsattr = NULL;
+  int ret = 0, count = 0, index = 0;
+  uint64_t *block = (uint64_t *) data;
+  const int flags = TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK;
+
+  if (entry_is_dot (fsfile))
+return TSK_WALK_CONT;
+
+  blkdata.found = false;
+  blkdata.block = *block;
+
+  /* Retrieve block list */
+  count = tsk_fs_file_attr_getsize (fsfile);
+
+  for (index = 0; index < count; index++) {
+fsattr = tsk_fs_file_attr_get_idx (fsfile, index);
+
+if (fsattr != NULL && fsattr->flags & TSK_FS_ATTR_NONRES)
+  tsk_fs_attr_walk (fsattr, flags, attrwalk_callback, (void*) );
+  }
+
+  if (blkdata.found)
+ret = send_dirent_info (fsfile, path);
+
+  return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR;
+}
+
+/* Attribute walk, searches the given block within the FS node attributes. */
+static TSK_WALK_RET_ENUM
+attrwalk_callback (TSK_FS_FILE *fsfile, TSK_OFF_T offset,
+   TSK_DADDR_T blkaddr, char *buf, size_t size,
+   TSK_FS_BLOCK_FLAG_ENUM flags, void *data)
+{
+  findblk_data *blkdata = (findblk_data *) data;
+
+  if (blkaddr == blkdata->block) {
+blkdata->found = true;
+
+return TSK_WALK_STOP;
+  }
+
+  return TSK_WALK_CONT;
+}
+
 /* Extract the information from the entry, serialize and send it out.
  * Return 0 on success, -1 on error.
  */
diff --git a/generator/actions.ml b/generator/actions.ml
index 91a1819..b38a30f 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13253,6 +13253,15 @@ is removed." };
 shortdesc = "search the entries associated to the given inode";
 longdesc = "Internal function for find_inode." };

+  { defaults with
+name = "internal_find_block"; added = (1, 35, 6);
+style = RErr, [Mountable "device"; Int64 "block"; FileOut "filename";], [];
+proc_nr = Some 471;
+visibility 

[Libguestfs] [PATCH v2 2/3] New API: find_block

2016-09-19 Thread Matteo Cafasso
Library's counterpart of the daemon's internal_find_block command.

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

It returns to the caller the list of tsk_dirent structs generated by the
internal_find_block command.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/actions.ml | 16 
 src/tsk.c| 17 +
 2 files changed, 33 insertions(+)

diff --git a/generator/actions.ml b/generator/actions.ml
index b38a30f..8947551 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3729,6 +3729,22 @@ Searches all the entries associated with the given inode.
 For each entry, a C structure is returned.
 See C for more information about C structures." };

+  { defaults with
+name = "find_block"; added = (1, 35, 6);
+style = RStructList ("dirents", "tsk_dirent"), [Mountable "device"; Int64 
"block";], [];
+optional = Some "libtsk";
+progress = true; cancellable = true;
+shortdesc = "search the entries referring to the given data block";
+longdesc = "\
+Searches all the entries referring to the given data block.
+
+Certain filesystems preserve the block mapping when deleting a file.
+Therefore, it is possible to see multiple deleted files referring
+to the same block.
+
+For each entry, a C structure is returned.
+See C for more information about C structures." };
+
 ]

 (* daemon_functions are any functions which cause some action
diff --git a/src/tsk.c b/src/tsk.c
index 1def9c9..7db6f71 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -72,6 +72,23 @@ guestfs_impl_find_inode (guestfs_h *g, const char 
*mountable, int64_t inode)
   return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

+struct guestfs_tsk_dirent_list *
+guestfs_impl_find_block (guestfs_h *g, const char *mountable, int64_t block)
+{
+  int ret = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = make_temp_file (g, "find_block");
+  if (tmpfile == NULL)
+return NULL;
+
+  ret = guestfs_internal_find_block (g, mountable, block, tmpfile);
+  if (ret < 0)
+return NULL;
+
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
+}
+
 /* Parse the file content and return dirents list.
  * Return a list of tsk_dirent on success, NULL on error.
  */
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v2 0/3] New API - find_block

2016-09-19 Thread Matteo Cafasso
v2:

- use boolean field in struct
- move refactoring to previous series

Matteo Cafasso (3):
  New API: internal_find_block
  New API: find_block
  find_block: added API tests

 daemon/tsk.c | 90 
 generator/actions.ml | 25 
 src/MAX_PROC_NR  |  2 +-
 src/tsk.c| 17 +
 tests/tsk/Makefile.am|  1 +
 tests/tsk/test-find-block.sh | 66 
 6 files changed, 200 insertions(+), 1 deletion(-)
 create mode 100755 tests/tsk/test-find-block.sh

--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 1/4] lib: logic refactoring

2016-09-19 Thread Matteo Cafasso
Code changes in preparation for new APIs.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 src/tsk.c | 39 +--
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/src/tsk.c b/src/tsk.c
index 90177ab..ecafcb7 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -34,44 +34,43 @@
 #include "guestfs-internal-all.h"
 #include "guestfs-internal-actions.h"

-static struct guestfs_tsk_dirent_list *parse_filesystem_walk (guestfs_h *, 
FILE *);
+static struct guestfs_tsk_dirent_list *parse_dirent_file (guestfs_h *, const 
char *);
 static int deserialise_dirent_list (guestfs_h *, FILE *, struct 
guestfs_tsk_dirent_list *);
+static char *make_temp_file (guestfs_h *, const char *);

 struct guestfs_tsk_dirent_list *
 guestfs_impl_filesystem_walk (guestfs_h *g, const char *mountable)
 {
   int ret = 0;
-  CLEANUP_FCLOSE FILE *fp = NULL;
   CLEANUP_UNLINK_FREE char *tmpfile = NULL;

-  ret = guestfs_int_lazy_make_tmpdir (g);
-  if (ret < 0)
+  tmpfile = make_temp_file (g, "filesystem_walk");
+  if (tmpfile == NULL)
 return NULL;

-  tmpfile = safe_asprintf (g, "%s/filesystem_walk%d", g->tmpdir, ++g->unique);
-
   ret = guestfs_internal_filesystem_walk (g, mountable, tmpfile);
   if (ret < 0)
 return NULL;

-  fp = fopen (tmpfile, "r");
-  if (fp == NULL) {
-perrorf (g, "fopen: %s", tmpfile);
-return NULL;
-  }
-
-  return parse_filesystem_walk (g, fp);  /* caller frees */
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

 /* Parse the file content and return dirents list.
  * Return a list of tsk_dirent on success, NULL on error.
  */
 static struct guestfs_tsk_dirent_list *
-parse_filesystem_walk (guestfs_h *g, FILE *fp)
+parse_dirent_file (guestfs_h *g, const char *tmpfile)
 {
   int ret = 0;
+  CLEANUP_FCLOSE FILE *fp = NULL;
   struct guestfs_tsk_dirent_list *dirents = NULL;

+  fp = fopen (tmpfile, "r");
+  if (fp == NULL) {
+perrorf (g, "fopen: %s", tmpfile);
+return NULL;
+  }
+
   /* Initialise results array. */
   dirents = safe_malloc (g, sizeof (*dirents));
   dirents->len = 8;
@@ -126,3 +125,15 @@ deserialise_dirent_list (guestfs_h *g, FILE *fp,

   return ret ? 0 : -1;
 }
+
+static char *
+make_temp_file (guestfs_h *g, const char *name)
+{
+  int ret = 0;
+
+  ret = guestfs_int_lazy_make_tmpdir (g);
+  if (ret < 0)
+return NULL;
+
+  return safe_asprintf (g, "%s/%s%d", g->tmpdir, name, ++g->unique);
+}
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 2/4] New API: internal_find_inode

2016-09-19 Thread Matteo Cafasso
The internal_find_inode command searches all entries referring to the
given inode and returns a tsk_dirent structure for each of them.

The command is able to retrieve information regarding deleted
or unaccessible files where other commands such as stat or find
would fail.

The gathered list of tsk_dirent structs is serialised into XDR format
and written to a file by the appliance.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 daemon/tsk.c | 52 
 generator/actions.ml |  9 +
 src/MAX_PROC_NR  |  2 +-
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/daemon/tsk.c b/daemon/tsk.c
index e5669da..af803d7 100644
--- a/daemon/tsk.c
+++ b/daemon/tsk.c
@@ -44,6 +44,7 @@ enum tsk_dirent_flags {

 static int open_filesystem (const char *, TSK_IMG_INFO **, TSK_FS_INFO **);
 static TSK_WALK_RET_ENUM fswalk_callback (TSK_FS_FILE *, const char *, void *);
+static TSK_WALK_RET_ENUM findino_callback (TSK_FS_FILE *, const char *, void 
*);
 static int send_dirent_info (TSK_FS_FILE *, const char *);
 static char file_type (TSK_FS_FILE *);
 static int file_flags (TSK_FS_FILE *fsfile);
@@ -79,6 +80,35 @@ do_internal_filesystem_walk (const mountable_t *mountable)
   return ret;
 }

+int
+do_internal_find_inode (const mountable_t *mountable, int64_t inode)
+{
+  int ret = -1;
+  TSK_FS_INFO *fs = NULL;
+  TSK_IMG_INFO *img = NULL;  /* Used internally by tsk_fs_dir_walk */
+  const int flags =
+TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC |
+TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN;
+
+  ret = open_filesystem (mountable->device, , );
+  if (ret < 0)
+return ret;
+
+  reply (NULL, NULL);  /* Reply message. */
+
+  ret = tsk_fs_dir_walk (fs, fs->root_inum, flags,
+ findino_callback, (void *) );
+  if (ret == 0)
+ret = send_file_end (0);  /* File transfer end. */
+  else
+send_file_end (1);  /* Cancel file transfer. */
+
+  fs->close (fs);
+  img->close (img);
+
+  return ret;
+}
+
 /* Inspect the device and initialises the img and fs structures.
  * Return 0 on success, -1 on error.
  */
@@ -120,6 +150,28 @@ fswalk_callback (TSK_FS_FILE *fsfile, const char *path, 
void *data)
   return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR;
 }

+/* Find inode, it gets called on every FS node.
+ * If the FS node address is the given one, parse it,
+ * encode it into an XDR structure and send it to the library.
+ * Return TSK_WALK_CONT on success, TSK_WALK_ERROR on error.
+ */
+static TSK_WALK_RET_ENUM
+findino_callback (TSK_FS_FILE *fsfile, const char *path, void *data)
+{
+  int ret = 0;
+  uint64_t *inode = (uint64_t *) data;
+
+  if (*inode != fsfile->name->meta_addr)
+return TSK_WALK_CONT;
+
+  if (entry_is_dot (fsfile))
+return TSK_WALK_CONT;
+
+  ret = send_dirent_info (fsfile, path);
+
+  return (ret == 0) ? TSK_WALK_CONT : TSK_WALK_ERROR;
+}
+
 /* Extract the information from the entry, serialize and send it out.
  * Return 0 on success, -1 on error.
  */
diff --git a/generator/actions.ml b/generator/actions.ml
index 68ecee3..4e6627b 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -13232,6 +13232,15 @@ handle C.
 If C is true (C by default), then the transformation
 is removed." };

+  { defaults with
+name = "internal_find_inode"; added = (1, 35, 6);
+style = RErr, [Mountable "device"; Int64 "inode"; FileOut "filename";], [];
+proc_nr = Some 470;
+visibility = VInternal;
+optional = Some "libtsk";
+shortdesc = "search the entries associated to the given inode";
+longdesc = "Internal function for find_inode." };
+
 ]

 (* Non-API meta-commands available only in guestfish.
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 5ef9d24..5f476b6 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-469
+470
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 4/4] find_inode: added API tests

2016-09-19 Thread Matteo Cafasso
NTFS file system always has the MFT file at inode 0. This reliable
information helps testing the API.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 tests/tsk/Makefile.am|  3 +-
 tests/tsk/test-find-inode.sh | 66 
 2 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100755 tests/tsk/test-find-inode.sh

diff --git a/tests/tsk/Makefile.am b/tests/tsk/Makefile.am
index 0b50839..07c74f9 100644
--- a/tests/tsk/Makefile.am
+++ b/tests/tsk/Makefile.am
@@ -20,7 +20,8 @@ include $(top_srcdir)/subdir-rules.mk
 TESTS = \
test-download-inode.sh \
test-download-blocks.sh \
-   test-filesystem-walk.sh
+   test-filesystem-walk.sh \
+   test-find-inode.sh

 TESTS_ENVIRONMENT = $(top_builddir)/run --test

diff --git a/tests/tsk/test-find-inode.sh b/tests/tsk/test-find-inode.sh
new file mode 100755
index 000..f69fcf6
--- /dev/null
+++ b/tests/tsk/test-find-inode.sh
@@ -0,0 +1,66 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2016 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the find-inode command.
+
+if [ -n "$SKIP_TEST_FIND_INODE_SH" ]; then
+echo "$0: test skipped because environment variable is set."
+exit 77
+fi
+
+# Skip if TSK is not supported by the appliance.
+if ! guestfish add /dev/null : run : available "libtsk"; then
+echo "$0: skipped because TSK is not available in the appliance"
+exit 77
+fi
+
+if [ ! -s ../../test-data/phony-guests/windows.img ]; then
+echo "$0: skipped because windows.img is zero-sized"
+exit 77
+fi
+
+output=$(
+guestfish --ro -a ../../test-data/phony-guests/windows.img <https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 3/4] New API: find_inode

2016-09-19 Thread Matteo Cafasso
Library's counterpart of the daemon's internal_find_inode command.

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

It returns to the caller the list of tsk_dirent structs generated by the
internal_find_inode command.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 generator/actions.ml | 12 
 src/tsk.c| 17 +
 2 files changed, 29 insertions(+)

diff --git a/generator/actions.ml b/generator/actions.ml
index 4e6627b..91a1819 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3717,6 +3717,18 @@ Unknown file type

 =back" };

+  { defaults with
+name = "find_inode"; added = (1, 35, 6);
+style = RStructList ("dirents", "tsk_dirent"), [Mountable "device"; Int64 
"inode";], [];
+optional = Some "libtsk";
+progress = true; cancellable = true;
+shortdesc = "search the entries associated to the given inode";
+longdesc = "\
+Searches all the entries associated with the given inode.
+
+For each entry, a C structure is returned.
+See C for more information about C structures." };
+
 ]

 (* daemon_functions are any functions which cause some action
diff --git a/src/tsk.c b/src/tsk.c
index ecafcb7..1def9c9 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -55,6 +55,23 @@ guestfs_impl_filesystem_walk (guestfs_h *g, const char 
*mountable)
   return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

+struct guestfs_tsk_dirent_list *
+guestfs_impl_find_inode (guestfs_h *g, const char *mountable, int64_t inode)
+{
+  int ret = 0;
+  CLEANUP_UNLINK_FREE char *tmpfile = NULL;
+
+  tmpfile = make_temp_file (g, "find_inode");
+  if (tmpfile == NULL)
+return NULL;
+
+  ret = guestfs_internal_find_inode (g, mountable, inode, tmpfile);
+  if (ret < 0)
+return NULL;
+
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
+}
+
 /* Parse the file content and return dirents list.
  * Return a list of tsk_dirent on success, NULL on error.
  */
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH v7 0/4] New API - find_inode

2016-09-19 Thread Matteo Cafasso
 v7:

- Merge src/tsk.c refactoring patch with #4 of find_block series

Matteo Cafasso (4):
  lib: logic refactoring
  New API: internal_find_inode
  New API: find_inode
  find_inode: added API tests

 daemon/tsk.c | 52 ++
 generator/actions.ml | 21 ++
 src/MAX_PROC_NR  |  2 +-
 src/tsk.c| 52 ++
 tests/tsk/Makefile.am|  3 +-
 tests/tsk/test-find-inode.sh | 66 
 6 files changed, 182 insertions(+), 14 deletions(-)
 create mode 100755 tests/tsk/test-find-inode.sh

--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


[Libguestfs] [PATCH 4/4] TSK: small refactoring

2016-09-17 Thread Matteo Cafasso
Removed duplicated code.

Signed-off-by: Matteo Cafasso <noxda...@gmail.com>
---
 src/tsk.c | 69 ++-
 1 file changed, 28 insertions(+), 41 deletions(-)

diff --git a/src/tsk.c b/src/tsk.c
index 6b1b29c..8e6d266 100644
--- a/src/tsk.c
+++ b/src/tsk.c
@@ -34,96 +34,71 @@
 #include "guestfs-internal-all.h"
 #include "guestfs-internal-actions.h"

-static struct guestfs_tsk_dirent_list *parse_dirent_file (guestfs_h *, FILE *);
+static struct guestfs_tsk_dirent_list *parse_dirent_file (guestfs_h *, const 
char *);
 static int deserialise_dirent_list (guestfs_h *, FILE *, struct 
guestfs_tsk_dirent_list *);
+static char *make_temp_file (guestfs_h *, const char *);

 struct guestfs_tsk_dirent_list *
 guestfs_impl_filesystem_walk (guestfs_h *g, const char *mountable)
 {
   int ret = 0;
-  CLEANUP_FCLOSE FILE *fp = NULL;
   CLEANUP_UNLINK_FREE char *tmpfile = NULL;

-  ret = guestfs_int_lazy_make_tmpdir (g);
-  if (ret < 0)
-return NULL;
-
-  tmpfile = safe_asprintf (g, "%s/filesystem_walk%d", g->tmpdir, ++g->unique);
+  tmpfile = make_temp_file (g, "filesystem_walk");

   ret = guestfs_internal_filesystem_walk (g, mountable, tmpfile);
   if (ret < 0)
 return NULL;

-  fp = fopen (tmpfile, "r");
-  if (fp == NULL) {
-perrorf (g, "fopen: %s", tmpfile);
-return NULL;
-  }
-
-  return parse_dirent_file (g, fp);  /* caller frees */
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

 struct guestfs_tsk_dirent_list *
 guestfs_impl_find_inode (guestfs_h *g, const char *mountable, int64_t inode)
 {
   int ret = 0;
-  CLEANUP_FCLOSE FILE *fp = NULL;
   CLEANUP_UNLINK_FREE char *tmpfile = NULL;

-  ret = guestfs_int_lazy_make_tmpdir (g);
-  if (ret < 0)
-return NULL;
-
-  tmpfile = safe_asprintf (g, "%s/find_inode%d", g->tmpdir, ++g->unique);
+  tmpfile = make_temp_file (g, "find_inode");

   ret = guestfs_internal_find_inode (g, mountable, inode, tmpfile);
   if (ret < 0)
 return NULL;

-  fp = fopen (tmpfile, "r");
-  if (fp == NULL) {
-perrorf (g, "fopen: %s", tmpfile);
-return NULL;
-  }
-
-  return parse_dirent_file (g, fp);  /* caller frees */
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

 struct guestfs_tsk_dirent_list *
 guestfs_impl_find_block (guestfs_h *g, const char *mountable, int64_t block)
 {
   int ret = 0;
-  CLEANUP_FCLOSE FILE *fp = NULL;
   CLEANUP_UNLINK_FREE char *tmpfile = NULL;

-  ret = guestfs_int_lazy_make_tmpdir (g);
-  if (ret < 0)
-return NULL;
-
-  tmpfile = safe_asprintf (g, "%s/find_block%d", g->tmpdir, ++g->unique);
+  tmpfile = make_temp_file (g, "find_block");

   ret = guestfs_internal_find_block (g, mountable, block, tmpfile);
   if (ret < 0)
 return NULL;

-  fp = fopen (tmpfile, "r");
-  if (fp == NULL) {
-perrorf (g, "fopen: %s", tmpfile);
-return NULL;
-  }
-
-  return parse_dirent_file (g, fp);  /* caller frees */
+  return parse_dirent_file (g, tmpfile);  /* caller frees */
 }

 /* Parse the file content and return dirents list.
  * Return a list of tsk_dirent on success, NULL on error.
  */
 static struct guestfs_tsk_dirent_list *
-parse_dirent_file (guestfs_h *g, FILE *fp)
+parse_dirent_file (guestfs_h *g, const char *tmpfile)
 {
   int ret = 0;
+  CLEANUP_FCLOSE FILE *fp = NULL;
   struct guestfs_tsk_dirent_list *dirents = NULL;

+  fp = fopen (tmpfile, "r");
+  if (fp == NULL) {
+perrorf (g, "fopen: %s", tmpfile);
+return NULL;
+  }
+
   /* Initialise results array. */
   dirents = safe_malloc (g, sizeof (*dirents));
   dirents->len = 8;
@@ -178,3 +153,15 @@ deserialise_dirent_list (guestfs_h *g, FILE *fp,

   return ret ? 0 : -1;
 }
+
+static char *
+make_temp_file (guestfs_h *g, const char *name)
+{
+  int ret = 0;
+
+  ret = guestfs_int_lazy_make_tmpdir (g);
+  if (ret < 0)
+return NULL;
+
+  return safe_asprintf (g, "%s/%s%d", g->tmpdir, name, ++g->unique);
+}
--
2.9.3

___
Libguestfs mailing list
Libguestfs@redhat.com
https://www.redhat.com/mailman/listinfo/libguestfs


  1   2   3   >