URL: https://github.com/SSSD/sssd/pull/5585
Author: alexey-tikhonov
 Title: #5585: Poor man's backtrace.
Action: opened

PR body:
"""
    In case SSSD is run with debug_level < 9, log everything
    to a ring buffer in memory and flush the buffer to a log file on any
    error (up to and including `min(0x0040, debug_level)`)
    (i.e. if `debug_level` is explicitly set to 0 or 1 then only those
    error levels will trigger backtrace, otherwise up to 2).

    Feature is only supported for `logger == files`.

    Feature is configurable via 'debug_backtrace_enabled' option.
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/5585/head:pr5585
git checkout pr5585
From d6aa917c139081995453032acfefc38a2785429a Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Fri, 19 Mar 2021 20:38:58 +0100
Subject: [PATCH 1/8] DEBUG: got rid of most explicit DEBUG_IS_SET checks as a
 preliminary step for "logs backtrace" feature

---
 src/db/sysdb.c                      |  6 ++----
 src/p11_child/p11_child_openssl.c   |  8 +++-----
 src/providers/data_provider_fo.c    |  2 +-
 src/providers/files/files_certmap.c |  9 +++------
 src/providers/ipa/ipa_access.c      | 11 ++++-------
 src/providers/ipa/ipa_s2n_exop.c    | 26 ++++++++++----------------
 src/providers/krb5/krb5_child.c     | 18 +++++++-----------
 src/providers/ldap/sdap_async.c     | 16 ++++------------
 src/providers/ldap/sdap_certmap.c   | 10 ++++------
 src/providers/ldap/sdap_fd_events.c | 10 ++++------
 src/providers/proxy/proxy_id.c      | 22 ++++++++++------------
 src/responder/pam/pamsrv_p11.c      | 10 ++++------
 src/responder/ssh/ssh_cmd.c         | 10 ++++------
 src/sbus/connection/sbus_watch.c    | 15 +++++++--------
 src/util/debug.h                    | 23 ++++++++++++++---------
 src/util/sss_pam_data.h             |  2 +-
 src/util/sss_semanage.c             |  6 ++----
 src/util/tev_curl.c                 | 16 +++++++---------
 18 files changed, 91 insertions(+), 129 deletions(-)

diff --git a/src/db/sysdb.c b/src/db/sysdb.c
index 6001c49cb2..3fe0ebf6c2 100644
--- a/src/db/sysdb.c
+++ b/src/db/sysdb.c
@@ -2134,10 +2134,8 @@ void ldb_debug_messages(void *context, enum ldb_debug_level level,
         break;
     }
 
-    if (DEBUG_IS_SET(loglevel)) {
-        sss_vdebug_fn(__FILE__, __LINE__, "ldb", loglevel, APPEND_LINE_FEED,
-                      fmt, ap);
-    }
+    sss_vdebug_fn(__FILE__, __LINE__, "ldb", loglevel, APPEND_LINE_FEED,
+                  fmt, ap);
 }
 
 struct sss_domain_info *find_domain_by_msg(struct sss_domain_info *dom,
diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
index cee44df51c..78c05f5cb3 100644
--- a/src/p11_child/p11_child_openssl.c
+++ b/src/p11_child/p11_child_openssl.c
@@ -1335,11 +1335,9 @@ static CK_RV get_preferred_rsa_mechanism(TALLOC_CTX *mem_ctx,
         if (mechanism_list != NULL) {
             rv = module->C_GetMechanismList(slot_id, mechanism_list, &count);
             if (rv == CKR_OK) {
-                if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
-                    for (m = 0; m < count; m++) {
-                        DEBUG(SSSDBG_TRACE_ALL, "Found mechanism [%lu].\n",
-                                                mechanism_list[m]);
-                    }
+                for (m = 0; m < count; m++) {
+                    DEBUG(SSSDBG_TRACE_ALL, "Found mechanism [%lu].\n",
+                                            mechanism_list[m]);
                 }
                 for (c = 0; prefs[c].mech != 0; c++) {
                     for (m = 0; m < count; m++) {
diff --git a/src/providers/data_provider_fo.c b/src/providers/data_provider_fo.c
index 0dfbb04b0f..639548a3db 100644
--- a/src/providers/data_provider_fo.c
+++ b/src/providers/data_provider_fo.c
@@ -645,7 +645,7 @@ errno_t be_resolve_server_process(struct tevent_req *subreq,
         return ENOENT;
     }
 
-    if (DEBUG_IS_SET(SSSDBG_FUNC_DATA) && fo_get_server_name(state->srv)) {
+    if (fo_get_server_name(state->srv)) {
         struct resolv_hostent *srvaddr;
         char ipaddr[128];
         srvaddr = fo_get_server_hostent(state->srv);
diff --git a/src/providers/files/files_certmap.c b/src/providers/files/files_certmap.c
index 7d90a1fecf..665279f6f2 100644
--- a/src/providers/files/files_certmap.c
+++ b/src/providers/files/files_certmap.c
@@ -39,12 +39,9 @@ static void ext_debug(void *private, const char *file, long line,
         level = data->level;
     }
 
-    if (DEBUG_IS_SET(level)) {
-        va_start(ap, format);
-        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
-                      format, ap);
-        va_end(ap);
-    }
+    va_start(ap, format);
+    sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED, format, ap);
+    va_end(ap);
 }
 
 errno_t files_init_certmap(TALLOC_CTX *mem_ctx, struct files_id_ctx *id_ctx)
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c
index 4a6727c978..9b9cdf59f8 100644
--- a/src/providers/ipa/ipa_access.c
+++ b/src/providers/ipa/ipa_access.c
@@ -41,6 +41,7 @@ void hbac_debug_messages(const char *file, int line,
                          const char *fmt, ...)
 {
     int loglevel;
+    va_list ap;
 
     switch(level) {
     case HBAC_DBG_FATAL:
@@ -63,13 +64,9 @@ void hbac_debug_messages(const char *file, int line,
         break;
     }
 
-    if (DEBUG_IS_SET(loglevel)) {
-        va_list ap;
-
-        va_start(ap, fmt);
-        sss_vdebug_fn(file, line, function, loglevel, 0, fmt, ap);
-        va_end(ap);
-    }
+    va_start(ap, fmt);
+    sss_vdebug_fn(file, line, function, loglevel, 0, fmt, ap);
+    va_end(ap);
 }
 
 enum hbac_result {
diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c
index 08b1113fa0..b0baf0e67c 100644
--- a/src/providers/ipa/ipa_s2n_exop.c
+++ b/src/providers/ipa/ipa_s2n_exop.c
@@ -1658,14 +1658,12 @@ struct tevent_req *ipa_s2n_get_acct_info_send(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
-        input = ipa_s2n_reqinp2str(state, req_input);
-        DEBUG(SSSDBG_TRACE_FUNC,
-              "Sending request_type: [%s] for trust user [%s] to IPA server\n",
-              ipa_s2n_reqtype2str(state->request_type),
-              input);
-        talloc_zfree(input);
-    }
+    input = ipa_s2n_reqinp2str(state, req_input);
+    DEBUG(SSSDBG_TRACE_FUNC,
+          "Sending request_type: [%s] for trust user [%s] to IPA server\n",
+          ipa_s2n_reqtype2str(state->request_type),
+          input);
+    talloc_zfree(input);
 
     subreq = ipa_s2n_exop_send(state, state->ev, state->sh, state->protocol,
                                state->exop_timeout, bv_req);
@@ -2085,15 +2083,11 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq)
 
         if (attrs->response_type == RESP_USER_GROUPLIST) {
 
-            if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
-                size_t c;
+            DEBUG(SSSDBG_TRACE_FUNC, "Received [%zu] groups in group list "
+                                     "from IPA Server\n", attrs->ngroups);
 
-                DEBUG(SSSDBG_TRACE_FUNC, "Received [%zu] groups in group list "
-                                         "from IPA Server\n", attrs->ngroups);
-
-                for (c = 0; c < attrs->ngroups; c++) {
-                    DEBUG(SSSDBG_TRACE_FUNC, "[%s].\n", attrs->groups[c]);
-                }
+            for (size_t c = 0; c < attrs->ngroups; c++) {
+                DEBUG(SSSDBG_TRACE_FUNC, "[%s].\n", attrs->groups[c]);
             }
 
 
diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c
index 877d0b293a..fbd0555190 100644
--- a/src/providers/krb5/krb5_child.c
+++ b/src/providers/krb5/krb5_child.c
@@ -696,12 +696,10 @@ static krb5_error_code answer_pkinit(krb5_context ctx,
         goto done;
     }
 
-    if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
-        for (c = 0; chl->identities[c] != NULL; c++) {
-            DEBUG(SSSDBG_TRACE_ALL, "[%zu] Identity [%s] flags [%"PRId32"].\n",
-                                    c, chl->identities[c]->identity,
-                                    chl->identities[c]->token_flags);
-        }
+    for (c = 0; chl->identities[c] != NULL; c++) {
+        DEBUG(SSSDBG_TRACE_ALL, "[%zu] Identity [%s] flags [%"PRId32"].\n",
+                                c, chl->identities[c]->identity,
+                                chl->identities[c]->token_flags);
     }
 
     DEBUG(SSSDBG_TRACE_ALL, "Setting pkinit_prompting.\n");
@@ -847,11 +845,9 @@ static krb5_error_code sss_krb5_prompter(krb5_context context, void *data,
           name, banner, num_prompts);
 
     if (num_prompts != 0) {
-        if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
-            for (c = 0; c < num_prompts; c++) {
-                DEBUG(SSSDBG_TRACE_ALL, "Prompt [%zu][%s].\n", c,
-                                        prompts[c].prompt);
-            }
+        for (c = 0; c < num_prompts; c++) {
+            DEBUG(SSSDBG_TRACE_ALL, "Prompt [%zu][%s].\n", c,
+                                    prompts[c].prompt);
         }
 
         DEBUG(SSSDBG_FUNC_DATA, "Prompter interface isn't used for password prompts by SSSD.\n");
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index cc77fb249d..6632abeb15 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -1247,10 +1247,6 @@ static void sdap_print_server(struct sdap_handle *sh)
     char ip[NI_MAXHOST];
     int port;
 
-    if (!DEBUG_IS_SET(SSSDBG_TRACE_INTERNAL)) {
-        return;
-    }
-
     ret = get_fd_from_ldap(sh->ldap, &fd);
     if (ret != EOK) {
         DEBUG(SSSDBG_MINOR_FAILURE, "cannot get sdap fd\n");
@@ -1470,14 +1466,10 @@ static errno_t sdap_get_generic_ext_step(struct tevent_req *req)
          "calling ldap_search_ext with [%s][%s].\n",
           state->filter ? state->filter : "no filter",
           state->search_base);
-    if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) {
-        int i;
-
-        if (state->attrs) {
-            for (i = 0; state->attrs[i]; i++) {
-                DEBUG(SSSDBG_TRACE_LIBS,
-                      "Requesting attrs: [%s]\n", state->attrs[i]);
-            }
+    if (state->attrs) {
+        for (int i = 0; state->attrs[i]; i++) {
+            DEBUG(SSSDBG_TRACE_LIBS,
+                  "Requesting attrs: [%s]\n", state->attrs[i]);
         }
     }
 
diff --git a/src/providers/ldap/sdap_certmap.c b/src/providers/ldap/sdap_certmap.c
index fcf88a9c69..e32895cf93 100644
--- a/src/providers/ldap/sdap_certmap.c
+++ b/src/providers/ldap/sdap_certmap.c
@@ -44,12 +44,10 @@ static void ext_debug(void *private, const char *file, long line,
         level = data->level;
     }
 
-    if (DEBUG_IS_SET(level)) {
-        va_start(ap, format);
-        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
-                      format, ap);
-        va_end(ap);
-    }
+    va_start(ap, format);
+    sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
+                  format, ap);
+    va_end(ap);
 }
 
 struct sss_certmap_ctx *sdap_get_sss_certmap(struct sdap_certmap_ctx *ctx)
diff --git a/src/providers/ldap/sdap_fd_events.c b/src/providers/ldap/sdap_fd_events.c
index 96b8aa62e9..d3bcd55e29 100644
--- a/src/providers/ldap/sdap_fd_events.c
+++ b/src/providers/ldap/sdap_fd_events.c
@@ -128,12 +128,10 @@ static int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb,
         }
     }
 
-    if (DEBUG_IS_SET(SSSDBG_TRACE_LIBS)) {
-        char *uri = ldap_url_desc2str(srv);
-        DEBUG(SSSDBG_TRACE_LIBS, "New LDAP connection to [%s] with fd [%d].\n",
-                  uri, ber_fd);
-        free(uri);
-    }
+    char *uri = ldap_url_desc2str(srv);
+    DEBUG(SSSDBG_TRACE_LIBS, "New LDAP connection to [%s] with fd [%d].\n",
+              uri, ber_fd);
+    free(uri);
 
     fd_event_item = talloc_zero(cb_data, struct fd_event_item);
     if (fd_event_item == NULL) {
diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c
index f363860891..25daea585d 100644
--- a/src/providers/proxy/proxy_id.c
+++ b/src/providers/proxy/proxy_id.c
@@ -565,19 +565,17 @@ static int enum_users(TALLOC_CTX *mem_ctx,
 /* =Save-group-utilities=================================================*/
 #define DEBUG_GR_MEM(level, grp) \
     do { \
-        if (DEBUG_IS_SET(level)) { \
-            if (!grp->gr_mem || !grp->gr_mem[0]) { \
-                DEBUG(level, "Group %s has no members!\n", \
-                              grp->gr_name); \
-            } else { \
-                int i = 0; \
-                while (grp->gr_mem[i]) { \
-                    /* count */ \
-                    i++; \
-                } \
-                DEBUG(level, "Group %s has %d members!\n", \
-                              grp->gr_name, i); \
+        if (!grp->gr_mem || !grp->gr_mem[0]) { \
+            DEBUG(level, "Group %s has no members!\n", \
+                          grp->gr_name); \
+        } else { \
+            int i = 0; \
+            while (grp->gr_mem[i]) { \
+                /* count */ \
+                i++; \
             } \
+            DEBUG(level, "Group %s has %d members!\n", \
+                          grp->gr_name, i); \
         } \
     } while(0)
 
diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
index bf285c264f..3b21332db9 100644
--- a/src/responder/pam/pamsrv_p11.c
+++ b/src/responder/pam/pamsrv_p11.c
@@ -132,12 +132,10 @@ static void ext_debug(void *private, const char *file, long line,
         level = data->level;
     }
 
-    if (DEBUG_IS_SET(level)) {
-        va_start(ap, format);
-        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
-                      format, ap);
-        va_end(ap);
-    }
+    va_start(ap, format);
+    sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
+                  format, ap);
+    va_end(ap);
 }
 
 errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx,
diff --git a/src/responder/ssh/ssh_cmd.c b/src/responder/ssh/ssh_cmd.c
index a593c904f6..45ab57be59 100644
--- a/src/responder/ssh/ssh_cmd.c
+++ b/src/responder/ssh/ssh_cmd.c
@@ -140,12 +140,10 @@ static void ssh_ext_debug(void *private, const char *file, long line,
         level = data->level;
     }
 
-    if (DEBUG_IS_SET(level)) {
-        va_start(ap, format);
-        sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
-                      format, ap);
-        va_end(ap);
-    }
+    va_start(ap, format);
+    sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED,
+                  format, ap);
+    va_end(ap);
 }
 
 static errno_t ssh_cmd_refresh_certmap_ctx(struct ssh_ctx *ssh_ctx,
diff --git a/src/sbus/connection/sbus_watch.c b/src/sbus/connection/sbus_watch.c
index 3abb66fa47..d1b55e9633 100644
--- a/src/sbus/connection/sbus_watch.c
+++ b/src/sbus/connection/sbus_watch.c
@@ -315,6 +315,7 @@ sbus_watch_toggle(DBusWatch *dbus_watch, void *data)
     struct sbus_watch_fd *watch_fd;
     dbus_bool_t is_enabled;
     unsigned int flags;
+    int fd;
 
     is_enabled = dbus_watch_get_enabled(dbus_watch);
     flags = dbus_watch_get_flags(dbus_watch);
@@ -344,15 +345,13 @@ sbus_watch_toggle(DBusWatch *dbus_watch, void *data)
         }
     }
 
-    if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) {
-        int fd = sbus_watch_get_fd(dbus_watch);
+    fd = sbus_watch_get_fd(dbus_watch);
 
-        DEBUG(SSSDBG_TRACE_ALL, "Toggle to %s %s/%s watch on %d\n",
-              is_enabled ? "enabled" : "disabled",
-              (flags & DBUS_WATCH_READABLE) ? "R" : "-",
-              (flags & DBUS_WATCH_WRITABLE) ? "W" : "-",
-              fd);
-    }
+    DEBUG(SSSDBG_TRACE_ALL, "Toggle to %s %s/%s watch on %d\n",
+          is_enabled ? "enabled" : "disabled",
+          (flags & DBUS_WATCH_READABLE) ? "R" : "-",
+          (flags & DBUS_WATCH_WRITABLE) ? "W" : "-",
+          fd);
 }
 
 /**
diff --git a/src/util/debug.h b/src/util/debug.h
index 54a7e39346..29329dbd97 100644
--- a/src/util/debug.h
+++ b/src/util/debug.h
@@ -26,6 +26,8 @@
 #include <stdio.h>
 #include <stdbool.h>
 
+#include "util/util_errors.h"
+
 #define SSSDBG_TIMESTAMP_UNRESOLVED      -1
 #define SSSDBG_TIMESTAMP_DEFAULT          1
 
@@ -128,15 +130,6 @@ int rotate_debug_files(void);
     } \
 } while (0)
 
-/** \def DEBUG_IS_SET(level)
-    \brief checks whether level is set in debug_level
-
-    \param level the debug level, please use one of the SSSDBG*_ macros
-*/
-#define DEBUG_IS_SET(level) (debug_level & (level) || \
-                            (debug_level == SSSDBG_UNRESOLVED && \
-                                            (level & (SSSDBG_FATAL_FAILURE | \
-                                                      SSSDBG_CRIT_FAILURE))))
 
 /* SSSD_*_OPTS are used as 'poptOption' entries */
 #define SSSD_LOGGER_OPTS \
@@ -181,6 +174,18 @@ void sss_debug_fn(const char *file,
 
 #define APPEND_LINE_FEED 0x1 /* can be used as a sss_vdebug_fn() flag */
 
+/* Checks whether level is set in generic debug_level.
+   Rarely needed to be used explicitly as everything
+   should go to backtrace buffer anyway (regardless debug_level)
+   Deciding if "--verbose" should be passed to `adcli` child process
+   is one of usage examples.
+ */
+#define DEBUG_IS_SET(level) (debug_level & (level) || \
+                            (debug_level == SSSDBG_UNRESOLVED && \
+                                            (level & (SSSDBG_FATAL_FAILURE | \
+                                                      SSSDBG_CRIT_FAILURE))))
+
+
 /* not to be used explictly, use 'DEBUG_INIT' instead */
 void _sss_debug_init(int dbg_lvl, const char *logger);
 void _sss_talloc_log_fn(const char *msg);
diff --git a/src/util/sss_pam_data.h b/src/util/sss_pam_data.h
index c989810541..674588daa2 100644
--- a/src/util/sss_pam_data.h
+++ b/src/util/sss_pam_data.h
@@ -34,7 +34,7 @@
 #include "util/authtok.h"
 
 #define DEBUG_PAM_DATA(level, pd) do { \
-    if (DEBUG_IS_SET(level)) pam_print_data(level, pd); \
+    pam_print_data(level, pd); \
 } while(0)
 
 struct response_data {
diff --git a/src/util/sss_semanage.c b/src/util/sss_semanage.c
index aea03852ac..10a567c9a9 100644
--- a/src/util/sss_semanage.c
+++ b/src/util/sss_semanage.c
@@ -55,10 +55,8 @@ static void sss_semanage_error_callback(void *varg,
     }
 
     va_start(ap, fmt);
-    if (DEBUG_IS_SET(level)) {
-        sss_vdebug_fn(__FILE__, __LINE__, "libsemanage", level,
-                      APPEND_LINE_FEED, fmt, ap);
-    }
+    sss_vdebug_fn(__FILE__, __LINE__, "libsemanage", level,
+                  APPEND_LINE_FEED, fmt, ap);
     va_end(ap);
 }
 
diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c
index ebbcefc016..8c6fa291e0 100644
--- a/src/util/tev_curl.c
+++ b/src/util/tev_curl.c
@@ -196,15 +196,13 @@ static void handle_curlmsg_done(CURLMsg *message)
         return;
     }
 
-    if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
-        crv = curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url);
-        if (crv != CURLE_OK) {
-            DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get CURLINFO_EFFECTIVE_URL "
-                  "[%d]: %s\n", crv, curl_easy_strerror(crv));
-            /* not fatal since we need this only for debugging */
-        } else {
-            DEBUG(SSSDBG_TRACE_FUNC, "Handled %s\n", done_url);
-        }
+    crv = curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url);
+    if (crv != CURLE_OK) {
+        DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get CURLINFO_EFFECTIVE_URL "
+              "[%d]: %s\n", crv, curl_easy_strerror(crv));
+        /* not fatal since we need this only for debugging */
+    } else {
+        DEBUG(SSSDBG_TRACE_FUNC, "Handled %s\n", done_url);
     }
 
     crv = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (void *) &req);

From fba928f4a3b15592cdffa93a3dff73eb1d7f5f98 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Mon, 22 Mar 2021 14:58:22 +0100
Subject: [PATCH 2/8] DEBUG: poor man's backtrace

:feature: In case SSSD is run with debug_level < 9, log everything
to a ring buffer in memory and flush the buffer to a log file on any
error (up to and including `min(0x0040, debug_level)`)
(i.e. if `debug_level` is explicitly set to 0 or 1 then only those
error levels will trigger backtrace, otherwise up to 2).
Feature is only supported for `logger == files`.
---
 Makefile.am                    |   3 +
 src/tests/cmocka/dummy_child.c |   6 +-
 src/util/debug.c               |  78 +++++----
 src/util/debug.h               |  11 +-
 src/util/debug_backtrace.c     | 289 +++++++++++++++++++++++++++++++++
 5 files changed, 338 insertions(+), 49 deletions(-)
 create mode 100644 src/util/debug_backtrace.c

diff --git a/Makefile.am b/Makefile.am
index f4f71bdfdb..7d4bc24c3c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -945,6 +945,7 @@ endif
 pkglib_LTLIBRARIES += libsss_debug.la
 libsss_debug_la_SOURCES = \
     src/util/debug.c \
+    src/util/debug_backtrace.c \
     src/util/sss_log.c \
     src/util/sss_cli_cmd.c \
     $(NULL)
@@ -1069,6 +1070,7 @@ pkglib_LTLIBRARIES += libsss_sbus.la
 libsss_sbus_la_SOURCES = \
     src/util/check_and_open.c \
     src/util/debug.c \
+    src/util/debug_backtrace.c \
     src/util/sss_ptr_hash.c \
     src/util/sss_ptr_list.c \
     src/util/sss_utf8.c \
@@ -1132,6 +1134,7 @@ libsss_sbus_la_LDFLAGS = \
 pkglib_LTLIBRARIES += libsss_sbus_sync.la
 libsss_sbus_sync_la_SOURCES = \
     src/util/debug.c \
+    src/util/debug_backtrace.c \
     src/util/sss_utf8.c \
     src/util/util.c \
     src/util/util_errors.c \
diff --git a/src/tests/cmocka/dummy_child.c b/src/tests/cmocka/dummy_child.c
index 33b8c77fcb..8d0a2eb16b 100644
--- a/src/tests/cmocka/dummy_child.c
+++ b/src/tests/cmocka/dummy_child.c
@@ -42,6 +42,7 @@ int main(int argc, const char *argv[])
     const char *action = NULL;
     const char *guitar;
     const char *drums;
+    int timestamp_opt;
 
     struct poptOption long_options[] = {
         POPT_AUTOHELP
@@ -69,6 +70,7 @@ int main(int argc, const char *argv[])
     poptFreeContext(pc);
 
     debug_log_file = "test_dummy_child";
+    timestamp_opt = debug_timestamps; /* save value for verification */
     DEBUG_INIT(debug_level, opt_logger);
 
     action = getenv("TEST_CHILD_ACTION");
@@ -80,7 +82,7 @@ int main(int argc, const char *argv[])
                 _exit(1);
             }
         } else if (strcasecmp(action, "check_only_extra_args") == 0) {
-            if (debug_timestamps == 1) {
+            if (timestamp_opt == 1) {
                 DEBUG(SSSDBG_CRIT_FAILURE,
                       "debug_timestamp was passed when only extra args "
                       "should have been\n");
@@ -93,7 +95,7 @@ int main(int argc, const char *argv[])
                 _exit(1);
             }
         } else if (strcasecmp(action, "check_only_extra_args_neg") == 0) {
-            if (debug_timestamps != 1) {
+            if (timestamp_opt != 1) {
                 DEBUG(SSSDBG_CRIT_FAILURE,
                       "debug_timestamp was not passed as expected\n");
                 _exit(1);
diff --git a/src/util/debug.c b/src/util/debug.c
index 2e01311bf1..f87e85812a 100644
--- a/src/util/debug.c
+++ b/src/util/debug.c
@@ -36,6 +36,12 @@
 
 #include "util/util.h"
 
+/* from debug_backtrace.h */
+void sss_debug_backtrace_init(void);
+void sss_debug_backtrace_vprintf(int level, const char *format, va_list ap);
+void sss_debug_backtrace_printf(int level, const char *format, ...);
+void sss_debug_backtrace_endmsg(int level);
+
 const char *debug_prg_name = "sssd";
 
 int debug_level = SSSDBG_UNRESOLVED;
@@ -43,7 +49,7 @@ int debug_timestamps = SSSDBG_TIMESTAMP_UNRESOLVED;
 int debug_microseconds = SSSDBG_MICROSECONDS_UNRESOLVED;
 enum sss_logger_t sss_logger = STDERR_LOGGER;
 const char *debug_log_file = "sssd";
-static FILE *debug_file;
+FILE *_sss_debug_file;
 
 const char *sss_logger_str[] = {
         [STDERR_LOGGER] = "stderr",
@@ -97,17 +103,27 @@ void _sss_debug_init(int dbg_lvl, const char *logger)
         debug_level = SSSDBG_UNRESOLVED;
     }
 
+    if (debug_timestamps == SSSDBG_TIMESTAMP_UNRESOLVED) {
+        debug_timestamps = SSSDBG_TIMESTAMP_DEFAULT;
+    }
+
+    if (debug_microseconds == SSSDBG_MICROSECONDS_UNRESOLVED) {
+        debug_microseconds = SSSDBG_MICROSECONDS_DEFAULT;
+    }
+
     sss_set_logger(logger);
 
     /* if 'FILES_LOGGER' is requested then open log file, if it wasn't
      * initialized before via set_debug_file_from_fd().
      */
-    if ((sss_logger == FILES_LOGGER) && (debug_file == NULL)) {
+    if ((sss_logger == FILES_LOGGER) && (_sss_debug_file == NULL)) {
         if (_sss_open_debug_file() != 0) {
             ERROR("Error opening log file, falling back to stderr\n");
             sss_logger = STDERR_LOGGER;
         }
     }
+
+    sss_debug_backtrace_init();
 }
 
 errno_t set_debug_file_from_fd(const int fd)
@@ -129,18 +145,18 @@ errno_t set_debug_file_from_fd(const int fd)
         return ret;
     }
 
-    debug_file = dummy;
+    _sss_debug_file = dummy;
 
     return EOK;
 }
 
 int get_fd_from_debug_file(void)
 {
-    if (debug_file == NULL) {
+    if (_sss_debug_file == NULL) {
         return STDERR_FILENO;
     }
 
-    return fileno(debug_file);
+    return fileno(_sss_debug_file);
 }
 
 int debug_convert_old_level(int old_level)
@@ -186,29 +202,6 @@ int debug_convert_old_level(int old_level)
     return new_level;
 }
 
-static void debug_fflush(void)
-{
-    fflush(debug_file ? debug_file : stderr);
-}
-
-static void debug_vprintf(const char *format, va_list ap)
-{
-    vfprintf(debug_file ? debug_file : stderr, format, ap);
-}
-
-static void debug_printf(const char *format, ...)
-                SSS_ATTRIBUTE_PRINTF(1, 2);
-
-static void debug_printf(const char *format, ...)
-{
-    va_list ap;
-
-    va_start(ap, format);
-
-    debug_vprintf(format, ap);
-
-    va_end(ap);
-}
 
 #ifdef WITH_JOURNALD
 static errno_t journal_send(const char *file,
@@ -292,6 +285,7 @@ void sss_vdebug_fn(const char *file,
     va_list ap_fallback;
 
     if (sss_logger == JOURNALD_LOGGER) {
+        if (!DEBUG_IS_SET(level)) return; /* no debug backtrace with journald atm */
         /* If we are not outputting logs to files, we should be sending them
          * to journald.
          * NOTE: on modern systems, this is where stdout/stderr will end up
@@ -303,8 +297,8 @@ void sss_vdebug_fn(const char *file,
         ret = journal_send(file, line, function, level, format, ap);
         if (ret != EOK) {
             /* Emergency fallback, send to STDERR */
-            debug_vprintf(format, ap_fallback);
-            debug_fflush();
+            vfprintf(stderr, format, ap_fallback);
+            fflush(stderr);
         }
         va_end(ap_fallback);
         return;
@@ -327,19 +321,21 @@ void sss_vdebug_fn(const char *file,
                      tm.tm_hour, tm.tm_min, tm.tm_sec);
         }
         if (debug_microseconds) {
-            debug_printf("%s:%.6ld): ", last_time_str, tv.tv_usec);
+            sss_debug_backtrace_printf(level, "%s:%.6ld): ",
+                                       last_time_str, tv.tv_usec);
         } else {
-            debug_printf("%s): ", last_time_str);
+            sss_debug_backtrace_printf(level, "%s): ", last_time_str);
         }
     }
 
-    debug_printf("[%s] [%s] (%#.4x): ", debug_prg_name, function, level);
+    sss_debug_backtrace_printf(level, "[%s] [%s] (%#.4x): ",
+                               debug_prg_name, function, level);
 
-    debug_vprintf(format, ap);
+    sss_debug_backtrace_vprintf(level, format, ap);
     if (flags & APPEND_LINE_FEED) {
-        debug_printf("\n");
+        sss_debug_backtrace_printf(level, "\n");
     }
-    debug_fflush();
+    sss_debug_backtrace_endmsg(level);
 }
 
 void sss_debug_fn(const char *file,
@@ -416,7 +412,7 @@ int open_debug_file_ex(const char *filename, FILE **filep, bool want_cloexec)
         return ENOMEM;
     }
 
-    if (debug_file && !filep) fclose(debug_file);
+    if (_sss_debug_file && !filep) fclose(_sss_debug_file);
 
     old_umask = umask(SSS_DFL_UMASK);
     errno = 0;
@@ -442,7 +438,7 @@ int open_debug_file_ex(const char *filename, FILE **filep, bool want_cloexec)
     }
 
     if (filep == NULL) {
-        debug_file = f;
+        _sss_debug_file = f;
     } else {
         *filep = f;
     }
@@ -457,10 +453,10 @@ int rotate_debug_files(void)
 
     if (sss_logger != FILES_LOGGER) return EOK;
 
-    if (debug_file != NULL) {
+    if (_sss_debug_file != NULL) {
         do {
             error = 0;
-            ret = fclose(debug_file);
+            ret = fclose(_sss_debug_file);
             if (ret != 0) {
                 error = errno;
             }
@@ -486,7 +482,7 @@ int rotate_debug_files(void)
         }
     }
 
-    debug_file = NULL;
+    _sss_debug_file = NULL;
 
     return _sss_open_debug_file();
 }
diff --git a/src/util/debug.h b/src/util/debug.h
index 29329dbd97..b7e41dd8e4 100644
--- a/src/util/debug.h
+++ b/src/util/debug.h
@@ -63,6 +63,8 @@ extern const char *debug_log_file;   /* only file name, excluding path */
     DEBUG_INIT(dbg_lvl, sss_logger_str[STDERR_LOGGER]); \
 } while (0)
 
+void sss_debug_backtrace_enable(bool enable);
+
 /* debug_convert_old_level() converts "old" style decimal notation
  * to bitmask composed of SSSDBG_*
  * Used explicitly, for example, while processing user input
@@ -122,12 +124,9 @@ int rotate_debug_files(void);
     \param ... the debug message format arguments
 */
 #define DEBUG(level, format, ...) do { \
-    int __debug_macro_level = level; \
-    if (DEBUG_IS_SET(__debug_macro_level)) { \
-        sss_debug_fn(__FILE__, __LINE__, __FUNCTION__, \
-                     __debug_macro_level, \
-                     format, ##__VA_ARGS__); \
-    } \
+    sss_debug_fn(__FILE__, __LINE__, __FUNCTION__, \
+                 level, \
+                 format, ##__VA_ARGS__); \
 } while (0)
 
 
diff --git a/src/util/debug_backtrace.c b/src/util/debug_backtrace.c
new file mode 100644
index 0000000000..4eccebb3ab
--- /dev/null
+++ b/src/util/debug_backtrace.c
@@ -0,0 +1,289 @@
+/*
+    Copyright (C) 2021 Red Hat
+
+    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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "util/debug.h"
+
+extern FILE *_sss_debug_file;
+
+
+static const unsigned SSS_DEBUG_BACKTRACE_DEFAULT_SIZE = 100*1024; /* bytes */
+static const unsigned SSS_DEBUG_BACKTRACE_LEVEL        = SSSDBG_BE_FO;
+
+
+/*                     -->
+ * ring buffer = [*******t...\n............e000]
+ * where:
+ *    "t" - 'tail', "e" - 'end'
+ *    "......" - "old" part of buffer
+ *    "******" - "new" part of buffer
+ *    "000"    - unoccupied space
+ */
+static struct {
+    bool      enabled;
+    bool      initialized;
+    int       size;
+    char     *buffer;  /* buffer start */
+    char     *end;     /* end data border */
+    char     *tail;    /* tail of "current" message */
+} _bt;
+
+
+static inline bool _all_levels_enabled(void);
+static inline bool _backtrace_is_enabled(int level);
+static inline bool _is_trigger_level(int level);
+static void _backtrace_vprintf(const char *format, va_list ap);
+static void _backtrace_printf(const char *format, ...);
+static void _backtrace_dump(void);
+static inline void _debug_vprintf(const char *format, va_list ap);
+static inline void _debug_fwrite(const char *ptr, const char *end);
+static inline void _debug_fflush(void);
+
+
+void sss_debug_backtrace_init(void)
+{
+    _bt.size = SSS_DEBUG_BACKTRACE_DEFAULT_SIZE;
+    _bt.buffer = (char *)malloc(_bt.size);
+    if (!_bt.buffer) {
+        ERROR("Failed to allocate debug backtrace buffer, feature is off\n");
+        return;
+    }
+
+    _bt.end         = _bt.buffer;
+    _bt.tail        = _bt.buffer;
+
+    _bt.enabled     = true;
+    _bt.initialized = true;
+
+    _backtrace_printf("   *  ");
+}
+
+
+void sss_debug_backtrace_enable(bool enable)
+{
+    _bt.enabled = enable;
+}
+
+
+void sss_debug_backtrace_vprintf(int level, const char *format, va_list ap)
+{
+    va_list ap_copy;
+
+    /* Potential optimization: only print to file here if backtrace is disabled,
+     * otherwise always print message to backtrace only and then copy message
+     * from backtrace to file in sss_debug_backtrace_endmsg().
+     * This saves va_copy and another round of format parsing inside printf but
+     * results in a little bit less readable output.
+     */
+    if (DEBUG_IS_SET(level)) {
+        va_copy(ap_copy, ap);
+        _debug_vprintf(format, ap_copy);
+        va_end(ap_copy);
+    }
+
+    if (_backtrace_is_enabled(level)) {
+        _backtrace_vprintf(format, ap);
+    }
+}
+
+
+void sss_debug_backtrace_printf(int level, const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    sss_debug_backtrace_vprintf(level, format, ap);
+    va_end(ap);
+}
+
+
+void sss_debug_backtrace_endmsg(int level)
+{
+    if (DEBUG_IS_SET(level)) {
+        _debug_fflush();
+    }
+
+    if (_backtrace_is_enabled(level)) {
+        if (_is_trigger_level(level)) {
+            _backtrace_dump();
+        }
+        _backtrace_printf("   *  ");
+    }
+}
+
+
+
+
+/* ********** Helpers ********** */
+
+
+static inline void _debug_vprintf(const char *format, va_list ap)
+{
+    vfprintf(_sss_debug_file ? _sss_debug_file : stderr, format, ap);
+}
+
+
+static inline void _debug_fwrite(const char *begin, const char *end)
+{
+    if (end <= begin) {
+        return;
+    }
+    size_t size = (end - begin);
+    fwrite_unlocked(begin, size, 1, _sss_debug_file ? _sss_debug_file : stderr);
+}
+
+
+static inline void _debug_fflush(void)
+{
+    fflush(_sss_debug_file ? _sss_debug_file : stderr);
+}
+
+
+ /* does 'level' trigger backtrace dump? */
+static inline bool _is_trigger_level(int level)
+{
+    return ((level <= SSSDBG_OP_FAILURE) &&
+            (level <= debug_level));
+}
+
+
+/* checks if global 'debug_level' has all levels up to 9 enabled */
+static inline bool _all_levels_enabled(void)
+{
+    static const unsigned all_levels =
+      SSSDBG_FATAL_FAILURE|SSSDBG_CRIT_FAILURE|SSSDBG_OP_FAILURE|
+      SSSDBG_MINOR_FAILURE|SSSDBG_CONF_SETTINGS|SSSDBG_FUNC_DATA|
+      SSSDBG_TRACE_FUNC|SSSDBG_TRACE_LIBS|SSSDBG_TRACE_INTERNAL|
+      SSSDBG_TRACE_ALL|SSSDBG_BE_FO;
+
+    unsigned level = debug_level & ~SSSDBG_TRACE_LDB;
+
+    return ((level ^ all_levels) == 0);
+}
+
+
+/* should message of this 'level' go to backtrace? */
+static inline bool _backtrace_is_enabled(int level)
+{
+    /* Store message in backtrace buffer if: */
+    return (_bt.initialized        && /* backtrace is initialized */
+            _bt.enabled            && /* backtrace is enabled */
+            sss_logger != STDERR_LOGGER &&
+            !_all_levels_enabled() && /* generic log doesn't cover everything */
+            level <= SSS_DEBUG_BACKTRACE_LEVEL); /* skip SSSDBG_TRACE_LDB */
+}
+
+
+ /* prints to buffer */
+static void _backtrace_vprintf(const char *format, va_list ap)
+{
+    int buff_tail_size = _bt.size - (_bt.tail - _bt.buffer);
+    int written;
+
+    /* make sure there is at least 1kb available to avoid truncation;
+     * putting a sane limit on the size of single message (1kb in a worst case)
+     * makes logic simpler and avoids performance hit
+     */
+    if (buff_tail_size < 1024) {
+        /* let's wrap */
+        _bt.end = _bt.tail;
+        _bt.tail = _bt.buffer;
+        buff_tail_size = _bt.size;
+    }
+
+    written = vsnprintf(_bt.tail, buff_tail_size, format, ap);
+    if (written >= buff_tail_size) {
+        /* message is > 1kb, just discard */
+        return;
+    }
+
+    _bt.tail += written;
+    if (_bt.tail > _bt.end) {
+        _bt.end = _bt.tail;
+    }
+}
+
+
+static void _backtrace_printf(const char *format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    _backtrace_vprintf(format, ap);
+    va_end(ap);
+}
+
+
+static bool _bt_empty(const char *begin, const char *end)
+{
+    int counter = 0;
+
+    while (begin < end) {
+        if (*begin == '\n') {
+            counter++;
+            if (counter == 2) {
+                /* there is least one line in addition to trigger msg */
+                return false;
+            }
+        }
+        begin++;
+    }
+
+    return true;
+}
+
+
+static void _backtrace_dump(void)
+{
+    const char *start = NULL;
+    static const char *start_marker =
+        "********************** PREVIOUS MESSAGE WAS TRIGGERED BY THE FOLLOWING BACKTRACE:\n";
+    static const char *end_marker   =
+        "********************** BACKTRACE DUMP ENDS HERE *********************************\n\n";
+
+    if (_bt.end > _bt.tail) {
+        /* there is something in the "old" part, but don't start mid message */
+        start = _bt.tail + 1;
+        while ((start < _bt.end) && (*start != '\n')) start++;
+        if (start >= _bt.end) start = NULL;
+    }
+
+    if (!start) {
+        /* do we have anything to dump at all? */
+        if (_bt_empty(_bt.buffer, _bt.tail)) {
+            return;
+        }
+    }
+
+    fprintf(_sss_debug_file ? _sss_debug_file : stderr, "%s", start_marker);
+
+    if (start) {
+        _debug_fwrite(start + 1, _bt.end); /* dump "old" part of buffer */
+    }
+    _debug_fwrite(_bt.buffer, _bt.tail); /* dump "new" part of buffer */
+
+    fprintf(_sss_debug_file ? _sss_debug_file : stderr, "%s", end_marker);
+    _debug_fflush();
+
+    _bt.end  = _bt.buffer;
+    _bt.tail = _bt.buffer;
+}
+

From d8cf3cc67ce09f5b036e7ff14097024f14c076e5 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Wed, 31 Mar 2021 11:48:58 +0200
Subject: [PATCH 3/8] PAM: fixes a couple of covscan issues

Fixes:
```
Error: COMPILER_WARNING (CWE-758):
sssd-2.4.3/src/util/debug.h:127:5: warning[-Wformat-overflow=]: '%.*s' directive argument is null
 #  127 |     sss_debug_fn(__FILE__, __LINE__, __FUNCTION__, \
 #      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 #  128 |                  level, \
 #      |                  ~~~~~~~~
 #  129 |                  format, ##__VA_ARGS__); \
 #      |                  ~~~~~~~~~~~~~~~~~~~~~~
sssd-2.4.3/src/responder/pam/pamsrv_cmd.c: scope_hint: In function 'filter_responses'
sssd-2.4.3/src/responder/pam/pamsrv_cmd.c:569:51: note: format string is defined here
 #  569 |               "Found PAM ENV filter for variable [%.*s] and service [%s].\n",
 #      |                                                   ^~~~
```

and

```
Error: COMPILER_WARNING (CWE-758):
sssd-2.4.3/src/util/util.h:47: included_from: Included from here.
sssd-2.4.3/src/responder/pam/pamsrv_cmd.c:24: included_from: Included from here.
sssd-2.4.3/src/responder/pam/pamsrv_cmd.c: scope_hint: In function 'pam_check_user_search_next'
sssd-2.4.3/src/util/debug.h:127:5: warning[-Wformat-overflow=]: '%s' directive argument is null
 #  127 |     sss_debug_fn(__FILE__, __LINE__, __FUNCTION__, \
 #      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 #  128 |                  level, \
 #      |                  ~~~~~~~~
 #  129 |                  format, ##__VA_ARGS__); \
 #      |                  ~~~~~~~~~~~~~~~~~~~~~~
sssd-2.4.3/src/responder/pam/pamsrv_cmd.c:1947:53: note: format string is defined here
 # 1947 |     DEBUG(SSSDBG_TRACE_ALL, "PAM initgroups scheme [%s].\n",
 #      |                                                     ^~
```
---
 src/responder/pam/pamsrv_cmd.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
index d052ca7528..c503801f69 100644
--- a/src/responder/pam/pamsrv_cmd.c
+++ b/src/responder/pam/pamsrv_cmd.c
@@ -68,7 +68,8 @@ enum pam_initgroups_scheme pam_initgroups_string_to_enum(const char *str)
     return PAM_INITGR_INVALID;
 }
 
-const char *pam_initgroup_enum_to_string(enum pam_initgroups_scheme scheme) {
+const char *pam_initgroup_enum_to_string(enum pam_initgroups_scheme scheme)
+{
     size_t c;
 
     for (c = 0 ; pam_initgroup_enum_str[c].option != NULL; c++) {
@@ -77,7 +78,7 @@ const char *pam_initgroup_enum_to_string(enum pam_initgroups_scheme scheme) {
         }
     }
 
-    return NULL;
+    return "(NULL)";
 }
 
 
@@ -567,7 +568,9 @@ static errno_t filter_responses_env(struct response_data *resp,
 
         DEBUG(SSSDBG_TRACE_ALL,
               "Found PAM ENV filter for variable [%.*s] and service [%s].\n",
-              (int) var_name_len, var_name, service);
+              (int) var_name_len,
+              (var_name ? var_name : "(NULL)"),
+              (service ? service : "(NULL)"));
 
         if (service != NULL && pd->service != NULL
                     && strcmp(service, pd->service) != 0) {

From 2489279d887e166075298620a470e064a2b5abd0 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Sat, 10 Apr 2021 19:57:55 +0200
Subject: [PATCH 4/8] CACHE_REQ: fixed REVERSE_INULL warning

Fixes following warning:
```
sssd-2.4.3/src/responder/common/cache_req/cache_req.c:807: check_after_deref: Null-checking "domain" suggests that it may be null, but it has already been dereferenced on all paths leading to the check.
sssd-2.4.3/src/responder/common/cache_req/cache_req.c:784: deref_ptr: Directly dereferencing pointer "domain".
sssd-2.4.3/src/responder/common/cache_req/cache_req.c:790: deref_ptr_in_call: Dereferencing pointer "domain".
sssd-2.4.3/src/responder/common/cache_req/cache_req.c:805: alias: Assigning: "state->selected_domain" = "domain".
 #  805|           state->selected_domain = domain;
 #  806|
 #  807|->         if (domain == NULL) {
 #  808|               break;
 #  809|           }
```
---
 src/responder/common/cache_req/cache_req.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/responder/common/cache_req/cache_req.c b/src/responder/common/cache_req/cache_req.c
index c6902f8424..abff0d4957 100644
--- a/src/responder/common/cache_req/cache_req.c
+++ b/src/responder/common/cache_req/cache_req.c
@@ -777,6 +777,11 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
 
     while (state->cr_domain != NULL) {
         domain = state->cr_domain->domain;
+
+        if (domain == NULL) {
+            break;
+        }
+
         /* As the cr_domain list is a flatten version of the domains
          * list, we have to ensure to only go through the subdomains in
          * case it's specified in the plugin to do so.
@@ -804,10 +809,6 @@ static errno_t cache_req_search_domains_next(struct tevent_req *req)
 
         state->selected_domain = domain;
 
-        if (domain == NULL) {
-            break;
-        }
-
         ret = cache_req_set_domain(cr, domain);
         if (ret != EOK) {
             return ret;

From b5da62904146088abbf34566509851f4d57b9c1c Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Sat, 10 Apr 2021 22:01:59 +0200
Subject: [PATCH 5/8] DEBUG: makes debug backtrace switchable

:config: Introduced new option 'debug_backtrace_enabled' to control
debug backtrace.
---
 src/confdb/confdb.h                  |  1 +
 src/config/SSSDConfig/sssdoptions.py |  1 +
 src/config/SSSDConfigTest.py         |  1 +
 src/config/cfg_rules.ini             | 11 +++++++++++
 src/config/etc/sssd.api.conf         |  1 +
 src/man/sssd.conf.5.xml              | 24 ++++++++++++++++++++++++
 src/util/server.c                    | 12 ++++++++++++
 7 files changed, 51 insertions(+)

diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 0b31ebe00d..56fdfc4785 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -61,6 +61,7 @@
 #define CONFDB_SERVICE_DEBUG_LEVEL_ALIAS "debug"
 #define CONFDB_SERVICE_DEBUG_TIMESTAMPS "debug_timestamps"
 #define CONFDB_SERVICE_DEBUG_MICROSECONDS "debug_microseconds"
+#define CONFDB_SERVICE_DEBUG_BACKTRACE_ENABLED "debug_backtrace_enabled"
 #define CONFDB_SERVICE_RECON_RETRIES "reconnection_retries"
 #define CONFDB_SERVICE_FD_LIMIT "fd_limit"
 #define CONFDB_SERVICE_ALLOWED_UIDS "allowed_uids"
diff --git a/src/config/SSSDConfig/sssdoptions.py b/src/config/SSSDConfig/sssdoptions.py
index 550e63f6ba..696857c1d9 100644
--- a/src/config/SSSDConfig/sssdoptions.py
+++ b/src/config/SSSDConfig/sssdoptions.py
@@ -21,6 +21,7 @@ def __init__(self):
         'debug_level': _('Set the verbosity of the debug logging'),
         'debug_timestamps': _('Include timestamps in debug logs'),
         'debug_microseconds': _('Include microseconds in timestamps in debug logs'),
+        'debug_backtrace_enabled': _('Enable/disable debug backtrace'),
         'timeout': _('Watchdog timeout before restarting service'),
         'command': _('Command to start service'),
         'reconnection_retries': _('Number of times to attempt connection to Data Providers'),
diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py
index bdf4b3759b..0d0f5e49d3 100755
--- a/src/config/SSSDConfigTest.py
+++ b/src/config/SSSDConfigTest.py
@@ -381,6 +381,7 @@ def testListOptions(self):
             'debug_level',
             'debug_timestamps',
             'debug_microseconds',
+            'debug_backtrace_enabled',
             'command',
             'reconnection_retries',
             'fd_limit',
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index c1ea02c6cb..14d3303d41 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -32,6 +32,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -66,6 +67,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -107,6 +109,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -150,6 +153,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -172,6 +176,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -192,6 +197,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -216,6 +222,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -237,6 +244,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -259,6 +267,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -309,6 +318,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
@@ -370,6 +380,7 @@ option = debug
 option = debug_level
 option = debug_timestamps
 option = debug_microseconds
+option = debug_backtrace_enabled
 option = command
 option = reconnection_retries
 option = fd_limit
diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf
index e8fb0195ad..f92f1b090c 100644
--- a/src/config/etc/sssd.api.conf
+++ b/src/config/etc/sssd.api.conf
@@ -8,6 +8,7 @@ debug = int, None, false
 debug_level = int, None, false
 debug_timestamps = bool, None, false
 debug_microseconds = bool, None, false
+debug_backtrace_enabled = bool, None, false
 command = str, None, false
 reconnection_retries = int, None, false
 fd_limit = int, None, false
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
index b3aa927aaa..fc32b04154 100644
--- a/src/man/sssd.conf.5.xml
+++ b/src/man/sssd.conf.5.xml
@@ -147,6 +147,30 @@
                         </para>
                     </listitem>
                 </varlistentry>
+                <varlistentry>
+                    <term>debug_backtrace_enabled (bool)</term>
+                    <listitem>
+                        <para>
+                            Enable debug backtrace.
+                        </para>
+                        <para>
+                            In case SSSD is run with debug_level less than 9,
+                            everything is logged to a ring buffer in memory and
+                            flushed to a log file on any error up to
+                            and including `min(0x0040, debug_level)`
+                            (i.e. if debug_level is explicitly set to 0 or 1 then
+                            only those error levels will trigger backtrace,
+                            otherwise up to 2).
+                        </para>
+                        <para>
+                            Feature is only supported for `logger == files` (i.e.
+                            setting doesn't have effect for other logger types).
+                        </para>
+                        <para>
+                            Default: true
+                        </para>
+                    </listitem>
+                </varlistentry>
               </variablelist>
             </para>
         </refsect2>
diff --git a/src/util/server.c b/src/util/server.c
index 9c4273f305..fa3db39590 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -455,6 +455,7 @@ int server_setup(const char *name, int flags,
     int ret = EOK;
     bool dt;
     bool dm;
+    bool backtrace_enabled;
     struct tevent_signal *tes;
     struct logrotate_ctx *lctx;
     char *locale;
@@ -642,6 +643,17 @@ int server_setup(const char *name, int flags,
         else debug_microseconds = 0;
     }
 
+    ret = confdb_get_bool(ctx->confdb_ctx, conf_entry,
+                          CONFDB_SERVICE_DEBUG_BACKTRACE_ENABLED,
+                          true,
+                          &backtrace_enabled);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Error reading %s from confdb (%d) [%s]\n",
+              CONFDB_SERVICE_DEBUG_BACKTRACE_ENABLED, ret, strerror(ret));
+        return ret;
+    }
+    sss_debug_backtrace_enable(backtrace_enabled);
+
     /* before opening the log file set up log rotation */
     lctx = talloc_zero(ctx, struct logrotate_ctx);
     if (!lctx) return ENOMEM;

From a7edf5f99b8b9ff8d1af3e283bdb37342f7dc3ec Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Sun, 11 Apr 2021 11:55:11 +0200
Subject: [PATCH 6/8] DEBUG: log IMPORTANT_INFO if any bit >= OP_FAILURE is on

This makes sense in general and ensures IMPORTANT_INFO doesn't trigger
backtrace dump.
---
 src/util/debug.h | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/util/debug.h b/src/util/debug.h
index b7e41dd8e4..97564d43e2 100644
--- a/src/util/debug.h
+++ b/src/util/debug.h
@@ -107,7 +107,13 @@ int rotate_debug_files(void);
 #define SSSDBG_TRACE_ALL      0x4000   /* level 9 */
 #define SSSDBG_BE_FO          0x8000   /* level 9 */
 #define SSSDBG_TRACE_LDB     0x10000   /* level 10 */
-#define SSSDBG_IMPORTANT_INFO SSSDBG_OP_FAILURE
+
+/* IMPORTANT_INFO will be logged if any of bits >=  OP_FAILURE are on: */
+#define SSSDBG_IMPORTANT_INFO (SSSDBG_OP_FAILURE|SSSDBG_MINOR_FAILURE|\
+                               SSSDBG_CONF_SETTINGS|SSSDBG_FUNC_DATA|\
+                               SSSDBG_TRACE_FUNC|SSSDBG_TRACE_LIBS|\
+                               SSSDBG_TRACE_INTERNAL|SSSDBG_TRACE_ALL|\
+                               SSSDBG_BE_FO|SSSDBG_TRACE_LDB)
 
 #define SSSDBG_INVALID        -1
 #define SSSDBG_UNRESOLVED      0

From fa69c31f04496a240cb9162ecb796e365445d464 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Sun, 11 Apr 2021 17:24:13 +0200
Subject: [PATCH 7/8] CERTMAP: removed "sss_certmap initialized" debug

Most lib users expect only errors to be logged and provide logger function
with SSSDBG_OP_FAILURE debug level.

Thus "sss_certmap initialized" was triggering backtrace dump for no reason.
---
 src/lib/certmap/sss_certmap.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/lib/certmap/sss_certmap.c b/src/lib/certmap/sss_certmap.c
index f19e577320..d1747f20de 100644
--- a/src/lib/certmap/sss_certmap.c
+++ b/src/lib/certmap/sss_certmap.c
@@ -932,7 +932,6 @@ int sss_certmap_init(TALLOC_CTX *mem_ctx,
         return ret;
     }
 
-    CM_DEBUG((*ctx), "sss_certmap initialized.");
     return EOK;
 }
 

From 55328ecbb7022344b407181328e606a079434727 Mon Sep 17 00:00:00 2001
From: Alexey Tikhonov <[email protected]>
Date: Wed, 14 Apr 2021 14:00:49 +0200
Subject: [PATCH 8/8] SERVER: decrease log level in `orderly_shutdown()` to
 avoid backtrace in this case.

---
 src/util/server.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/util/server.c b/src/util/server.c
index fa3db39590..b6f450a798 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -244,7 +244,7 @@ void orderly_shutdown(int status)
 
     if (sent_sigterm == 0 && getpgrp() == getpid()) {
         debug = is_socket_activated() ? SSSDBG_TRACE_INTERNAL
-                                      : SSSDBG_FATAL_FAILURE;
+                                      : SSSDBG_IMPORTANT_INFO;
         DEBUG(debug, "SIGTERM: killing children\n");
         sent_sigterm = 1;
         kill(-getpgrp(), SIGTERM);
_______________________________________________
sssd-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/[email protected]
Do not reply to spam on the list, report it: 
https://pagure.io/fedora-infrastructure

Reply via email to