s4-drs: added filtering by udv in getncchanges
[ira/wip.git] / source4 / dsdb / common / util.c
index 4f7ddde14cfbe60d37cdf823579d56902a6a1c6b..632025da54edaf794d6aea2a9332271894d1fe60 100644 (file)
@@ -1022,6 +1022,55 @@ static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
        return ret;
 }
 
+/*
+ * replace elements in a record using LDB_CONTROL_AS_SYSTEM
+ * used to skip access checks on operations
+ * that are performed by the system
+ */
+int samdb_replace_as_system(struct ldb_context *sam_ldb,
+                           TALLOC_CTX *mem_ctx,
+                           struct ldb_message *msg)
+{
+       int i;
+       int ldb_ret;
+       struct ldb_request *req = NULL;
+
+       /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
+       for (i=0;i<msg->num_elements;i++) {
+               msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
+       }
+
+
+       ldb_ret = ldb_msg_sanity_check(sam_ldb, msg);
+       if (ldb_ret != LDB_SUCCESS) {
+               return ldb_ret;
+       }
+
+       ldb_ret = ldb_build_mod_req(&req, sam_ldb, mem_ctx,
+                                   msg,
+                                   NULL,
+                                   NULL,
+                                   ldb_op_default_callback,
+                                   NULL);
+
+       if (ldb_ret != LDB_SUCCESS) {
+               talloc_free(req);
+               return ldb_ret;
+       }
+
+       ldb_ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
+       if (ldb_ret != LDB_SUCCESS) {
+               talloc_free(req);
+               return ldb_ret;
+       }
+
+       /* do request and auto start a transaction */
+       ldb_ret = dsdb_autotransaction_request(sam_ldb, req);
+
+       talloc_free(req);
+       return ldb_ret;
+}
+
 /*
   return a default security descriptor
 */
