lib audit_logging: re-factor and add functions.
authorGary Lockyer <gary@catalyst.net.nz>
Wed, 16 May 2018 20:03:00 +0000 (08:03 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 1 Jun 2018 06:28:26 +0000 (08:28 +0200)
Re-factor the common calls to json_dumps DEBUGC and audit_message_send
into a separate function.
Add functions to retrieve json object and json array elements

Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
auth/auth_log.c
lib/audit_logging/audit_logging.c
lib/audit_logging/audit_logging.h
lib/audit_logging/tests/audit_logging_test.c

index 87daf2f110ff27597bc0920917ccff3b19fc5a5f..369a5c96162f593d5406edc6d458e19fa39125ff 100644 (file)
@@ -82,31 +82,13 @@ static void log_json(struct imessaging_context *msg_ctx,
                     int debug_class,
                     int debug_level)
 {
-       char* json = NULL;
-
-       if (object->error) {
-               return;
-       }
-
-       json = json_dumps(object->root, 0);
-       if (json == NULL) {
-               DBG_ERR("Unable to convert JSON object to string\n");
-               object->error = true;
-               return;
-       }
-
-       DEBUGC(debug_class, debug_level, ("JSON %s: %s\n", type, json));
+       audit_log_json(type, object, debug_class, debug_level);
        if (msg_ctx && lp_ctx && lpcfg_auth_event_notification(lp_ctx)) {
                audit_message_send(msg_ctx,
                                   AUTH_EVENT_NAME,
                                   MSG_AUTH_LOG,
-                                  json);
-       }
-
-       if (json) {
-               free(json);
+                                  object);
        }
-
 }
 
 /*
index 5c16806d54ebc835908313b54b5632ce4be64f1b..1f82d576c849ddf2d6d0bfa6c247ff154f18b04f 100644 (file)
@@ -102,9 +102,46 @@ char* audit_get_timestamp(TALLOC_CTX *frame)
        return ts;
 }
 
-#ifdef HAVE_JANSSON
+/*
+ * @brief write an audit message to the audit logs.
+ *
+ * Write a human readable text audit message to the samba logs.
+ *
+ * @param prefix Text to be printed at the start of the log line
+ * @param message The content of the log line.
+ * @param debub_class The debug class to log the message with.
+ * @param debug_level The debug level to log the message with.
+ */
+void audit_log_human_text(const char* prefix,
+                         const char* message,
+                         int debug_class,
+                         int debug_level)
+{
+       DEBUGC(debug_class, debug_level, ("%s %s\n", prefix, message));
+}
 
