ldb: Ensure to decrement the transaction_active whenever we delete a transaction
[metze/samba/wip.git] / lib / ldb / common / ldb.c
index a4c04cec4614871877b8b13a1517265602ac60a4..3dc6d872289e1374f23f1f0c89b364321ec5b360 100644 (file)
@@ -60,7 +60,6 @@ static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
 {
        struct ldb_context *ldb = talloc_get_type(context, struct ldb_context);
        enum ldb_debug_level ldb_level = LDB_DEBUG_FATAL;
-       char *s = NULL;
 
        switch (level) {
        case TEVENT_DEBUG_FATAL:
@@ -77,10 +76,10 @@ static void ldb_tevent_debug(void *context, enum tevent_debug_level level,
                break;
        };
 
-       vasprintf(&s, fmt, ap);
-       if (!s) return;
-       ldb_debug(ldb, ldb_level, "tevent: %s", s);
-       free(s);
+       /* There isn't a tevent: prefix here because to add it means
+        * actually printing the string, and most of the time we don't
+        * want to show it */
+       ldb_vdebug(ldb, ldb_level, fmt, ap);
 }
 
 /*
@@ -269,28 +268,25 @@ int ldb_connect(struct ldb_context *ldb, const char *url,
 
 void ldb_set_errstring(struct ldb_context *ldb, const char *err_string)
 {
-       if (ldb->err_string) {
-               talloc_free(ldb->err_string);
-       }
-       ldb->err_string = talloc_strdup(ldb, err_string);
-       if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
-               ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_set_errstring: %s", ldb->err_string);
-       }
+       ldb_asprintf_errstring(ldb, "%s", err_string);
 }
 
 void ldb_asprintf_errstring(struct ldb_context *ldb, const char *format, ...)
 {
        va_list ap;
-       char *old_string = NULL;
 
        if (ldb->err_string) {
-               old_string = ldb->err_string;
+               talloc_free(ldb->err_string);
        }
 
        va_start(ap, format);
        ldb->err_string = talloc_vasprintf(ldb, format, ap);
        va_end(ap);
-       talloc_free(old_string);
+
+       if (ldb->flags & LDB_FLG_ENABLE_TRACING) {
+               ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_asprintf/set_errstring: %s",
+                         ldb->err_string);
+       }
 }
 
 void ldb_reset_err_string(struct ldb_context *ldb)
@@ -412,6 +408,7 @@ int ldb_transaction_prepare_commit(struct ldb_context *ldb)
 
        status = module->ops->prepare_commit(module);
        if (status != LDB_SUCCESS) {
+               ldb->transaction_active--;
                /* if a module fails the prepare then we need
                   to call the end transaction for everyone */
                FIRST_OP(ldb, del_transaction);
@@ -546,7 +543,7 @@ int ldb_transaction_cancel_noerr(struct ldb_context *ldb)
 }
 
 
-/* autostarts a transacion if none active */
+/* autostarts a transaction if none active */
 static int ldb_autotransaction_request(struct ldb_context *ldb,
                                       struct ldb_request *req)
 {
@@ -567,11 +564,6 @@ static int ldb_autotransaction_request(struct ldb_context *ldb,
        }
        ldb_transaction_cancel(ldb);
 
-       if (ldb->err_string == NULL) {
-               /* no error string was setup by the backend */
-               ldb_asprintf_errstring(ldb, "%s (%d)", ldb_strerror(ret), ret);
-       }
-
        return ret;
 }
 
