s4-dsdb: pass parent request to dsdb_module_*() functions
[samba.git] / source4 / dsdb / samdb / ldb_modules / util.c
index e550630c5dd8eac9f4e108a91d60b0a137cf2be6..e3e908f033dd7384e59b3957c384007d00d2ba0d 100644 (file)
@@ -27,7 +27,6 @@
 #include "dsdb/samdb/samdb.h"
 #include "util.h"
 #include "libcli/security/security.h"
-#include "lib/ldb/include/ldb_private.h"
 #include "libcli/security/session.h"
 
 /*
@@ -38,7 +37,8 @@ int dsdb_module_search_dn(struct ldb_module *module,
                          struct ldb_result **_res,
                          struct ldb_dn *basedn,
                          const char * const *attrs,
-                         uint32_t dsdb_flags)
+                         uint32_t dsdb_flags,
+                         struct ldb_request *parent)
 {
        int ret;
        struct ldb_request *req;
@@ -61,7 +61,7 @@ int dsdb_module_search_dn(struct ldb_module *module,
                                   NULL,
                                   res,
                                   ldb_search_default_callback,
-                                  NULL);
+                                  parent);
        LDB_REQ_SET_LOCATION(req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -74,6 +74,10 @@ int dsdb_module_search_dn(struct ldb_module *module,
                return ret;
        }
 
+       if (dsdb_flags & DSDB_FLAG_TRUSTED) {
+               ldb_req_mark_trusted(req);
+       }
+
        /* Run the new request */
        if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
                ret = ldb_next_request(module, req);
@@ -115,7 +119,8 @@ int dsdb_module_search(struct ldb_module *module,
                       struct ldb_dn *basedn, enum ldb_scope scope, 
                       const char * const *attrs,
                       int dsdb_flags, 
-                      const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
+                      struct ldb_request *parent,
+                      const char *format, ...) _PRINTF_ATTRIBUTE(9, 10)
 {
        int ret;
        struct ldb_request *req;
@@ -153,7 +158,7 @@ int dsdb_module_search(struct ldb_module *module,
                                   NULL,
                                   res,
                                   ldb_search_default_callback,
-                                  NULL);
+                                  parent);
        LDB_REQ_SET_LOCATION(req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -166,6 +171,10 @@ int dsdb_module_search(struct ldb_module *module,
                return ret;
        }
 
+       if (dsdb_flags & DSDB_FLAG_TRUSTED) {
+               ldb_req_mark_trusted(req);
+       }
+
        if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
                ret = ldb_next_request(module, req);
        } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
@@ -191,7 +200,8 @@ int dsdb_module_search(struct ldb_module *module,
   find a DN given a GUID. This searches across all partitions
  */
 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
-                          const struct GUID *guid, struct ldb_dn **dn)
+                          const struct GUID *guid, struct ldb_dn **dn,
+                          struct ldb_request *parent)
 {
        struct ldb_result *res;
        const char *attrs[] = { NULL };
@@ -204,6 +214,7 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
                                 DSDB_SEARCH_SHOW_RECYCLED |
                                 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
                                 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
+                                parent,
                                 "objectGUID=%s", GUID_string(tmp_ctx, guid));
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -229,7 +240,8 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
 /*
   find a GUID given a DN.
  */
-int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
+int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid,
+                          struct ldb_request *parent)
 {
        const char *attrs[] = { NULL };
        struct ldb_result *res;
@@ -240,7 +252,8 @@ int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct
        ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
                                    DSDB_FLAG_NEXT_MODULE |
                                    DSDB_SEARCH_SHOW_RECYCLED |
-                                   DSDB_SEARCH_SHOW_EXTENDED_DN);
+                                   DSDB_SEARCH_SHOW_EXTENDED_DN,
+                                   parent);
        if (ret != LDB_SUCCESS) {
                ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
                                       ldb_dn_get_linearized(dn));