@@ -1472,6 +1521,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));
@@ -2012,7 +2141,7 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA
 {
        struct ldb_message *msg;
        struct ldb_dn *basedn;
-       const char *sidstr;
+       char *sidstr;
        int ret;
 
        sidstr = dom_sid_string(mem_ctx, sid);
@@ -2021,45 +2150,47 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA
        /* We might have to create a ForeignSecurityPrincipal, even if this user
         * is in our own domain */
 
-       msg = ldb_msg_new(mem_ctx);
+       msg = ldb_msg_new(sidstr);
        if (msg == NULL) {
+               talloc_free(sidstr);
                return NT_STATUS_NO_MEMORY;
        }
 
-       /* TODO: Hmmm. This feels wrong. How do I find the base dn to
-        * put the ForeignSecurityPrincipals? d_state->domain_dn does
-        * not work, this is wrong for the Builtin domain, there's no
-        * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
-        */
-
-       basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
-                                "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
-
-       if (basedn == NULL) {
+       ret = dsdb_wellknown_dn(sam_ctx, sidstr, samdb_base_dn(sam_ctx),
+                               DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
+                               &basedn);
+       if (ret != LDB_SUCCESS) {
                DEBUG(0, ("Failed to find DN for "
-                         "ForeignSecurityPrincipal container\n"));
+                         "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
+               talloc_free(sidstr);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
        /* add core elements to the ldb_message for the alias */
-       msg->dn = ldb_dn_copy(mem_ctx, basedn);
-       if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
+       msg->dn = basedn;
+       if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
+               talloc_free(sidstr);
                return NT_STATUS_NO_MEMORY;
+       }
 
-       samdb_msg_add_string(sam_ctx, mem_ctx, msg,
+       samdb_msg_add_string(sam_ctx, msg, msg,
                             "objectClass",
                             "foreignSecurityPrincipal");
 
        /* create the alias */
        ret = ldb_add(sam_ctx, msg);
-       if (ret != 0) {
+       if (ret != LDB_SUCCESS) {
                DEBUG(0,("Failed to create foreignSecurityPrincipal "
                         "record %s: %s\n", 
                         ldb_dn_get_linearized(msg->dn),
                         ldb_errstring(sam_ctx)));
+               talloc_free(sidstr);
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
-       *ret_dn = msg->dn;
+
+       *ret_dn = talloc_steal(mem_ctx, msg->dn);
+       talloc_free(sidstr);
+
        return NT_STATUS_OK;
 }
 
@@ -2098,14 +2229,16 @@ struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_c
        if (!ldb_dn_validate(dn)) {
                DEBUG(2, ("Failed to validated DN %s\n",
                          ldb_dn_get_linearized(dn)));
+               talloc_free(tmp_ctx);
                return NULL;
        }
+       talloc_free(tmp_ctx);
        return dn;
 }
+
 /*
   Find the DN of a domain, be it the netbios or DNS name 
 */
-
 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
                                  const char *domain_name) 
 {
@@ -2177,13 +2310,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       res = talloc_zero(mem_ctx, struct ldb_result);
+       res = talloc_zero(expression, struct ldb_result);
        if (!res) {
                DEBUG(0, (__location__ ": out of memory\n"));
+               talloc_free(expression);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
+       ret = ldb_build_search_req(&search_req, ldb, expression,
                                   ldb_get_default_basedn(ldb),
                                   LDB_SCOPE_SUBTREE,
                                   expression, attrs,
@@ -2191,6 +2325,7 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
                                   res, ldb_search_default_callback,
                                   NULL);
        if (ret != LDB_SUCCESS) {
+               talloc_free(expression);
                return ret;
        }
 
@@ -2199,12 +2334,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
        options = talloc(search_req, struct ldb_search_options_control);
        if (options == NULL) {
                DEBUG(0, (__location__ ": out of memory\n"));
+               talloc_free(expression);
                return LDB_ERR_OPERATIONS_ERROR;
        }
        options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
 
        ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
        if (ret != LDB_SUCCESS) {
+               talloc_free(expression);
                return ret;
        }
 
@@ -2212,16 +2349,19 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
                                      LDB_CONTROL_SEARCH_OPTIONS_OID,
                                      true, options);
        if (ret != LDB_SUCCESS) {
+               talloc_free(expression);
                return ret;
        }
 
        ret = ldb_request(ldb, search_req);
        if (ret != LDB_SUCCESS) {
+               talloc_free(expression);
                return ret;
        }
 
        ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
        if (ret != LDB_SUCCESS) {
+               talloc_free(expression);
                return ret;
        }
 
@@ -2229,10 +2369,12 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb,
           partitions module that can return two here with the
           search_options control set */
        if (res->count < 1) {
+               talloc_free(expression);
                return LDB_ERR_NO_SUCH_OBJECT;
        }
 
-       *dn = res->msgs[0]->dn;
+       *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
+       talloc_free(expression);
 
        return LDB_SUCCESS;
 }
@@ -2255,6 +2397,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
 
        res = talloc_zero(tmp_ctx, struct ldb_result);
        if (!res) {
+               talloc_free(tmp_ctx);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
@@ -2274,6 +2417,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
 
        ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
        if (ret != LDB_SUCCESS) {
+               talloc_free(tmp_ctx);
                return ret;
        }
 
@@ -2282,23 +2426,27 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
        }
 
-       talloc_free(req);
        *_res = talloc_steal(mem_ctx, res);
+       talloc_free(tmp_ctx);
        return ret;
 }
 
 
 /*
-  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);
@@ -2308,11 +2456,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);
+}
+
 
 
 /*
@@ -2653,6 +2810,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
 
@@ -2745,14 +2908,33 @@ int dsdb_functional_level(struct ldb_context *ldb)
        return *domainFunctionality;
 }
 
+/*
+  set a GUID in an extended DN structure
+ */
+int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
+{
+       struct ldb_val v;
+       NTSTATUS status;
+       int ret;
+
+       status = GUID_to_ndr_blob(guid, dn, &v);
+       if (!NT_STATUS_IS_OK(status)) {
+               return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
+       }
+
+       ret = ldb_dn_set_extended_component(dn, component_name, &v);
+       data_blob_free(&v);
+       return ret;
+}
+
 /*
   return a GUID from a extended DN structure
  */
-NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid)
+NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
 {
        const struct ldb_val *v;
 
-       v = ldb_dn_get_extended_component(dn, "GUID");
+       v = ldb_dn_get_extended_component(dn, component_name);
        if (v == NULL) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
@@ -2811,18 +2993,61 @@ 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;
+}
+
+/*
+  return true if a ldb_val containing a DN in storage form is
+  in the upgraded w2k3 linked attribute format
+ */
+bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
+{
+       return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
 }
 
 /*
@@ -2947,3 +3172,29 @@ int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
        talloc_free(nc_root);
        return ret;
 }
+
+/*
+  return the tombstoneLifetime, in days
+ */
+int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
+{
+       struct ldb_dn *dn;
+       dn = samdb_config_dn(ldb);
+       if (!dn) {
+               return LDB_ERR_NO_SUCH_OBJECT;
+       }
+       dn = ldb_dn_copy(ldb, dn);
+       if (!dn) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
+        be a wellknown GUID for this */
+       if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT")) {
+               talloc_free(dn);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
+       talloc_free(dn);
+       return LDB_SUCCESS;
+}