@@ -581,26 +573,41 @@ int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
        int ret;
 
        if (!handle) {
-               return LDB_ERR_UNAVAILABLE;
+               return ldb_error(handle->ldb, LDB_ERR_UNAVAILABLE, NULL);
        }
 
        if (handle->state == LDB_ASYNC_DONE) {
+               if ((handle->status != LDB_SUCCESS) &&
+                   (handle->ldb->err_string == NULL)) {
+                       /* if no error string was setup by the backend */
+                       ldb_asprintf_errstring(handle->ldb, "ldb_wait: %s (%d)",
+                                              ldb_strerror(handle->status),
+                                              handle->status);
+               }
                return handle->status;
        }
 
        ev = ldb_get_event_context(handle->ldb);
        if (NULL == ev) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               return ldb_oom(handle->ldb);
        }
 
        switch (type) {
        case LDB_WAIT_NONE:
                ret = tevent_loop_once(ev);
                if (ret != 0) {
-                       return LDB_ERR_OPERATIONS_ERROR;
+                       return ldb_operr(handle->ldb);
                }
-               if (handle->state == LDB_ASYNC_DONE ||
-                   handle->status != LDB_SUCCESS) {
+               if (handle->status != LDB_SUCCESS) {
+                       if (handle->ldb->err_string == NULL) {
+                               /*
+                                * if no error string was setup by the backend
+                                */
+                               ldb_asprintf_errstring(handle->ldb,
+                                                      "ldb_wait: %s (%d)",
+                                                      ldb_strerror(handle->status),
+                                                      handle->status);
+                       }
                        return handle->status;
                }
                break;
@@ -609,13 +616,35 @@ int ldb_wait(struct ldb_handle *handle, enum ldb_wait_type type)
                while (handle->state != LDB_ASYNC_DONE) {
                        ret = tevent_loop_once(ev);
                        if (ret != 0) {
-                               return LDB_ERR_OPERATIONS_ERROR;
+                               return ldb_operr(handle->ldb);
                        }
                        if (handle->status != LDB_SUCCESS) {
+                               if  (handle->ldb->err_string == NULL) {
+                                       /*
+                                        * if no error string was setup by the
+                                        * backend
+                                        */
+                                       ldb_asprintf_errstring(handle->ldb,
+                                                              "ldb_wait: %s (%d)",
+                                                              ldb_strerror(handle->status),
+                                                              handle->status);
+                               }
                                return handle->status;
                        }
                }
-               return handle->status;
+               if (handle->status != LDB_SUCCESS) {
+                       if (handle->ldb->err_string == NULL) {
+                               /*
+                                * if no error string was setup by the backend
+                                */
+                               ldb_asprintf_errstring(handle->ldb,
+                                                      "ldb_wait: %s (%d)",
+                                                      ldb_strerror(handle->status),
+                                                      handle->status);
+                       }
+                       return handle->status;
+               }
+               break;
        }
 
        return LDB_SUCCESS;
@@ -698,6 +727,7 @@ static void ldb_trace_request(struct ldb_context *ldb, struct ldb_request *req)
 {
        TALLOC_CTX *tmp_ctx = talloc_new(req);
        unsigned int i;
+       struct ldb_ldif ldif;
 
        switch (req->operation) {
        case LDB_SEARCH:
@@ -737,18 +767,36 @@ static void ldb_trace_request(struct ldb_context *ldb, struct ldb_request *req)
                ldb_debug_add(ldb, " data: %s\n", req->op.extended.data?"yes":"no");
                break;
        case LDB_ADD:
+               ldif.changetype = LDB_CHANGETYPE_ADD;
+               ldif.msg = discard_const_p(struct ldb_message, req->op.add.message);
+
                ldb_debug_add(ldb, "ldb_trace_request: ADD\n");
+
+               /* 
+                * The choice to call
+                * ldb_ldif_write_redacted_trace_string() is CRITICAL
+                * for security.  It ensures that we do not output
+                * passwords into debug logs 
+                */
+
                ldb_debug_add(req->handle->ldb, "%s\n", 
-                             ldb_ldif_message_string(req->handle->ldb, tmp_ctx, 
-                                                     LDB_CHANGETYPE_ADD, 
-                                                     req->op.add.message));
+                             ldb_ldif_write_redacted_trace_string(req->handle->ldb, tmp_ctx, &ldif));
                break;
        case LDB_MODIFY:
+               ldif.changetype = LDB_CHANGETYPE_MODIFY;
+               ldif.msg = discard_const_p(struct ldb_message, req->op.mod.message);
+
                ldb_debug_add(ldb, "ldb_trace_request: MODIFY\n");
+
+               /* 
+                * The choice to call
+                * ldb_ldif_write_redacted_trace_string() is CRITICAL
+                * for security.  It ensures that we do not output
+                * passwords into debug logs 
+                */
+
                ldb_debug_add(req->handle->ldb, "%s\n", 
-                             ldb_ldif_message_string(req->handle->ldb, tmp_ctx, 
-                                                     LDB_CHANGETYPE_ADD, 
-                                                     req->op.mod.message));
+                             ldb_ldif_write_redacted_trace_string(req->handle->ldb, tmp_ctx, &ldif));
                break;
        case LDB_REQ_REGISTER_CONTROL:
                ldb_debug_add(ldb, "ldb_trace_request: REGISTER_CONTROL\n");
@@ -851,11 +899,15 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
                                        discard_const(&req->op.add.message));
                if (ret != LDB_SUCCESS) {
                        ldb_oom(ldb);
-                       return LDB_ERR_OPERATIONS_ERROR;
+                       return ret;
                }
                FIRST_OP(ldb, add);
                ret = ldb_msg_check_element_flags(ldb, req->op.add.message);
                if (ret != LDB_SUCCESS) {
+                       /*
+                        * "ldb_msg_check_element_flags" generates an error
+                        * string
+                        */
                        return ret;
                }
                ret = module->ops->add(module, req);
@@ -869,6 +921,10 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
                FIRST_OP(ldb, modify);
                ret = ldb_msg_check_element_flags(ldb, req->op.mod.message);
                if (ret != LDB_SUCCESS) {
+                       /*
+                        * "ldb_msg_check_element_flags" generates an error
+                        * string
+                        */
                        return ret;
                }
                ret = module->ops->modify(module, req);
@@ -906,6 +962,12 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *req)
                break;
        }
 
+       if ((ret != LDB_SUCCESS) && (ldb->err_string == NULL)) {
+               /* if no error string was setup by the backend */
+               ldb_asprintf_errstring(ldb, "ldb_request: %s (%d)",
+                                      ldb_strerror(ret), ret);
+       }
+
        return ret;
 }
 
@@ -1026,7 +1088,7 @@ int ldb_modify_default_callback(struct ldb_request *req, struct ldb_reply *ares)
                return ldb_request_done(req, LDB_SUCCESS);
        default:
                talloc_free(ares);
-               ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+               ldb_asprintf_errstring(req->handle->ldb, "Invalid LDB reply type %d", ares->type);
                return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
        }
 
@@ -1050,7 +1112,7 @@ int ldb_op_default_callback(struct ldb_request *req, struct ldb_reply *ares)
 
        if (ares->type != LDB_REPLY_DONE) {
                talloc_free(ares);
-               ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+               ldb_asprintf_errstring(req->handle->ldb, "Invalid LDB reply type %d", ares->type);
                return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
        }
 
@@ -1356,7 +1418,7 @@ int ldb_extended_default_callback(struct ldb_request *req,
        }
 
        talloc_free(ares);
-       ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+       ldb_asprintf_errstring(req->handle->ldb, "Invalid LDB reply type %d", ares->type);
        return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
 }
 
@@ -1919,7 +1981,7 @@ uint32_t ldb_req_get_custom_flags(struct ldb_request *req)
 
 
 /**
  return true is a request is untrusted
* return true if a request is untrusted
  */
 bool ldb_req_is_untrusted(struct ldb_request *req)
 {