s4/ldb:introduce the LDB_CONTROL_PROVISION_OID control
[samba.git] / source4 / dsdb / common / util.c
index a5d0f60f517c022c56034a1314d50af0e6c3667e..9b813d1b52784909eba9d94ca2632ecb10a43efd 100644 (file)
@@ -42,7 +42,6 @@
 #include "lib/util/tsort.h"
 #include "dsdb/common/util.h"
 #include "lib/socket/socket.h"
-#include "dsdb/samdb/ldb_modules/util.h"
 #include "librpc/gen_ndr/irpc.h"
 
 /*
@@ -112,7 +111,7 @@ const char *samdb_search_string_v(struct ldb_context *sam_ldb,
                return NULL;
        }
 
-       return samdb_result_string(res[0], attr_name, NULL);
+       return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
 }
 
 /*
@@ -236,7 +235,7 @@ unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
                return default_value;
        }
 
-       return samdb_result_uint(res[0], attr_name, default_value);
+       return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
 }
 
 /*
@@ -264,7 +263,7 @@ int64_t samdb_search_int64(struct ldb_context *sam_ldb,
                return default_value;
        }
 
-       return samdb_result_int64(res[0], attr_name, default_value);
+       return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
 }
 
 /*
@@ -310,38 +309,13 @@ int samdb_search_string_multiple(struct ldb_context *sam_ldb,
        }
 
        for (i=0;i<count;i++) {
-               (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
+               (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
        }
        (*strs)[count] = NULL;
 
        return count;
 }
 
-/*
-  pull a uint from a result set. 
-*/
-unsigned int samdb_result_uint(const struct ldb_message *msg, const char *attr, unsigned int default_value)
-{
-       return ldb_msg_find_attr_as_uint(msg, attr, default_value);
-}
-
-/*
-  pull a (signed) int64 from a result set. 
-*/
-int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
-{
-       return ldb_msg_find_attr_as_int64(msg, attr, default_value);
-}
-
-/*
-  pull a string from a result set. 
-*/
-const char *samdb_result_string(const struct ldb_message *msg, const char *attr, 
-                               const char *default_value)
-{
-       return ldb_msg_find_attr_as_string(msg, attr, default_value);
-}
-
 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
                               const char *attr, struct ldb_dn *default_value)
 {
@@ -477,16 +451,6 @@ NTTIME samdb_result_account_expires(const struct ldb_message *msg)
        return ret;
 }
 
-/*
-  pull a uint64_t from a result set. 
-*/
-uint64_t samdb_result_uint64(const struct ldb_message *msg, const char *attr,
-                            uint64_t default_value)
-{
-       return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
-}
-
-
 /*
   construct the allow_password_change field from the PwdLastSet attribute and the 
   domain password settings
@@ -497,7 +461,7 @@ NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
                                          struct ldb_message *msg, 
                                          const char *attr)
 {
-       uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
+       uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
        int64_t minPwdAge;
 
        if (attr_time == 0) {
@@ -522,7 +486,7 @@ NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
                                          struct ldb_dn *domain_dn, 
                                          struct ldb_message *msg)
 {
-       int64_t attr_time = samdb_result_int64(msg, "pwdLastSet", 0);
+       int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
        uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
                                                                "userAccountControl",
                                                                0);
@@ -806,12 +770,11 @@ int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg
 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
                         const char *attr_name, const char *str)
 {
-       char *s = talloc_strdup(mem_ctx, str);
-       char *a = talloc_strdup(mem_ctx, attr_name);
-       if (s == NULL || a == NULL) {
+       const char *s = talloc_strdup(mem_ctx, str);
+       if (s == NULL) {
                return ldb_oom(sam_ldb);
        }
-       return ldb_msg_add_string(msg, a, s);
+       return ldb_msg_add_string(msg, attr_name, s);
 }
 
 /*
@@ -963,12 +926,24 @@ int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct l
                       const char *attr_name, int v)
 {
        const char *s = talloc_asprintf(mem_ctx, "%d", v);
-       return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
+       if (s == NULL) {
+               return ldb_oom(sam_ldb);
+       }
+       return ldb_msg_add_string(msg, attr_name, s);
 }
 
 /*
-  add a unsigned int element to a message
-*/
+ * Add an unsigned int element to a message
+ *
+ * The issue here is that we have not yet first cast to int32_t explicitly,
+ * before we cast to an signed int to printf() into the %d or cast to a
+ * int64_t before we then cast to a long long to printf into a %lld.
+ *
+ * There are *no* unsigned integers in Active Directory LDAP, even the RID
+ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
+ * (See the schema, and the syntax definitions in schema_syntax.c).
+ *
+ */
 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
                       const char *attr_name, unsigned int v)
 {
@@ -982,12 +957,24 @@ int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct
                        const char *attr_name, int64_t v)
 {
        const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
-       return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
+       if (s == NULL) {
+               return ldb_oom(sam_ldb);
+       }
+       return ldb_msg_add_string(msg, attr_name, s);
 }
 
 /*
-  add a uint64_t element to a message
-*/
+ * Add an unsigned int64_t (uint64_t) element to a message
+ *
+ * The issue here is that we have not yet first cast to int32_t explicitly,
+ * before we cast to an signed int to printf() into the %d or cast to a
+ * int64_t before we then cast to a long long to printf into a %lld.
+ *
+ * There are *no* unsigned integers in Active Directory LDAP, even the RID
+ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
+ * (See the schema, and the syntax definitions in schema_syntax.c).
+ *
+ */
 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
                        const char *attr_name, uint64_t v)
 {
@@ -1062,14 +1049,6 @@ int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, s
        val.data = (uint8_t *)parameters->array;
        return ldb_msg_add_value(msg, attr_name, &val, NULL);
 }