-#include "system/time.h"
+#ifdef HAVE_JANSSON
+/*
+ * @brief write a json object to the samba audit logs.
+ *
+ * Write the json object to the audit logs as a formatted string
+ *
+ * @param prefix Text to be printed at the start of the log line
+ * @param message The content of the log line.
+ * @param debub_class The debug class to log the message with.
+ * @param debug_level The debug level to log the message with.
+ */
+void audit_log_json(
+       const char* prefix,
+       struct json_object* message,
+       int debug_class,
+       int debug_level)
+{
+       TALLOC_CTX *ctx = talloc_new(NULL);
+       char *s = json_to_string(ctx, message);
+       DEBUGC(debug_class, debug_level, ("JSON %s: %s\n", prefix, s));
+       TALLOC_FREE(ctx);
+}
 
 /*
  * @brief get a connection to the messaging event server.
@@ -192,14 +229,18 @@ void audit_message_send(
        struct imessaging_context *msg_ctx,
        const char *server_name,
        uint32_t message_type,
-       const char *message)
+       struct json_object *message)
 {
        struct server_id event_server;
        NTSTATUS status;
-       DATA_BLOB message_blob = data_blob_string_const(message);
+
+       const char *message_string = NULL;
+       DATA_BLOB message_blob = data_blob_null;
+       TALLOC_CTX *ctx = talloc_new(NULL);
 
        if (msg_ctx == NULL) {
                DBG_DEBUG("No messaging context\n");
+               TALLOC_FREE(ctx);
                return;
        }
 
@@ -213,9 +254,12 @@ void audit_message_send(
                DBG_ERR("get_event_server for %s returned (%s)\n",
                        server_name,
                        nt_errstr(status));
+               TALLOC_FREE(ctx);
                return;
        }
 
+       message_string = json_to_string(ctx, message);
+       message_blob = data_blob_string_const(message_string);
        status = imessaging_send(
                msg_ctx,
                event_server,
@@ -232,6 +276,7 @@ void audit_message_send(
                        DBG_ERR("get_event_server for %s returned (%s)\n",
                                server_name,
                                nt_errstr(status));
+                       TALLOC_FREE(ctx);
                        return;
                }
                imessaging_send(
@@ -240,6 +285,7 @@ void audit_message_send(
                        message_type,
                        &message_blob);
        }
+       TALLOC_FREE(ctx);
 }
 
 /*
@@ -768,4 +814,64 @@ char *json_to_string(TALLOC_CTX *mem_ctx, struct json_object *object)
 
        return json_string;
 }
+
+/*
+ * @brief get a json array named "name" from the json object.
+ *
+ * Get the array attribute named name, creating it if it does not exist.
+ *
+ * @param object the json object.
+ * @param name the name of the array attribute
+ *
+ * @return The array object, will be created if it did not exist.
+ */
+struct json_object json_get_array(struct json_object *object, const char* name)
+{
+
+       struct json_object array = json_new_array();
+       json_t *a = NULL;
+
+       if (object->error) {
+               array.error = true;
+               return array;
+       }
+
+       a = json_object_get(object->root, name);
+       if (a == NULL) {
+               return array;
+       }
+       json_array_extend(array.root, a);
+
+       return array;
+}
+
+/*
+ * @brief get a json object named "name" from the json object.
+ *
+ * Get the object attribute named name, creating it if it does not exist.
+ *
+ * @param object the json object.
+ * @param name the name of the object attribute
+ *
+ * @return The object, will be created if it did not exist.
+ */
+struct json_object json_get_object(struct json_object *object, const char* name)
+{
+
+       struct json_object o = json_new_object();
+       json_t *v = NULL;
+
+       if (object->error) {
+               o.error = true;
+               return o;
+       }
+
+       v = json_object_get(object->root, name);
+       if (v == NULL) {
+               return o;
+       }
+       json_object_update(o.root, v);
+
+       return o;
+}
 #endif
index 763f3ed5d9ccbc1e522790615f41fcd5771e0e7c..152b22ee9167891da02882b590c62c3e138757cc 100644 (file)
 #include "lib/messaging/irpc.h"
 #include "lib/tsocket/tsocket.h"
 
-char* audit_get_timestamp(
-       TALLOC_CTX *frame);
+char* audit_get_timestamp(TALLOC_CTX *frame);
+void audit_log_human_text(const char *prefix,
+                         const char *message,
+                         int debug_class,
+                         int debug_level);
 