@@ -264,7 +277,8 @@ int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct
  */
 int dsdb_module_modify(struct ldb_module *module,
                       const struct ldb_message *message,
-                      uint32_t dsdb_flags)
+                      uint32_t dsdb_flags,
+                      struct ldb_request *parent)
 {
        struct ldb_request *mod_req;
        int ret;
@@ -283,7 +297,7 @@ int dsdb_module_modify(struct ldb_module *module,
                                NULL,
                                res,
                                ldb_modify_default_callback,
-                               NULL);
+                               parent);
        LDB_REQ_SET_LOCATION(mod_req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -296,6 +310,10 @@ int dsdb_module_modify(struct ldb_module *module,
                return ret;
        }
 
+       if (dsdb_flags & DSDB_FLAG_TRUSTED) {
+               ldb_req_mark_trusted(mod_req);
+       }
+
        /* Run the new request */
        if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
                ret = ldb_next_request(module, mod_req);
@@ -321,8 +339,9 @@ int dsdb_module_modify(struct ldb_module *module,
   current module
  */
 int dsdb_module_rename(struct ldb_module *module,
-                      struct ldb_dn *olddn, struct ldb_dn *newdn,
-                      uint32_t dsdb_flags)
+                      struct ldb_dn *olddn, struct ldb_dn *newdn,
+                      uint32_t dsdb_flags,
+                      struct ldb_request *parent)
 {
        struct ldb_request *req;
        int ret;
@@ -342,7 +361,7 @@ int dsdb_module_rename(struct ldb_module *module,
                                   NULL,
                                   res,
                                   ldb_modify_default_callback,
-                                  NULL);
+                                  parent);
        LDB_REQ_SET_LOCATION(req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -355,6 +374,10 @@ int dsdb_module_rename(struct ldb_module *module,
                return ret;
        }
 
+       if (dsdb_flags & DSDB_FLAG_TRUSTED) {
+               ldb_req_mark_trusted(req);
+       }
+
        /* Run the new request */
        if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
                ret = ldb_next_request(module, req);
@@ -379,7 +402,8 @@ int dsdb_module_rename(struct ldb_module *module,
  */
 int dsdb_module_add(struct ldb_module *module,
                    const struct ldb_message *message,
-                   uint32_t dsdb_flags)
+                   uint32_t dsdb_flags,
+                   struct ldb_request *parent)
 {
        struct ldb_request *req;
        int ret;
@@ -398,7 +422,7 @@ int dsdb_module_add(struct ldb_module *module,
                                NULL,
                                res,
                                ldb_modify_default_callback,
-                               NULL);
+                               parent);
        LDB_REQ_SET_LOCATION(req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -411,6 +435,10 @@ int dsdb_module_add(struct ldb_module *module,
                return ret;
        }
 
+       if (dsdb_flags & DSDB_FLAG_TRUSTED) {
+               ldb_req_mark_trusted(req);
+       }
+
        /* Run the new request */
        if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
                ret = ldb_next_request(module, req);
@@ -435,7 +463,8 @@ int dsdb_module_add(struct ldb_module *module,
  */
 int dsdb_module_del(struct ldb_module *module,
                    struct ldb_dn *dn,
-                   uint32_t dsdb_flags)
+                   uint32_t dsdb_flags,
+                   struct ldb_request *parent)
 {
        struct ldb_request *req;
        int ret;
@@ -454,7 +483,7 @@ int dsdb_module_del(struct ldb_module *module,
                                NULL,
                                res,
                                ldb_modify_default_callback,
-                               NULL);
+                               parent);
        LDB_REQ_SET_LOCATION(req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -467,6 +496,10 @@ int dsdb_module_del(struct ldb_module *module,
                return ret;
        }
 
+       if (dsdb_flags & DSDB_FLAG_TRUSTED) {
+               ldb_req_mark_trusted(req);
+       }
+
        /* Run the new request */
        if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
                ret = ldb_next_request(module, req);
@@ -578,7 +611,7 @@ int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
   (eg. serverReference, rIDManagerReference etc)
  */
 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
-                            const char *attribute, struct ldb_dn **dn)
+                            const char *attribute, struct ldb_dn **dn, struct ldb_request *parent)
 {
        const char *attrs[2];
        struct ldb_result *res;
@@ -588,7 +621,7 @@ int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, str
        attrs[1] = NULL;
 
        ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
-                                   DSDB_FLAG_NEXT_MODULE);
+                                   DSDB_FLAG_NEXT_MODULE, parent);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
@@ -609,11 +642,12 @@ int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, str
   find the RID Manager$ DN via the rIDManagerReference attribute in the
   base DN
  */
-int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
+int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn,
+                              struct ldb_request *parent)
 {
        return dsdb_module_reference_dn(module, mem_ctx,
                                        ldb_get_default_basedn(ldb_module_get_ctx(module)),
-                                       "rIDManagerReference", dn);
+                                       "rIDManagerReference", dn, parent);
 }
 
 /*
@@ -632,7 +666,7 @@ int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
   object for a partition
  */
 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
