auth_log: Add JSON logging of Authorisation and Authentications
[sfrench/samba-autobuild/.git] / lib / util / debug.c
index ed899448f3152dd856433cbf9658452a6b656a9e..f48daf69553acc4a7266b8f698f618816eaf3e15 100644 (file)
@@ -27,7 +27,8 @@
 #include "time_basic.h"
 #include "close_low_fd.h"
 #include "memory.h"
-#include "samba_util.h" /* LIST_SEP */
+#include "util_strlist.h" /* LIST_SEP */
+#include "blocking.h"
 #include "debug.h"
 
 /* define what facility to use for syslog */
@@ -149,7 +150,7 @@ static void debug_file_log(int msg_level,
 
 #ifdef WITH_SYSLOG
 static void debug_syslog_reload(bool enabled, bool previously_enabled,
-                               const char *prog_name)
+                               const char *prog_name, char *option)
 {
        if (enabled && !previously_enabled) {
 #ifdef LOG_DAEMON
@@ -207,7 +208,7 @@ static void debug_lttng_log(int msg_level,
 #ifdef HAVE_GPFS
 #include "gpfswrap.h"
 static void debug_gpfs_reload(bool enabled, bool previously_enabled,
-                             const char *prog_name)
+                             const char *prog_name, char *option)
 {
        gpfswrap_init();
 
@@ -236,12 +237,92 @@ static void debug_gpfs_log(int msg_level,
 }
 #endif /* HAVE_GPFS */
 
+#define DEBUG_RINGBUF_SIZE (1024 * 1024)
+#define DEBUG_RINGBUF_SIZE_OPT "size="
+
+static char *debug_ringbuf;
+static size_t debug_ringbuf_size;
+static size_t debug_ringbuf_ofs;
+
+/* We ensure in debug_ringbuf_log() that this is always \0 terminated */
+char *debug_get_ringbuf(void)
+{
+       return debug_ringbuf;
+}
+
+/* Return the size of the ringbuf (including a \0 terminator) */
+size_t debug_get_ringbuf_size(void)
+{
+       return debug_ringbuf_size;
+}
+
+static void debug_ringbuf_reload(bool enabled, bool previously_enabled,
+                                const char *prog_name, char *option)
+{
+       bool cmp;
+       size_t optlen = strlen(DEBUG_RINGBUF_SIZE_OPT);
+
+       debug_ringbuf_size = DEBUG_RINGBUF_SIZE;
+       debug_ringbuf_ofs = 0;
+
+       SAFE_FREE(debug_ringbuf);
+
+       if (!enabled) {
+               return;
+       }
+
+       if (option != NULL) {
+               cmp = strncmp(option, DEBUG_RINGBUF_SIZE_OPT, optlen);
+               if (cmp == 0) {
+                       debug_ringbuf_size = (size_t)strtoull(
+                               option + optlen, NULL, 10);
+               }
+       }
+
+       debug_ringbuf = calloc(debug_ringbuf_size, sizeof(char));
+       if (debug_ringbuf == NULL) {
+               return;
+       }
+}
+
+static void debug_ringbuf_log(int msg_level,
+                             const char *msg,
+                             const char *msg_no_nl)
+{
+       size_t msglen = strlen(msg);
+       size_t allowed_size;
+
+       if (debug_ringbuf == NULL) {
+               return;
+       }
+
+       /* Ensure the buffer is always \0 terminated */
+       allowed_size = debug_ringbuf_size - 1;
+
+       if (msglen > allowed_size) {
+               return;
+       }
+
+       if ((debug_ringbuf_ofs + msglen) < debug_ringbuf_ofs) {
+               return;
+       }
+
+       if ((debug_ringbuf_ofs + msglen) > allowed_size) {
+               debug_ringbuf_ofs = 0;
+       }
+
+       memcpy(debug_ringbuf + debug_ringbuf_ofs, msg, msglen);
+       debug_ringbuf_ofs += msglen;
+}
+
 static struct debug_backend {
        const char *name;
        int log_level;
        int new_log_level;
-       void (*reload)(bool enabled, bool prev_enabled, const char *prog_name);
+       void (*reload)(bool enabled, bool prev_enabled,
+                      const char *prog_name, char *option);
        void (*log)(int msg_level, const char *msg, const char *msg_no_nl);
+       char *option;
 } debug_backends[] = {
        {
                .name = "file",
@@ -276,11 +357,16 @@ static struct debug_backend {
                .log = debug_gpfs_log,
        },
 #endif
+       {
+               .name = "ringbuf",
+               .log = debug_ringbuf_log,
+               .reload = debug_ringbuf_reload,
+       },
 };
 
 static struct debug_backend *debug_find_backend(const char *name)
 {
-       int i;
+       unsigned i;
 
        for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
                if (strcmp(name, debug_backends[i].name) == 0) {
@@ -297,6 +383,7 @@ static struct debug_backend *debug_find_backend(const char *name)
 static void debug_backend_parse_token(char *tok)
 {
        char *backend_name_option, *backend_name,*backend_level, *saveptr;
+       char *backend_option;
        struct debug_backend *b;
 
        /*
@@ -317,12 +404,7 @@ static void debug_backend_parse_token(char *tok)
                return;
        }
 
-       /*
-        * No backend is using the option yet.
-        */
-#if 0
        backend_option = strtok_r(NULL, "\0", &saveptr);
-#endif
 
        /*
         * Find and update backend
@@ -337,6 +419,13 @@ static void debug_backend_parse_token(char *tok)
        } else {
                b->new_log_level = atoi(backend_level);
        }
+
+       if (backend_option != NULL) {
+               b->option = strdup(backend_option);
+               if (b->option == NULL) {
+                       return;
+               }
+       }
 }
 
 /*
@@ -348,13 +437,14 @@ static void debug_set_backends(const char *param)
        size_t str_len = strlen(param);
        char str[str_len+1];
        char *tok, *saveptr;
-       int i;
+       unsigned i;
 
        /*
         * initialize new_log_level to detect backends that have been
         * disabled
         */
        for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+               SAFE_FREE(debug_backends[i].option);
                debug_backends[i].new_log_level = -1;
        }
 
@@ -380,7 +470,8 @@ static void debug_set_backends(const char *param)
                        bool enabled = b->new_log_level > -1;
                        bool previously_enabled = b->log_level > -1;
 
-                       b->reload(enabled, previously_enabled, state.prog_name);
+                       b->reload(enabled, previously_enabled, state.prog_name,
+                                 b->option);
                }
                b->log_level = b->new_log_level;
        }
@@ -389,7 +480,8 @@ static void debug_set_backends(const char *param)
 static void debug_backends_log(const char *msg, int msg_level)
 {
        char msg_no_nl[FORMAT_BUFR_SIZE];
-       int i, len;
+       unsigned i;
+       int len;
 
        /*
         * Some backends already add an extra newline, so also provide
@@ -445,6 +537,8 @@ static const char *default_classname_table[] = {
        [DBGC_DNS] =            "dns",
        [DBGC_LDB] =            "ldb",
        [DBGC_TEVENT] =         "tevent",
+       [DBGC_AUTH_AUDIT] =     "auth_audit",
+       [DBGC_AUTH_AUDIT_JSON] = "auth_json_audit",
 };
 
 /*
@@ -507,6 +601,8 @@ static void debug_init(void);
 
 void gfree_debugsyms(void)
 {
+       unsigned i;
+
        TALLOC_FREE(classname_table);
 
        if ( DEBUGLEVEL_CLASS != debug_class_list_initial ) {
@@ -517,6 +613,10 @@ void gfree_debugsyms(void)
        debug_num_classes = 0;
 
        state.initialized = false;
+
+       for (i = 0; i < ARRAY_SIZE(debug_backends); i++) {
+               SAFE_FREE(debug_backends[i].option);
+       }
 }
 
 /****************************************************************************
@@ -652,7 +752,7 @@ static bool debug_parse_param(char *param)
 {
        char *class_name;
        char *class_level;
-       char *saveptr;
+       char *saveptr = NULL;
        int ndx;
 
        class_name = strtok_r(param, ":", &saveptr);
@@ -1211,23 +1311,21 @@ void dbgflush( void )
 /***************************************************************************
  Print a Debug Header.
 
- Input:  level - Debug level of the message (not the system-wide debug
-                  level. )
-         cls   - Debuglevel class of the calling module.
-          file  - Pointer to a string containing the name of the file
-                  from which this function was called, or an empty string
-                  if the __FILE__ macro is not implemented.
-          func  - Pointer to a string containing the name of the function
-                  from which this function was called, or an empty string
-                  if the __FUNCTION__ macro is not implemented.
-         line  - line number of the call to dbghdr, assuming __LINE__
-                 works.
-
-  Output: Always true.  This makes it easy to fudge a call to dbghdr()
-          in a macro, since the function can be called as part of a test.
-          Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
-
-  Notes:  This function takes care of setting current_msg_level.
+ Input:  level    - Debug level of the message (not the system-wide debug
+                    level. )
+         cls      - Debuglevel class of the calling module.
+         location - Pointer to a string containing the name of the file
+                    from which this function was called, or an empty string
+                    if the __FILE__ macro is not implemented.
+         func     - Pointer to a string containing the name of the function
+                    from which this function was called, or an empty string
+                    if the __FUNCTION__ macro is not implemented.
+
+ Output: Always true.  This makes it easy to fudge a call to dbghdr()
+         in a macro, since the function can be called as part of a test.
+         Eg: ( (level <= DEBUGLEVEL) && (dbghdr(level,"",line)) )
+
+ Notes:  This function takes care of setting current_msg_level.
 
 ****************************************************************************/