s4-dsdb: added dsdb_load_udv_v2() and dsdb_load_udv_v1()
[ira/wip.git] / source4 / dsdb / common / util.c
index 5d9ec1182f8e1007672a7b9d832941f3b9fd5575..0aad31580188f71ea9d2ac1b32d1fb2d3152bc86 100644 (file)
@@ -686,7 +686,7 @@ struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
        if (!s.array) {
                return s;
        }
-       s.length = s.size = val->length/2;
+       s.length = s.size = val->length;
        memcpy(s.array, val->data, val->length);
 
        return s;
@@ -851,8 +851,7 @@ int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct l
 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
                       const char *attr_name, uint_t v)
 {
-       const char *s = talloc_asprintf(mem_ctx, "%u", v);
-       return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
+       return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
 }
 
 /*
@@ -871,8 +870,7 @@ int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct
 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)
 {
-       const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
-       return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
+       return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
 }
 
 /*
@@ -937,7 +935,7 @@ int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, s
                             const char *attr_name, struct lsa_BinaryString *parameters)
 {
        struct ldb_val val;
-       val.length = parameters->length * 2;
+       val.length = parameters->length;
        val.data = (uint8_t *)parameters->array;
        return ldb_msg_add_value(msg, attr_name, &val, NULL);
 }
@@ -1196,11 +1194,18 @@ const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
        return domain_sid;
 
 failed:
-       DEBUG(1,("Failed to find domain_sid for open ldb\n"));
        talloc_free(tmp_ctx);
        return NULL;
 }
 
+/*
+  get domain sid from cache
+*/
+const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
+{
+       return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
+}
+
 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
 {
        TALLOC_CTX *tmp_ctx;
@@ -1521,6 +1526,86 @@ struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx
        return server_site_dn;
 }
 
+/*
+  find a 'reference' DN that points at another object
+  (eg. serverReference, rIDManagerReference etc)
+ */
+int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
+                      const char *attribute, struct ldb_dn **dn)
+{
+       const char *attrs[2];
+       struct ldb_result *res;
+       int ret;
+
+       attrs[0] = attribute;
+       attrs[1] = NULL;
+
+       ret = ldb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, NULL);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       if (res->count != 1) {
+               talloc_free(res);
+               return LDB_ERR_NO_SUCH_OBJECT;
+       }
+
+       *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
+       if (!*dn) {
+               talloc_free(res);
+               return LDB_ERR_NO_SUCH_ATTRIBUTE;
+       }
+
+       talloc_free(res);
+       return LDB_SUCCESS;
+}
+
+/*
+  find our machine account via the serverReference attribute in the
+  server DN
+ */
+int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
+{
+       struct ldb_dn *server_dn;
+       int ret;
+
+       server_dn = samdb_server_dn(ldb, mem_ctx);
+       if (server_dn == NULL) {
+               return LDB_ERR_NO_SUCH_OBJECT;
+       }
+
+       ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
+       talloc_free(server_dn);
+
+       return ret;
+}
+
+/*
+  find the RID Manager$ DN via the rIDManagerReference attribute in the
+  base DN
+ */
+int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
+{
+       return samdb_reference_dn(ldb, mem_ctx, samdb_base_dn(ldb), "rIDManagerReference", dn);
+}
+
+/*
+  find the RID Set DN via the rIDSetReferences attribute in our
+  machine account DN
+ */
+int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
+{
+       struct ldb_dn *server_ref_dn;
+       int ret;
+
+       ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
+       talloc_free(server_ref_dn);
+       return ret;
+}
+
 const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
 {
        const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb, mem_ctx));
@@ -2353,16 +2438,20 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
 
 
 /*
-  use a DN to find a GUID
+  use a DN to find a GUID with a given attribute name
  */
-int dsdb_find_guid_by_dn(struct ldb_context *ldb, 
-                        struct ldb_dn *dn, struct GUID *guid)
+int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
+                             struct ldb_dn *dn, const char *attribute,
+                             struct GUID *guid)
 {
        int ret;
        struct ldb_result *res;
-       const char *attrs[] = { "objectGUID", NULL };
+       const char *attrs[2];
        TALLOC_CTX *tmp_ctx = talloc_new(ldb);
 
+       attrs[0] = attribute;
+       attrs[1] = NULL;
+
        ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
        if (ret != LDB_SUCCESS) {
                talloc_free(tmp_ctx);
@@ -2372,11 +2461,20 @@ int dsdb_find_guid_by_dn(struct ldb_context *ldb,
                talloc_free(tmp_ctx);
                return LDB_ERR_NO_SUCH_OBJECT;
        }
-       *guid = samdb_result_guid(res->msgs[0], "objectGUID");
+       *guid = samdb_result_guid(res->msgs[0], attribute);
        talloc_free(tmp_ctx);
        return LDB_SUCCESS;
 }
 
+/*
+  use a DN to find a GUID
+ */
+int dsdb_find_guid_by_dn(struct ldb_context *ldb,
+                        struct ldb_dn *dn, struct GUID *guid)
+{
+       return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
+}
+
 
 
 /*
@@ -2557,10 +2655,11 @@ failed:
 
 
 /*
-  load the uSNHighest attribute from the @REPLCHANGED object for a
-  partition
+  load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
+  object for a partition
  */
-int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
+int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
+                               uint64_t *uSN, uint64_t *urgent_uSN)
 {
        struct ldb_request *req;
        int ret;
@@ -2625,8 +2724,14 @@ int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t
 
        if (res->count < 1) {
                *uSN = 0;
+               if (urgent_uSN) {
+                       *urgent_uSN = 0;
+               }
        } else {
                *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
+               if (urgent_uSN) {
+                       *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
+               }
        }
 
        talloc_free(tmp_ctx);
@@ -2635,10 +2740,11 @@ int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t
 }
 
 /*
-  save the uSNHighest attribute in the @REPLCHANGED object for a
+  save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
   partition
  */