-void audit_message_send(
-       struct imessaging_context *msg_ctx,
-       const char *server_name,
-       uint32_t message_type,
-       const char *message);
 #ifdef HAVE_JANSSON
 #include <jansson.h>
 /*
@@ -40,6 +38,14 @@ struct json_object {
        bool error;
 };
 
+void audit_log_json(const char *prefix,
+                   struct json_object *message,
+                   int debug_class,
+                   int debug_level);
+void audit_message_send(struct imessaging_context *msg_ctx,
+                       const char *server_name,
+                       uint32_t message_type,
+                       struct json_object *message);
 struct json_object json_new_object(void);
 struct json_object json_new_array(void);
 void json_free(struct json_object *object);
@@ -85,5 +91,9 @@ void json_add_guid(
        const char *name,
        const struct GUID *guid);
 
+struct json_object json_get_array(struct json_object *object,
+                                 const char* name);
+struct json_object json_get_object(struct json_object *object,
+                                  const char* name);
 char *json_to_string(TALLOC_CTX *mem_ctx, struct json_object *object);
 #endif
index 8385e9ce3637bebc324a1b66535c3a6bd2bb1611..56e8fbcd43ed926dbbdb6522cc453401d6f42369 100644 (file)
@@ -492,6 +492,141 @@ static void test_json_to_string(void **state)
 }
 #endif
 
+static void test_json_get_array(void **state)
+{
+       struct json_object object;
+       struct json_object array;
+       struct json_object stored_array = json_new_array();
+       json_t *value = NULL;
+       json_t *o = NULL;
+       struct json_object o1;
+       struct json_object o2;
+
+       object = json_new_object();
+
+       array = json_get_array(&object, "not-there");
+       assert_false(array.error);
+       assert_non_null(array.root);
+       assert_true(json_is_array(array.root));
+       json_free(&array);
+
+       o1 = json_new_object();
+       json_add_string(&o1, "value", "value-one");
+       json_add_object(&stored_array, NULL, &o1);
+       json_add_object(&object, "stored_array", &stored_array);
+
+       array = json_get_array(&object, "stored_array");
+       assert_false(array.error);
+       assert_non_null(array.root);
+       assert_true(json_is_array(array.root));
+
+       assert_int_equal(1, json_array_size(array.root));
+
+       o = json_array_get(array.root, 0);
+       assert_non_null(o);
+       assert_true(json_is_object(o));
+
+       value = json_object_get(o, "value");
+       assert_non_null(value);
+       assert_true(json_is_string(value));
+
+       assert_string_equal("value-one", json_string_value(value));
+       json_free(&array);
+
+       /*
+        * Now update the array and add it back to the object
+        */
+       array = json_get_array(&object, "stored_array");
+       assert_true(json_is_array(array.root));
+       o2 = json_new_object();
+       json_add_string(&o2, "value", "value-two");
+       assert_false(o2.error);
+       json_add_object(&array, NULL, &o2);
+       assert_true(json_is_array(array.root));
+       json_add_object(&object, "stored_array", &array);
+       assert_true(json_is_array(array.root));
+
+       array = json_get_array(&object, "stored_array");
+       assert_non_null(array.root);
+       assert_true(json_is_array(array.root));
+       assert_false(array.error);
+       assert_true(json_is_array(array.root));
+
+       assert_int_equal(2, json_array_size(array.root));
+
+       o = json_array_get(array.root, 0);
+       assert_non_null(o);
+       assert_true(json_is_object(o));
+
+       assert_non_null(value);
+       assert_true(json_is_string(value));
+
+       assert_string_equal("value-one", json_string_value(value));
+
+       o = json_array_get(array.root, 1);
+       assert_non_null(o);
+       assert_true(json_is_object(o));
+
+       value = json_object_get(o, "value");
+       assert_non_null(value);
+       assert_true(json_is_string(value));
+
+       assert_string_equal("value-two", json_string_value(value));
+
+       json_free(&array);
+       json_free(&object);
+}
+
+static void test_json_get_object(void **state)
+{
+       struct json_object object;
+       struct json_object o1;
+       struct json_object o2;
+       struct json_object o3;
+       json_t *value = NULL;
+
+       object = json_new_object();
+
+       o1 = json_get_object(&object, "not-there");
+       assert_false(o1.error);
+       assert_non_null(o1.root);
+       assert_true(json_is_object(o1.root));
+       json_free(&o1);
+
+       o1 = json_new_object();
+       json_add_string(&o1, "value", "value-one");
+       json_add_object(&object, "stored_object", &o1);
+
+       o2 = json_get_object(&object, "stored_object");
+       assert_false(o2.error);
+       assert_non_null(o2.root);
+       assert_true(json_is_object(o2.root));
+
+       value = json_object_get(o2.root, "value");
+       assert_non_null(value);
+       assert_true(json_is_string(value));
+
+       assert_string_equal("value-one", json_string_value(value));
+
+       json_add_string(&o2, "value", "value-two");
+       json_add_object(&object, "stored_object", &o2);
+
+
+       o3 = json_get_object(&object, "stored_object");
+       assert_false(o3.error);
+       assert_non_null(o3.root);
+       assert_true(json_is_object(o3.root));
+
+       value = json_object_get(o3.root, "value");
+       assert_non_null(value);
+       assert_true(json_is_string(value));
+
+       assert_string_equal("value-two", json_string_value(value));
+
+       json_free(&o3);
+       json_free(&object);
+}
+
 static void test_audit_get_timestamp(void **state)
 {
        const char *t = NULL;
@@ -549,6 +684,8 @@ int main(int argc, const char **argv)
                cmocka_unit_test(test_json_add_sid),
                cmocka_unit_test(test_json_add_guid),
                cmocka_unit_test(test_json_to_string),
+               cmocka_unit_test(test_json_get_array),
+               cmocka_unit_test(test_json_get_object),
 #endif
                cmocka_unit_test(test_audit_get_timestamp),
        };