-                                 uint64_t *uSN, uint64_t *urgent_uSN)
+                                  uint64_t *uSN, uint64_t *urgent_uSN, struct ldb_request *parent)
 {
        struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct ldb_request *req;
@@ -653,7 +687,7 @@ int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
                                   NULL, NULL,
                                   NULL,
                                   res, ldb_search_default_callback,
-                                  NULL);
+                                  parent);
        LDB_REQ_SET_LOCATION(req);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -689,6 +723,7 @@ int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
                   an implicit value of zero */
                *uSN = 0;
                talloc_free(tmp_ctx);
+               ldb_reset_err_string(ldb);
                return LDB_SUCCESS;
        }
 
@@ -719,7 +754,8 @@ int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
   partition
  */
 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
-                                  uint64_t uSN, uint64_t urgent_uSN)
+                                  uint64_t uSN, uint64_t urgent_uSN,
+                                  struct ldb_request *parent)
 {
        struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct ldb_request *req;
@@ -745,7 +781,7 @@ int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
                return ldb_module_oom(module);
        }
 
-       ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
+       ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNHighest", uSN);
        if (ret != LDB_SUCCESS) {
                talloc_free(msg);
                return ret;
@@ -754,7 +790,8 @@ int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
 
        /* urgent_uSN is optional so may not be stored */
        if (urgent_uSN) {
-               ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
+               ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNUrgent",
+                                          urgent_uSN);
                if (ret != LDB_SUCCESS) {
                        talloc_free(msg);
                        return ret;
@@ -775,7 +812,7 @@ int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
                                NULL,
                                res,
                                ldb_modify_default_callback,
-                               NULL);
+                               parent);
        LDB_REQ_SET_LOCATION(req);
 again:
        if (ret != LDB_SUCCESS) {
@@ -803,7 +840,7 @@ again:
                                        NULL,
                                        res,
                                        ldb_modify_default_callback,
-                                       NULL);
+                                       parent);
                LDB_REQ_SET_LOCATION(req);
                goto again;
        }
@@ -977,7 +1014,8 @@ int dsdb_module_constrainted_update_int32(struct ldb_module *module,
                                          struct ldb_dn *dn,
                                          const char *attr,
                                          const int32_t *old_val,
-                                         const int32_t *new_val)
+                                         const int32_t *new_val,
+                                         struct ldb_request *parent)
 {
        struct ldb_message *msg;
        int ret;
@@ -994,7 +1032,7 @@ int dsdb_module_constrainted_update_int32(struct ldb_module *module,
                return ret;
        }
 
-       ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
+       ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
        talloc_free(msg);
        return ret;
 }
