From ffee5d4dc48959a8a305082f54e924a3055d54f4 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Tue, 9 Aug 2011 14:13:14 +0200
Subject: [PATCH] Allow more libldap debugging

When the user exports an openldap-compatible debug level in the
SSSD_DEBUG_LDAP_SEARCH environment variable, it would be used for the
duration of ldap_search_ext call and reset afterwards.
---
 src/providers/ldap/sdap_async.c |   12 ++++++
 src/util/debug.c                |   53 +++++++++++++++++++++++++
 src/util/sss_ldap.c             |   83 ++++++++++++++++++++++++++++++++++++++-
 src/util/sss_ldap.h             |    2 +
 src/util/util.h                 |    3 +
 5 files changed, 152 insertions(+), 1 deletions(-)

diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index ebd8d48..30aa588 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -755,6 +755,8 @@ struct sdap_get_generic_state {
     size_t reply_max;
     size_t reply_count;
     struct sysdb_attrs **reply;
+
+    int old_ldap_debug;
 };
 
 static errno_t add_to_reply(struct sdap_get_generic_state *state,
@@ -800,6 +802,7 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
     state->reply_max = 0;
     state->reply_count = 0;
     state->reply = NULL;
+    state->old_ldap_debug = 0;
 
     DEBUG(6, ("calling ldap_search_ext with [%s][%s].\n", state->filter,
                                                           state->search_base));
@@ -813,6 +816,12 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
         }
     }
 