-/*
-  add a general value element to a message
-*/
-int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
-                             const char *attr_name, const struct ldb_val *val)
-{
-       return ldb_msg_add_value(msg, attr_name, val, NULL);
-}
 
 /*
   sets a general value element to a message
@@ -1101,6 +1080,46 @@ int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struc
        return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
 }
 
+/*
+ * sets a signed integer in a message
+ */
+int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+                     struct ldb_message *msg, const char *attr_name, int v)
+{
+       struct ldb_message_element *el;
+
+       el = ldb_msg_find_element(msg, attr_name);
+       if (el) {
+               el->num_values = 0;
+       }
+       return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
+}
+
+/*
+ * Sets an unsigned int element in a message
+ *
+ * The issue here is that we have not yet first cast to int32_t explicitly,
+ * before we cast to an signed int to printf() into the %d or cast to a
+ * int64_t before we then cast to a long long to printf into a %lld.
+ *
+ * There are *no* unsigned integers in Active Directory LDAP, even the RID
+ * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
+ * (See the schema, and the syntax definitions in schema_syntax.c).
+ *
+ */
+int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
+                      struct ldb_message *msg, const char *attr_name,
+                      unsigned int v)
+{
+       struct ldb_message_element *el;
+
+       el = ldb_msg_find_element(msg, attr_name);
+       if (el) {
+               el->num_values = 0;
+       }
+       return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
+}
+
 /*
  * Handle ldb_request in transaction
  */
@@ -2099,8 +2118,8 @@ NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
        if ((new_password != NULL)
                        && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
                /* we have the password as plaintext UTF16 */
-               CHECK_RET(samdb_msg_add_value(ldb, mem_ctx, msg,
-                       "clearTextPassword", new_password));
+               CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
+                                           new_password, NULL));
                el = ldb_msg_find_element(msg, "clearTextPassword");
                el->flags = LDB_FLAG_MOD_REPLACE;
        } else if ((new_password == NULL)
@@ -2352,9 +2371,12 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA
                return NT_STATUS_NO_MEMORY;
        }
 
-       samdb_msg_add_string(sam_ctx, msg, msg,
-                            "objectClass",
-                            "foreignSecurityPrincipal");
+       ret = samdb_msg_add_string(sam_ctx, msg, msg,
+                                  "objectClass", "foreignSecurityPrincipal");
+       if (ret != LDB_SUCCESS) {
+               talloc_free(sidstr);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* create the alias */
        ret = ldb_add(sam_ctx, msg);
@@ -2516,7 +2538,9 @@ int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
        attrs[0] = attribute;
        attrs[1] = NULL;
 
-       ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
+       ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
+                            DSDB_SEARCH_SHOW_DELETED |
+                            DSDB_SEARCH_SHOW_RECYCLED);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
                return ret;