-int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
+int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
+                               uint64_t uSN, uint64_t urgent_uSN)
 {
        struct ldb_request *req;
        struct ldb_message *msg;
@@ -2663,6 +2769,16 @@ int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t
        }
        msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
        
+       /* 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);
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(msg);
+                       return ret;
+               }
+               msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
+       }
+
 
        p_ctrl = talloc(msg, struct dsdb_control_current_partition);
        if (p_ctrl == NULL) {
@@ -2717,6 +2833,12 @@ int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
        return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
 }
 
+int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
+                                   const struct drsuapi_DsReplicaCursor *c2)
+{
+       return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
+}
+
 /*
   see if we are a RODC
 
@@ -2894,18 +3016,52 @@ NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const cha
        return NT_STATUS_OK;
 }
 
+/*
+  return RMD_FLAGS directly from a ldb_dn
+  returns 0 if not found
+ */
+uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
+{
+       const struct ldb_val *v;
+       char buf[32];
+       v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
+       if (!v || v->length > sizeof(buf)-1) return 0;
+       strncpy(buf, (const char *)v->data, v->length);
+       buf[v->length] = 0;
+       return strtoul(buf, NULL, 10);
+}
+
+/*
+  return RMD_FLAGS directly from a ldb_val for a DN
+  returns 0 if RMD_FLAGS is not found
+ */
+uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val)
+{
+       const char *p;
+       uint32_t flags;
+       char *end;
+
+       if (val->length < 13) {
+               return 0;
+       }
+       p = memmem(val->data, val->length-2, "<RMD_FLAGS=", 11);
+       if (!p) {
+               return 0;
+       }
+       flags = strtoul(p+11, &end, 10);
+       if (!end || *end != '>') {
+               /* it must end in a > */
+               return 0;
+       }
+       return flags;
+}
+
 /*
   return true if a ldb_val containing a DN in storage form is deleted
  */
 bool dsdb_dn_is_deleted_val(struct ldb_val *val)
 {
-       /* this relies on the sort order and exact format of
-          linearized extended DNs */
-       if (val->length >= 12 &&
-           strncmp((const char *)val->data, "<DELETED=1>;", 12) == 0) {
-               return true;
-       }
-       return false;
+       return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
 }
 
 /*
@@ -3065,3 +3221,101 @@ int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
        talloc_free(dn);
        return LDB_SUCCESS;
 }
+
+/*
+  compare a ldb_val to a string case insensitively
+ */
+int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
+{
+       size_t len = strlen(s);
+       int ret;
+       if (len > v->length) return 1;
+       ret = strncasecmp(s, (const char *)v->data, v->length);
+       if (ret != 0) return ret;
+       if (v->length > len && v->data[len] != 0) {
+               return -1;
+       }
+       return 0;
+}
+
+
+/*
+  load the UDV for a partition in v2 format
+ */
+int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
+                    struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
+{
+       static const char *attrs[] = { "replUpToDateVector", NULL };
+       struct ldb_result *r;
+       const struct ldb_val *ouv_value;
+       enum ndr_err_code ndr_err;
+       struct replUpToDateVectorBlob ouv;
+       int ret;
+
+       ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
+       if (!ouv_value) {
+               talloc_free(r);
+               *count = 0;
+               *cursors = NULL;
+               return LDB_SUCCESS;
+       }
+
+       ndr_err = ndr_pull_struct_blob(ouv_value, r,
+                                      lp_iconv_convenience(ldb_get_opaque(samdb, "loadparm")), &ouv,
+                                      (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               talloc_free(r);
+               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+       }
+       if (ouv.version != 2) {
+               /* we always store as version 2, and
+                * replUpToDateVector is not replicated
+                */
+               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+       }
+
+       *count = ouv.ctr.ctr2.count;
+       *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
+       talloc_free(r);
+
+       return LDB_SUCCESS;
+}
+
+/*
+  load the UDV for a partition in version 1 format
+ */
+int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
+                    struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
+{
+       struct drsuapi_DsReplicaCursor2 *v2;
+       int ret, i;
+
+       ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       if (*count == 0) {
+               talloc_free(v2);
+               *cursors = NULL;
+               return LDB_SUCCESS;
+       }
+
+       *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
+       if (*cursors == NULL) {
+               talloc_free(v2);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       for (i=0; i<*count; i++) {
+               (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
+               (*cursors)[i].highest_usn = v2[i].highest_usn;
+       }
+       talloc_free(v2);
+       return LDB_SUCCESS;
+}