+    ret = sss_ldap_set_debug(&state->old_ldap_debug);
+    if (ret != EOK) {
+        DEBUG(2, ("Could not set extra LDAP debugging\n"));
+        /* Not fatal, carry on */
+    }
+
     lret = ldap_search_ext(state->sh->ldap, state->search_base,
                            state->scope, state->filter,
                            discard_const(state->attrs),
@@ -853,6 +862,7 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
     return req;
 
 fail:
+    sss_ldap_reset_debug(state->old_ldap_debug);
     tevent_req_error(req, ret);
     tevent_req_post(req, ev);
     return req;
@@ -871,6 +881,8 @@ static void sdap_get_generic_done(struct sdap_op *op,
     int result;
     int ret;
 
+    sss_ldap_reset_debug(state->old_ldap_debug);
+
     if (error) {
         tevent_req_error(req, error);
         return;
diff --git a/src/util/debug.c b/src/util/debug.c
index 1b78eba..49d4caf 100644
--- a/src/util/debug.c
+++ b/src/util/debug.c
@@ -194,3 +194,56 @@ int rotate_debug_files(void)
 
     return open_debug_file();
 }
+
+int reopen_stderr_for_libldap(const char *filename)
+{
+    int ret;
+    char *logpath;
+    const char *log_file;
+    FILE *new_stderr;
+    TALLOC_CTX *tmp_ctx;
+
+    if (!debug_to_file) return EOK;
+
+    tmp_ctx = talloc_new(NULL);
+    if (!tmp_ctx) return ENOMEM;
+
+    log_file = filename ? filename : debug_log_file;
+
+    logpath = talloc_asprintf(tmp_ctx, "%s/%s.log", LOG_PATH, log_file);
+    if (logpath == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    fclose(stderr);
+    new_stderr = freopen(logpath, "a", stderr);
+    if (!new_stderr) {
+        ret = errno;
+        DEBUG(1, ("Couldn't reopen stderr to logfile\n"));
+        goto done;
+    }
+
+    ret = EOK;
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+int reopen_stderr_after_libldap(void)
+{
+    FILE *new_stderr;
+    int ret;
+
+    if (!debug_to_file) return EOK;
+
+    new_stderr = freopen("/dev/null", "a", stderr);
+    if (!new_stderr) {
+        ret = errno;
+        DEBUG(1, ("Couldn't reopen stderr to logfile\n"));
+        return ret;
+    }
+
+    return EOK;
+}
+
diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
index f098e7d..99d5592 100644
--- a/src/util/sss_ldap.c
+++ b/src/util/sss_ldap.c
@@ -22,7 +22,7 @@
 #include "config.h"
 
 #include "util/sss_ldap.h"
-
+#include "util/util.h"
 
 int sss_ldap_control_create(const char *oid, int iscritical,
                             struct berval *value, int dupval,
@@ -68,3 +68,84 @@ int sss_ldap_control_create(const char *oid, int iscritical,
     return LDAP_SUCCESS;
 #endif
 }
+
+int sss_ldap_set_debug(int *old_debug)
+{
+    const char *dbg;
+    static const char dbg_var[] = "SSSD_DEBUG_LDAP_SEARCH";
+    int ret;
+    int new_debug;
+    int ldap_old_debug;
+    char *endptr;
+
+    dbg = getenv(dbg_var);
+    if (!dbg){
+        DEBUG(7, ("No extra LDAP debugging set\n"));
+        return EOK;
+    }
+
+    new_debug = strtol(dbg, &endptr, 16);
+    if (errno != 0) {
+        ret = errno;
+        DEBUG(1, ("strtol failed on [%s]: [%d][%s].\n", dbg,
+                  ret, strerror(ret)));
+        return ret;
+    }
+
+    if (*endptr != '\0') {
+        DEBUG(1, ("Found additional characters [%s] in debug level"
+                  "[%s].\n", endptr, dbg));
+        return EINVAL;
+    }
+
+    ret = reopen_stderr_for_libldap(NULL);
+    if (ret != EOK) {
+        DEBUG(4, ("Could not redirect stderr to log file\n"));
+        return ret;
+    }
+
+    ret = ldap_get_option(NULL, LDAP_OPT_DEBUG_LEVEL,
+                          &ldap_old_debug);
+    if (ret != LDAP_OPT_SUCCESS) {
+        DEBUG(3, ("Could not save old LDAP debug level\n"));
+        return EIO;
+    }
+
+    DEBUG(8, ("LDAP debug level was %#X setting to %#X\n",
+              ldap_old_debug, new_debug));
+
+    ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL,
+                          &new_debug);
+    if (ret != LDAP_OPT_SUCCESS) {
+        DEBUG(3, ("Could not set LDAP debugging\n"));
+        return EIO;
+    }
+
+    if (old_debug) *old_debug = ldap_old_debug;
+
+    return EOK;
+}
+
+int sss_ldap_reset_debug(int ldap_old_debug)
+{
+    int ret;
+
+    ret = reopen_stderr_after_libldap();
+    if (ret != EOK) {
+        DEBUG(4, ("Could not redirect stderr back to /dev/null\n"));
+        return ret;
+    }
+
+    ret = ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL,
+                          &ldap_old_debug);
+    if (ret != LDAP_SUCCESS) {
+        DEBUG(3, ("Could not reset LDAP debugging\n"));
+        return EIO;
+    }
+
+    DEBUG(8, ("Resetting LDAP debug level to %#X\n",
+              ldap_old_debug));
+
+    return EOK;
+}
+
diff --git a/src/util/sss_ldap.h b/src/util/sss_ldap.h
index 14747df..3ed9005 100644
--- a/src/util/sss_ldap.h
+++ b/src/util/sss_ldap.h
@@ -26,5 +26,7 @@
 int sss_ldap_control_create(const char *oid, int iscritical,
                             struct berval *value, int dupval,
                             LDAPControl **ctrlp);
+int sss_ldap_set_debug(int *old_debug);
+int sss_ldap_reset_debug(int ldap_old_debug);
 
 #endif /* __SSS_LDAP_H__ */
diff --git a/src/util/util.h b/src/util/util.h
index 61fe7f6..5a7caed 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -240,6 +240,9 @@ void ldb_debug_messages(void *context, enum ldb_debug_level level,
 int open_debug_file_ex(const char *filename, FILE **filep);
 int open_debug_file(void);
 int rotate_debug_files(void);
+int reopen_stderr_for_libldap(const char *filename);
+int reopen_stderr_after_libldap(void);
+
 
 /* From sss_log.c */
 #define SSS_LOG_EMERG   0   /* system is unusable */
-- 
1.7.6