@@ -2590,7 +2614,9 @@ int dsdb_find_sid_by_dn(struct ldb_context *ldb,
 
        ZERO_STRUCTP(sid);
 
-       ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
+       ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
+                            DSDB_SEARCH_SHOW_DELETED |
+                            DSDB_SEARCH_SHOW_RECYCLED);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
                return ret;
@@ -2802,7 +2828,7 @@ int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
        }
 
-       if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+       if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
                /* it hasn't been created yet, which means
                   an implicit value of zero */
                *uSN = 0;
@@ -2990,7 +3016,7 @@ int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
                goto failed;
        }
 
-       *options = samdb_result_uint(res->msgs[0], "options", 0);
+       *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
 
        talloc_free(tmp_ctx);
 
@@ -3017,7 +3043,7 @@ const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *
                goto failed;
        }
 
-       return samdb_result_string(res->msgs[0], "objectCategory", NULL);
+       return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
 
 failed:
        DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
@@ -3059,7 +3085,8 @@ int dsdb_functional_level(struct ldb_context *ldb)
        int *domainFunctionality =
                talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
        if (!domainFunctionality) {
-               DEBUG(0,(__location__ ": WARNING: domainFunctionality not setup\n"));
+               /* this is expected during initial provision */
+               DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
                return DS_DOMAIN_FUNCTION_2000;
        }
        return *domainFunctionality;
@@ -3221,7 +3248,7 @@ uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
        if (val->length < 13) {
                return 0;
        }
-       p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
+       p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
        if (!p) {
                return 0;
        }
@@ -3271,7 +3298,9 @@ int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
                return ldb_operr(samdb);
        }
 
-       ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs, DSDB_SEARCH_SHOW_DELETED);
+       ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
+                            DSDB_SEARCH_SHOW_DELETED |
+                            DSDB_SEARCH_SHOW_RECYCLED);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
                return ret;
@@ -3569,6 +3598,13 @@ int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
                }
        }
 
+       if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
+               ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
        if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
                ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
                if (ret != LDB_SUCCESS) {
@@ -3624,6 +3660,13 @@ int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
                }
        }
 
+       if (dsdb_flags & DSDB_PROVISION) {
+               ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
        return LDB_SUCCESS;
 }
 
@@ -3758,6 +3801,32 @@ int dsdb_search_dn(struct ldb_context *ldb,
        return LDB_SUCCESS;
 }
 
+/*
+  search for attrs on one DN, by the GUID of the DN, allowing for
+  dsdb_flags controls
+ */
+int dsdb_search_by_dn_guid(struct ldb_context *ldb,
+                          TALLOC_CTX *mem_ctx,
+                          struct ldb_result **_res,
+                          const struct GUID *guid,
+                          const char * const *attrs,
+                          uint32_t dsdb_flags)
+{
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
+       struct ldb_dn *dn;
+       int ret;
+
+       dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
+       if (!ldb_dn_validate(dn)) {
+               talloc_free(tmp_ctx);
+               return LDB_ERR_INVALID_DN_SYNTAX;
+       }
+
+       ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
+       talloc_free(tmp_ctx);
+       return ret;
+}
+
 /*
   general search with dsdb_flags for controls
  */
@@ -4134,7 +4203,7 @@ const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
                return NULL;
        }
 
-       return samdb_result_string(res->msgs[0], "dNSHostName", NULL);
+       return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
 }
 
 /*
@@ -4182,3 +4251,15 @@ bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
        return false;
 }
 
+bool is_attr_in_list(const char * const * attrs, const char *attr)
+{
+       unsigned int i;
+
+       for (i = 0; attrs[i]; i++) {
+               if (ldb_attr_cmp(attrs[i], attr) == 0)
+                       return true;
+       }
+
+       return false;
+}
+