@@ -1003,11 +1041,12 @@ int dsdb_module_constrainted_update_uint32(struct ldb_module *module,
                                           struct ldb_dn *dn,
                                           const char *attr,
                                           const uint32_t *old_val,
-                                          const uint32_t *new_val)
+                                          const uint32_t *new_val,
+                                          struct ldb_request *parent)
 {
        return dsdb_module_constrainted_update_int32(module, dn, attr,
                                                     (const int32_t *)old_val,
-                                                    (const int32_t *)new_val);
+                                                    (const int32_t *)new_val, parent);
 }
 
 /*
@@ -1017,7 +1056,8 @@ int dsdb_module_constrainted_update_int64(struct ldb_module *module,
                                          struct ldb_dn *dn,
                                          const char *attr,
                                          const int64_t *old_val,
-                                         const int64_t *new_val)
+                                         const int64_t *new_val,
+                                         struct ldb_request *parent)
 {
        struct ldb_message *msg;
        int ret;
@@ -1034,7 +1074,7 @@ int dsdb_module_constrainted_update_int64(struct ldb_module *module,
                return ret;
        }
 
-       ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
+       ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
        talloc_free(msg);
        return ret;
 }
@@ -1043,21 +1083,23 @@ int dsdb_module_constrainted_update_uint64(struct ldb_module *module,
                                           struct ldb_dn *dn,
                                           const char *attr,
                                           const uint64_t *old_val,
-                                          const uint64_t *new_val)
+                                          const uint64_t *new_val,
+                                          struct ldb_request *parent)
 {
        return dsdb_module_constrainted_update_int64(module, dn, attr,
                                                     (const int64_t *)old_val,
-                                                    (const int64_t *)new_val);
+                                                    (const int64_t *)new_val,
+                                                    parent);
 }
 
 
 const struct ldb_val *dsdb_module_find_dsheuristics(struct ldb_module *module,
-                                                   TALLOC_CTX *mem_ctx)
+                                                   TALLOC_CTX *mem_ctx, struct ldb_request *parent)
 {
        int ret;
        struct ldb_dn *new_dn;
        struct ldb_context *ldb = ldb_module_get_ctx(module);
-       static const char *attrs[] = { "dsHeuristics", NULL };
+       static const char *attrs[] = { "dSHeuristics", NULL };
        struct ldb_result *res;
 
        new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(ldb));
@@ -1069,23 +1111,23 @@ const struct ldb_val *dsdb_module_find_dsheuristics(struct ldb_module *module,
        ret = dsdb_module_search_dn(module, mem_ctx, &res,
                                    new_dn,
                                    attrs,
-                                   DSDB_FLAG_NEXT_MODULE);
+                                   DSDB_FLAG_NEXT_MODULE,
+                                   parent);
        if (ret == LDB_SUCCESS && res->count == 1) {
                talloc_free(new_dn);
                return ldb_msg_find_ldb_val(res->msgs[0],
-                                           "dsHeuristics");
+                                           "dSHeuristics");
        }
        talloc_free(new_dn);
        return NULL;
 }
 
-bool dsdb_block_anonymous_ops(struct ldb_module *module,
-                             TALLOC_CTX *mem_ctx)
+bool dsdb_block_anonymous_ops(struct ldb_module *module, struct ldb_request *parent)
 {
-       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       TALLOC_CTX *tmp_ctx = talloc_new(module);
        bool result;
        const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
-                                                                    tmp_ctx);
+                                                                    tmp_ctx, parent);
        if (hr_val == NULL || hr_val->length < DS_HR_BLOCK_ANONYMOUS_OPS) {
                result = true;
        } else if (hr_val->data[DS_HR_BLOCK_ANONYMOUS_OPS -1] == '2') {
@@ -1098,15 +1140,68 @@ bool dsdb_block_anonymous_ops(struct ldb_module *module,
        return result;
 }
 
+bool dsdb_user_password_support(struct ldb_module *module,
+                               TALLOC_CTX *mem_ctx,
+                               struct ldb_request *parent)
+{
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       bool result;
+       const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
+                                                                    tmp_ctx,
+                                                                    parent);
+       if (hr_val == NULL || hr_val->length < DS_HR_USER_PASSWORD_SUPPORT) {
+               result = false;
+       } else if ((hr_val->data[DS_HR_USER_PASSWORD_SUPPORT -1] == '2') ||
+                  (hr_val->data[DS_HR_USER_PASSWORD_SUPPORT -1] == '0')) {
+               result = false;
+       } else {
+               result = true;
+       }
+
+       talloc_free(tmp_ctx);
+       return result;
+}
+
 /*
   show the chain of requests, useful for debugging async requests
  */
 void dsdb_req_chain_debug(struct ldb_request *req, int level)
 {
-       int i=0;
+       char *s = ldb_module_call_chain(req, req);
+       DEBUG(level, ("%s\n", s));
+       talloc_free(s);
+}
 
-       while (req && req->handle) {
-               DEBUG(level,("req[%u] %p  : %s\n", i++, req, ldb_req_location(req)));
-               req = req->handle->parent;
+/*
+ * Gets back a single-valued attribute by the rules of the DSDB triggers when
+ * performing a modify operation.
+ *
+ * In order that the constraint checking by the "objectclass_attrs" LDB module
+ * does work properly, the change request should remain similar or only be
+ * enhanced (no other modifications as deletions, variations).
+ */
+struct ldb_message_element *dsdb_get_single_valued_attr(const struct ldb_message *msg,
+                                                       const char *attr_name,
+                                                       enum ldb_request_type operation)
+{
+       struct ldb_message_element *el = NULL;
+       unsigned int i;
+
+       /* We've to walk over all modification entries and consider the last
+        * non-delete one which belongs to "attr_name".
+        *
+        * If "el" is NULL afterwards then that means there was no interesting
+        * change entry. */
+       for (i = 0; i < msg->num_elements; i++) {
+               if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
+                       if ((operation == LDB_MODIFY) &&
+                           (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
+                                               == LDB_FLAG_MOD_DELETE)) {
+                               continue;
+                       }
+                       el = &msg->elements[i];
+               }
        }
+
+       return el;
 }