diff options
author | Karolin Seeger <kseeger@samba.org> | 2014-07-28 09:13:45 +0200 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2014-07-28 09:18:00 +0200 |
commit | fcc634b483255bedf53f3aea40334c018e13dcce (patch) | |
tree | 7d59833bd515e295e70ec188e1aa2b1436b3355c /source4/dsdb/samdb/ldb_modules | |
parent | 97d7291d12e803076022d71556c792b0cd4e60e8 (diff) | |
parent | 80a1dfddf9086700a8de5fd6005a9179b0bb3d9e (diff) | |
download | samba-2cd741d5ceefd9e0771f5ea4891bc93baa48a165.tar.gz |
Merge commit 'origin/v4-1-test^' into v4-1-stablesamba-4.1.10
This was needed because of a changed commit message (fixed version number)
in v4-1-stable after generating the 'samba-4.1.9' tag.
Karolin
Signed-off-by: Karolin Seeger <kseeger@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules')
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/descriptor.c | 2 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/dirsync.c | 7 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/extended_dn_in.c | 37 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/instancetype.c | 3 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/objectclass.c | 54 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/operational.c | 2 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/partition_metadata.c | 34 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/password_hash.c | 1 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 267 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/rootdse.c | 110 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samldb.c | 29 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema_data.c | 16 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema_load.c | 207 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c | 6 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/simple_ldap_map.c | 2 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/update_keytab.c | 11 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/util.c | 13 |
17 files changed, 547 insertions, 254 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c index ceac8db7de2..cc0a9c25ebb 100644 --- a/source4/dsdb/samdb/ldb_modules/descriptor.c +++ b/source4/dsdb/samdb/ldb_modules/descriptor.c @@ -501,7 +501,7 @@ static int descriptor_search_callback(struct ldb_request *req, struct ldb_reply struct ldb_val *sd_val = NULL; struct ldb_message_element *sd_el; DATA_BLOB *show_sd; - int ret; + int ret = LDB_SUCCESS; ac = talloc_get_type(req->context, struct descriptor_context); diff --git a/source4/dsdb/samdb/ldb_modules/dirsync.c b/source4/dsdb/samdb/ldb_modules/dirsync.c index e7699485083..c93189ef716 100644 --- a/source4/dsdb/samdb/ldb_modules/dirsync.c +++ b/source4/dsdb/samdb/ldb_modules/dirsync.c @@ -70,7 +70,7 @@ static int dirsync_filter_entry(struct ldb_request *req, bool referral) { struct ldb_context *ldb; - uint64_t val; + uint64_t val = 0; enum ndr_err_code ndr_err; uint32_t n; int i; @@ -336,10 +336,13 @@ skip: * if not we remove the attribute. */ for (i = msg->num_elements - 1; i >= 0; i--) { + const char *ldapattrname; + el = &(msg->elements[i]); + ldapattrname = el->name; + attr = dsdb_attribute_by_lDAPDisplayName(dsc->schema, el->name); - const char *ldapattrname = el->name; keep = false; if (attr->linkID & 1) { diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c index 034d22a2ca3..213b2c2c87b 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c @@ -315,6 +315,7 @@ struct extended_dn_filter_ctx { struct ldb_module *module; struct ldb_request *req; struct dsdb_schema *schema; + uint32_t dsdb_flags; }; /* @@ -411,10 +412,7 @@ static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *privat return LDB_SUCCESS; } - dsdb_flags = DSDB_FLAG_NEXT_MODULE | - DSDB_FLAG_AS_SYSTEM | - DSDB_SEARCH_SHOW_RECYCLED | - DSDB_SEARCH_SHOW_EXTENDED_DN; + dsdb_flags = filter_ctx->dsdb_flags | DSDB_FLAG_NEXT_MODULE; if (guid_val) { expression = talloc_asprintf(filter_ctx, "objectGUID=%s", ldb_binary_encode(filter_ctx, *guid_val)); @@ -475,7 +473,9 @@ static int extended_dn_filter_callback(struct ldb_parse_tree *tree, void *privat fix the parse tree to change any extended DN components to their caconical form */ -static int extended_dn_fix_filter(struct ldb_module *module, struct ldb_request *req) +static int extended_dn_fix_filter(struct ldb_module *module, + struct ldb_request *req, + uint32_t default_dsdb_flags) { struct extended_dn_filter_ctx *filter_ctx; int ret; @@ -493,6 +493,7 @@ static int extended_dn_fix_filter(struct ldb_module *module, struct ldb_request filter_ctx->module = module; filter_ctx->req = req; filter_ctx->schema = dsdb_get_schema(ldb_module_get_ctx(module), filter_ctx); + filter_ctx->dsdb_flags= default_dsdb_flags; ret = ldb_parse_tree_walk(req->op.search.tree, extended_dn_filter_callback, filter_ctx); if (ret != LDB_SUCCESS) { @@ -541,10 +542,20 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req static const char *no_attr[] = { NULL }; - bool all_partitions = false; + uint32_t dsdb_flags = DSDB_FLAG_AS_SYSTEM | DSDB_SEARCH_SHOW_EXTENDED_DN; + + if (ldb_request_get_control(req, LDB_CONTROL_SHOW_DELETED_OID)) { + dsdb_flags |= DSDB_SEARCH_SHOW_DELETED; + } + if (ldb_request_get_control(req, LDB_CONTROL_SHOW_RECYCLED_OID)) { + dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED; + } + if (ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) { + dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED; + } if (req->operation == LDB_SEARCH) { - ret = extended_dn_fix_filter(module, req); + ret = extended_dn_fix_filter(module, req, dsdb_flags); if (ret != LDB_SUCCESS) { return ret; } @@ -556,7 +567,6 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req } else { /* It looks like we need to map the DN */ const struct ldb_val *sid_val, *guid_val, *wkguid_val; - uint32_t dsdb_flags = 0; if (!ldb_dn_match_allowed(dn, req)) { return ldb_error(ldb_module_get_ctx(module), @@ -573,7 +583,7 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req ForeignSecurityPrinciples due to provision errors */ if (guid_val) { - all_partitions = true; + dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS; base_dn = NULL; base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", ldb_binary_encode(req, *guid_val)); @@ -584,7 +594,7 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req base_dn_attrs = no_attr; } else if (sid_val) { - all_partitions = true; + dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS; base_dn = NULL; base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", ldb_binary_encode(req, *sid_val)); @@ -661,13 +671,6 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req return ldb_operr(ldb_module_get_ctx(module)); } - dsdb_flags = DSDB_FLAG_AS_SYSTEM | - DSDB_SEARCH_SHOW_RECYCLED | - DSDB_SEARCH_SHOW_EXTENDED_DN; - if (all_partitions) { - dsdb_flags |= DSDB_SEARCH_SEARCH_ALL_PARTITIONS; - } - ret = dsdb_request_add_controls(down_req, dsdb_flags); if (ret != LDB_SUCCESS) { return ret; diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c index 7bf95f3180c..c35f4b6a262 100644 --- a/source4/dsdb/samdb/ldb_modules/instancetype.c +++ b/source4/dsdb/samdb/ldb_modules/instancetype.c @@ -80,8 +80,7 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req) * "TYPE_WRITE" flag in order to succeed, * unless this NC is not instantiated */ - if (!(instanceType & INSTANCE_TYPE_UNINSTANT) && - !(instanceType & INSTANCE_TYPE_WRITE)) { + if (!(instanceType & INSTANCE_TYPE_WRITE)) { ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD was set, then also TYPE_WRITE is requested!"); return LDB_ERR_UNWILLING_TO_PERFORM; } diff --git a/source4/dsdb/samdb/ldb_modules/objectclass.c b/source4/dsdb/samdb/ldb_modules/objectclass.c index f6f7338d3cf..8c361e97231 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass.c @@ -186,36 +186,6 @@ static int get_search_callback(struct ldb_request *req, struct ldb_reply *ares) return LDB_SUCCESS; } -static int oc_op_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - struct oc_context *ac; - - ac = talloc_get_type(req->context, struct oc_context); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - if (ares->type == LDB_REPLY_REFERRAL) { - return ldb_module_send_referral(ac->req, ares->referral); - } - - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - if (ares->type != LDB_REPLY_DONE) { - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); -} - /* Fix up the DN to be in the standard form, taking particular care to match the parent DN This should mean that if the parent is: @@ -659,7 +629,7 @@ static int objectclass_do_add(struct oc_context *ac) ret = ldb_build_add_req(&add_req, ldb, ac, msg, ac->req->controls, - ac, oc_op_callback, + ac->req, dsdb_next_callback, ac->req); LDB_REQ_SET_LOCATION(add_req); if (ret != LDB_SUCCESS) { @@ -745,11 +715,19 @@ static int objectclass_modify(struct ldb_module *module, struct ldb_request *req talloc_free(nc_root); } - ret = ldb_build_mod_req(&down_req, ldb, ac, - msg, - req->controls, ac, - oc_changes ? oc_modify_callback : oc_op_callback, - req); + if (oc_changes) { + ret = ldb_build_mod_req(&down_req, ldb, ac, + msg, + req->controls, ac, + oc_modify_callback, + req); + } else { + ret = ldb_build_mod_req(&down_req, ldb, ac, + msg, + req->controls, req, + dsdb_next_callback, + req); + } LDB_REQ_SET_LOCATION(down_req); if (ret != LDB_SUCCESS) { return ret; @@ -978,7 +956,7 @@ static int objectclass_do_mod(struct oc_context *ac) ret = ldb_build_mod_req(&mod_req, ldb, ac, msg, ac->req->controls, - ac, oc_op_callback, + ac->req, dsdb_next_callback, ac->req); LDB_REQ_SET_LOCATION(mod_req); if (ret != LDB_SUCCESS) { @@ -1216,7 +1194,7 @@ static int objectclass_do_rename2(struct oc_context *ac) ret = ldb_build_rename_req(&rename_req, ldb, ac, ac->req->op.rename.olddn, fixed_dn, ac->req->controls, - ac, oc_op_callback, + ac->req, dsdb_next_callback, ac->req); LDB_REQ_SET_LOCATION(rename_req); if (ret != LDB_SUCCESS) { diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c index 9337faacc4c..2ebefac1713 100644 --- a/source4/dsdb/samdb/ldb_modules/operational.c +++ b/source4/dsdb/samdb/ldb_modules/operational.c @@ -131,7 +131,7 @@ static int construct_token_groups(struct ldb_module *module, struct ldb_message *msg, enum ldb_scope scope, struct ldb_request *parent) { - struct ldb_context *ldb = ldb_module_get_ctx(module);; + struct ldb_context *ldb = ldb_module_get_ctx(module); TALLOC_CTX *tmp_ctx = talloc_new(msg); unsigned int i; int ret; diff --git a/source4/dsdb/samdb/ldb_modules/partition_metadata.c b/source4/dsdb/samdb/ldb_modules/partition_metadata.c index 5826ac2ee11..b3b57447ecd 100644 --- a/source4/dsdb/samdb/ldb_modules/partition_metadata.c +++ b/source4/dsdb/samdb/ldb_modules/partition_metadata.c @@ -129,9 +129,13 @@ static int partition_metadata_set_uint64(struct ldb_module *module, } if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) { + int ret; + char *error_string = talloc_asprintf(tmp_ctx, "%s: tdb_store of key %s failed: %s", + tdb_name(tdb), key, tdb_errorstr(tdb)); + ret = ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, + error_string); talloc_free(tmp_ctx); - return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, - tdb_errorstr(tdb)); + return ret; } talloc_free(tmp_ctx); @@ -199,13 +203,13 @@ static int partition_metadata_open(struct ldb_module *module, bool create) } sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url"); - if (strncmp("tdb://", sam_name, 6) == 0) { - sam_name += 6; - } if (!sam_name) { talloc_free(tmp_ctx); return ldb_operr(ldb); } + if (strncmp("tdb://", sam_name, 6) == 0) { + sam_name += 6; + } filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name); if (!filename) { talloc_free(tmp_ctx); @@ -242,9 +246,14 @@ static int partition_metadata_open(struct ldb_module *module, bool create) if (data->metadata->db == NULL) { talloc_free(tmp_ctx); if (create) { - ldb_debug(ldb, LDB_DEBUG_ERROR, - "partition_metadata: Unable to create %s", - filename); + ldb_asprintf_errstring(ldb, "partition_metadata: Unable to create %s: %s", + filename, strerror(errno)); + } else { + ldb_asprintf_errstring(ldb, "partition_metadata: Unable to open %s: %s", + filename, strerror(errno)); + } + if (errno == EACCES || errno == EPERM) { + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; } return LDB_ERR_OPERATIONS_ERROR; } @@ -295,9 +304,16 @@ int partition_metadata_init(struct ldb_module *module) } /* metadata.tdb does not exist, create it */ - DEBUG(2, ("partition_metadata: Migrating partition metadata\n")); + DEBUG(2, ("partition_metadata: Migrating partition metadata: " + "open of metadata.tdb gave: %s\n", + ldb_errstring(ldb_module_get_ctx(module)))); ret = partition_metadata_open(module, true); if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), + "partition_metadata: " + "Migrating partition metadata: " + "create of metadata.tdb gave: %s\n", + ldb_errstring(ldb_module_get_ctx(module))); talloc_free(data->metadata); data->metadata = NULL; goto end; diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index 79741694990..78311c6c13e 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -2159,7 +2159,6 @@ static int setup_io(struct ph_context *ac, /* Some operations below require kerberos contexts */ if (smb_krb5_init_context(ac, - ldb_get_event_context(ldb), (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"), &io->smb_krb5_context) != 0) { return ldb_operr(ldb); diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 91a5d9233c5..4c5ced42309 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -67,6 +67,7 @@ struct replmd_private { uint64_t mod_usn; uint64_t mod_usn_urgent; } *ncs; + struct ldb_dn *schema_dn; }; struct la_entry { @@ -240,6 +241,8 @@ static int replmd_init(struct ldb_module *module) } ldb_module_set_private(module, replmd_private); + replmd_private->schema_dn = ldb_get_schema_basedn(ldb); + return ldb_next_init(module); } @@ -660,7 +663,15 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta const struct replPropertyMetaData1 *m2, const uint32_t *rdn_attid) { - if (m1->attid == m2->attid) { + /* + * This assignment seems inoccous, but it is critical for the + * system, as we need to do the comparisons as a unsigned + * quantity, not signed (enums are signed integers) + */ + uint32_t attid_1 = m1->attid; + uint32_t attid_2 = m2->attid; + + if (attid_1 == attid_2) { return 0; } @@ -669,7 +680,7 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta * so we need to return a value greater than zero * which means m1 is greater than m2 */ - if (m1->attid == *rdn_attid) { + if (attid_1 == *rdn_attid) { return 1; } @@ -678,38 +689,78 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta * so we need to return a value less than zero * which means m2 is greater than m1 */ - if (m2->attid == *rdn_attid) { + if (attid_2 == *rdn_attid) { return -1; } - return m1->attid > m2->attid ? 1 : -1; + /* + * See above regarding this being an unsigned comparison. + * Otherwise when the high bit is set on non-standard + * attributes, they would end up first, before objectClass + * (0). + */ + return attid_1 > attid_2 ? 1 : -1; } -static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1, - const struct dsdb_schema *schema, - struct ldb_dn *dn) +static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb, + struct replPropertyMetaDataCtr1 *ctr1, + const struct dsdb_attribute *rdn_sa, + struct ldb_dn *dn) +{ + if (ctr1->count == 0) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "No elements found in replPropertyMetaData for %s!\n", + ldb_dn_get_linearized(dn)); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + if (ctr1->array[ctr1->count - 1].attid != rdn_sa->attributeID_id) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "No rDN found in replPropertyMetaData for %s!\n", + ldb_dn_get_linearized(dn)); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + /* the objectClass attribute is value 0x00000000, so must be first */ + if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "No objectClass found in replPropertyMetaData for %s!\n", + ldb_dn_get_linearized(dn)); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + + return LDB_SUCCESS; +} + +static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb, + struct replPropertyMetaDataCtr1 *ctr1, + const struct dsdb_schema *schema, + struct ldb_dn *dn) { const char *rdn_name; const struct dsdb_attribute *rdn_sa; rdn_name = ldb_dn_get_rdn_name(dn); if (!rdn_name) { - DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn))); - return LDB_ERR_OPERATIONS_ERROR; + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + __location__ ": No rDN for %s?\n", + ldb_dn_get_linearized(dn)); + return LDB_ERR_INVALID_DN_SYNTAX; } rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name); if (rdn_sa == NULL) { - DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn))); - return LDB_ERR_OPERATIONS_ERROR; + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + __location__ ": No sa found for rDN %s for %s\n", + rdn_name, ldb_dn_get_linearized(dn)); + return LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE; } DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n", rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn))); - LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort); - - return LDB_SUCCESS; + LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, + replmd_replPropertyMetaData1_attid_sort); + return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, rdn_sa, dn); } static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1, @@ -840,6 +891,8 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) bool remove_current_guid = false; bool is_urgent = false; struct ldb_message_element *objectclass_el; + struct replmd_private *replmd_private = + talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */ control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID); @@ -1025,8 +1078,9 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) /* * sort meta data array, and move the rdn attribute entry to the end */ - ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn); + ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, ac->schema, msg->dn); if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb)); talloc_free(ac); return ret; } @@ -1080,7 +1134,17 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) */ replmd_ldb_message_sort(msg, ac->schema); + /* + * Assert that we do have an objectClass + */ objectclass_el = ldb_msg_find_element(msg, "objectClass"); + if (objectclass_el == NULL) { + ldb_asprintf_errstring(ldb, __location__ + ": objectClass missing on %s\n", + ldb_dn_get_linearized(msg->dn)); + talloc_free(ac); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } is_urgent = replmd_check_urgent_objectclass(objectclass_el, REPL_URGENT_ON_CREATE); @@ -1120,7 +1184,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) if (control) { control->critical = 0; } - if (ldb_dn_compare_base(ac->schema->base_dn, req->op.add.message->dn) != 0) { + if (ldb_dn_compare_base(replmd_private->schema_dn, req->op.add.message->dn) != 0) { /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */ msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE); @@ -1398,12 +1462,6 @@ static int replmd_update_rpmd(struct ldb_module *module, return ret; } - objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); - if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, - situation)) { - *is_urgent = true; - } - db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0); if (*seq_num <= db_seq) { DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\ @@ -1428,12 +1486,6 @@ static int replmd_update_rpmd(struct ldb_module *module, return ret; } - objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); - if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, - situation)) { - *is_urgent = true; - } - omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData"); if (!omd_value) { DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n", @@ -1464,12 +1516,33 @@ static int replmd_update_rpmd(struct ldb_module *module, return ret; } - if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) { + if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) { *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]); } } } + + /* + * Assert that we have an objectClass attribute - this is major + * corruption if we don't have this! + */ + objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); + if (objectclass_el != NULL) { + /* + * Now check if this objectClass means we need to do urgent replication + */ + if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el, + situation)) { + *is_urgent = true; + } + } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) { + ldb_asprintf_errstring(ldb, __location__ + ": objectClass missing on %s\n", + ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + /* * replmd_update_rpmd_element has done an update if the * seq_num is set @@ -1504,8 +1577,9 @@ static int replmd_update_rpmd(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn); + ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, schema, msg->dn); if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb)); return ret; } @@ -2400,8 +2474,10 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) int ret; bool is_urgent = false, rodc = false; unsigned int functional_level; - const DATA_BLOB *guid_blob; + const struct ldb_message_element *guid_el = NULL; struct ldb_control *sd_propagation_control; + struct replmd_private *replmd_private = + talloc_get_type(ldb_module_get_private(module), struct replmd_private); /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -2427,8 +2503,8 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n"); - guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID"); - if ( guid_blob != NULL ) { + guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID"); + if (guid_el != NULL) { ldb_set_errstring(ldb, "replmd_modify: it's not allowed to change the objectGUID!"); return LDB_ERR_CONSTRAINT_VIOLATION; @@ -2540,7 +2616,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) } } - if (!ldb_dn_compare_base(ac->schema->base_dn, msg->dn)) { + if (!ldb_dn_compare_base(replmd_private->schema_dn, msg->dn)) { /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */ msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE); if (msds_intid_struct) { @@ -2922,6 +2998,20 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request return ldb_next_request(module, req); } + /* + * We have to allow dbcheck to remove an object that + * is beyond repair, and to do so totally. This could + * mean we we can get a partial object from the other + * DC, causing havoc, so dbcheck suggests + * re-replication first. dbcheck sets both DBCHECK + * and RELAX in this situation. + */ + if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) + && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) { + /* really, really remove it */ + return ldb_next_request(module, req); + } + tmp_ctx = talloc_new(ldb); if (!tmp_ctx) { ldb_oom(ldb); @@ -2965,17 +3055,25 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request } if (next_deletion_state == OBJECT_REMOVED) { - struct auth_session_info *session_info = - (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); - if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) { - ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s", - ldb_dn_get_linearized(old_msg->dn)); - return LDB_ERR_UNWILLING_TO_PERFORM; + /* + * We have to prevent objects being deleted, even if + * the administrator really wants them gone, as + * without the tombstone, we can get a partial object + * from the other DC, causing havoc. + * + * The only other valid case is when the 180 day + * timeout has expired, when relax is specified. + */ + if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) { + /* it is already deleted - really remove it this time */ + talloc_free(tmp_ctx); + return ldb_next_request(module, req); } - /* it is already deleted - really remove it this time */ - talloc_free(tmp_ctx); - return ldb_next_request(module, req); + ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s. " + "This check is to prevent corruption of the replicated state.", + ldb_dn_get_linearized(old_msg->dn)); + return LDB_ERR_UNWILLING_TO_PERFORM; } rdn_name = ldb_dn_get_rdn_name(old_dn); @@ -3214,8 +3312,13 @@ static int replmd_delete_internals(struct ldb_module *module, struct ldb_request */ continue; } - if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) { - continue; + if (!sa->linkID) { + if (ldb_attr_in_list(preserved_attrs, el->name)) { + continue; + } + if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) { + continue; + } } ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el); if (ret != LDB_SUCCESS) { @@ -3826,6 +3929,8 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) unsigned int i; int ret; bool remote_isDeleted = false; + const struct dsdb_attribute *rdn_sa; + const char *rdn_name; ldb = ldb_module_get_ctx(ar->module); msg = ar->objs->objects[ar->index_current].msg; @@ -3861,6 +3966,13 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) struct ldb_message_element *el = &msg->elements[i]; if (el->num_values == 0) { + if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) { + ldb_asprintf_errstring(ldb, __location__ + ": empty objectClass sent on %s, aborting replication\n", + ldb_dn_get_linearized(msg->dn)); + return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION); + } + DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n", el->name)); memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1))); @@ -3870,12 +3982,38 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) } } + if (DEBUGLVL(4)) { + char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg); + DEBUG(4, ("DRS replication add message:\n%s\n", s)); + talloc_free(s); + } + remote_isDeleted = ldb_msg_find_attr_as_bool(msg, "isDeleted", false); /* * the meta data array is already sorted by the caller */ + + rdn_name = ldb_dn_get_rdn_name(msg->dn); + if (rdn_name == NULL) { + ldb_asprintf_errstring(ldb, __location__ ": No rDN for %s?\n", ldb_dn_get_linearized(msg->dn)); + return replmd_replicated_request_error(ar, LDB_ERR_INVALID_DN_SYNTAX); + } + + rdn_sa = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name); + if (rdn_sa == NULL) { + ldb_asprintf_errstring(ldb, ": No schema attribute found for rDN %s for %s\n", + rdn_name, ldb_dn_get_linearized(msg->dn)); + return replmd_replicated_request_error(ar, LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE); + } + + ret = replmd_replPropertyMetaDataCtr1_verify(ldb, &md->ctr.ctr1, rdn_sa, msg->dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb)); + return replmd_replicated_request_error(ar, ret); + } + for (i=0; i < md->ctr.ctr1.count; i++) { md->ctr.ctr1.array[i].local_usn = ar->seq_num; } @@ -3903,12 +4041,6 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) ar->isDeleted = remote_isDeleted; - if (DEBUGLVL(4)) { - char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg); - DEBUG(4, ("DRS replication add message:\n%s\n", s)); - talloc_free(s); - } - ret = ldb_build_add_req(&change_req, ldb, ar, @@ -4300,11 +4432,19 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) } if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) { - /* if we compare equal then do an - update. This is used when a client - asks for a FULL_SYNC, and can be - used to recover a corrupt - replica */ + /* + * if we compare equal then do an + * update. This is used when a client + * asks for a FULL_SYNC, and can be + * used to recover a corrupt + * replica. + * + * This call is a bit tricky, what we + * are doing it turning the 'is_newer' + * call into a 'not is older' by + * swapping i and j, and negating the + * outcome. + */ cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i], &nmd.ctr.ctr1.array[j]); } else { @@ -4385,8 +4525,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) * * sort the new meta data array */ - ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn); + ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, ar->schema, msg->dn); if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb)); return ret; } @@ -4460,6 +4601,14 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) /* we want to replace the old values */ for (i=0; i < msg->num_elements; i++) { msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) { + if (msg->elements[i].num_values == 0) { + ldb_asprintf_errstring(ldb, __location__ + ": objectClass removed on %s, aborting replication\n", + ldb_dn_get_linearized(msg->dn)); + return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION); + } + } } if (DEBUGLVL(4)) { @@ -5277,8 +5426,8 @@ linked_attributes[0]: attrs[0] = attr->lDAPDisplayName; attrs[1] = "isDeleted"; - attrs[1] = "isRecycled"; - attrs[2] = NULL; + attrs[2] = "isRecycled"; + attrs[3] = NULL; /* get the existing message from the db for the object with this GUID, returning attribute being modified. We will then diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index f905aa24230..b13dc9e5c59 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -36,13 +36,16 @@ #include "librpc/gen_ndr/ndr_irpc_c.h" #include "lib/tsocket/tsocket.h" #include "cldap_server/cldap_server.h" +#include "lib/events/events.h" -struct private_data { +struct rootdse_private_data { unsigned int num_controls; char **controls; unsigned int num_partitions; struct ldb_dn **partitions; bool block_anonymous; + struct tevent_context *saved_ev; + struct tevent_context *private_ev; }; struct rootdse_context { @@ -227,7 +230,7 @@ static int dsdb_module_we_are_master(struct ldb_module *module, struct ldb_dn *d static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *msg) { struct ldb_context *ldb; - struct private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct private_data); + struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct rootdse_private_data); const char * const *attrs = ac->req->op.search.attrs; char **server_sasl; const struct dsdb_schema *schema; @@ -654,7 +657,7 @@ static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares) static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req) { unsigned int i, j; - struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data); + struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data); bool is_untrusted; if (!req->controls) { @@ -717,7 +720,7 @@ static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req) { struct auth_session_info *session_info; - struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data); + struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data); bool is_untrusted = ldb_req_is_untrusted(req); bool is_anonymous = true; if (is_untrusted == false) { @@ -855,7 +858,7 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req) static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req) { - struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data); + struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data); char **list; list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1); @@ -876,7 +879,7 @@ static int rootdse_register_control(struct ldb_module *module, struct ldb_reques static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req) { - struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data); + struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data); struct ldb_dn **list; list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1); @@ -916,14 +919,14 @@ static int rootdse_init(struct ldb_module *module) int ret; struct ldb_context *ldb; struct ldb_result *res; - struct private_data *data; + struct rootdse_private_data *data; const char *attrs[] = { "msDS-Behavior-Version", NULL }; const char *ds_attrs[] = { "dsServiceName", NULL }; TALLOC_CTX *mem_ctx; ldb = ldb_module_get_ctx(module); - data = talloc_zero(module, struct private_data); + data = talloc_zero(module, struct rootdse_private_data); if (data == NULL) { return ldb_oom(ldb); } @@ -1356,6 +1359,67 @@ static int rootdse_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_NAMING_VIOLATION; } +static int rootdse_start_trans(struct ldb_module *module) +{ + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module), + struct rootdse_private_data); + ret = ldb_next_start_trans(module); + if (ret == LDB_SUCCESS) { + if (data->private_ev != NULL) { + return ldb_operr(ldb); + } + data->private_ev = s4_event_context_init(data); + if (data->private_ev == NULL) { + return ldb_operr(ldb); + } + data->saved_ev = ldb_get_event_context(ldb); + ldb_set_event_context(ldb, data->private_ev); + } + return ret; +} + +static int rootdse_end_trans(struct ldb_module *module) +{ + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module), + struct rootdse_private_data); + ret = ldb_next_end_trans(module); + if (data->saved_ev == NULL) { + return ldb_operr(ldb); + } + + if (data->private_ev != ldb_get_event_context(ldb)) { + return ldb_operr(ldb); + } + ldb_set_event_context(ldb, data->saved_ev); + data->saved_ev = NULL; + TALLOC_FREE(data->private_ev); + return ret; +} + +static int rootdse_del_trans(struct ldb_module *module) +{ + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module), + struct rootdse_private_data); + ret = ldb_next_del_trans(module); + if (data->saved_ev == NULL) { + return ldb_operr(ldb); + } + + if (data->private_ev != ldb_get_event_context(ldb)) { + return ldb_operr(ldb); + } + ldb_set_event_context(ldb, data->saved_ev); + data->saved_ev = NULL; + TALLOC_FREE(data->private_ev); + return ret; +} + struct fsmo_transfer_state { struct ldb_context *ldb; struct ldb_request *req; @@ -1373,6 +1437,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq) int ret; struct ldb_request *req = fsmo->req; struct ldb_context *ldb = fsmo->ldb; + struct ldb_module *module = fsmo->module; status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr); talloc_free(fsmo); @@ -1382,7 +1447,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq) * Now that it is failed, start the transaction up * again so the wrappers can close it without additional error */ - ldb_next_start_trans(fsmo->module); + rootdse_start_trans(module); ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE); return; } @@ -1392,7 +1457,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq) * Now that it is failed, start the transaction up * again so the wrappers can close it without additional error */ - ldb_next_start_trans(fsmo->module); + rootdse_start_trans(module); ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE); return; } @@ -1401,7 +1466,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq) * Now that it is done, start the transaction up again so the * wrappers can close it without error */ - ret = ldb_next_start_trans(fsmo->module); + ret = rootdse_start_trans(module); ldb_module_done(req, NULL, NULL, ret); } @@ -1442,7 +1507,7 @@ static int rootdse_become_master(struct ldb_module *module, * this gives the least supprise to this supprising action (as * we will never record anything done to this point */ - ldb_next_del_trans(module); + rootdse_del_trans(module); msg = imessaging_client_init(tmp_ctx, lp_ctx, ldb_get_event_context(ldb)); @@ -1611,15 +1676,18 @@ static int rootdse_extended(struct ldb_module *module, struct ldb_request *req) } static const struct ldb_module_ops ldb_rootdse_module_ops = { - .name = "rootdse", - .init_context = rootdse_init, - .search = rootdse_search, - .request = rootdse_request, - .add = rootdse_add, - .modify = rootdse_modify, - .rename = rootdse_rename, - .extended = rootdse_extended, - .del = rootdse_delete + .name = "rootdse", + .init_context = rootdse_init, + .search = rootdse_search, + .request = rootdse_request, + .add = rootdse_add, + .modify = rootdse_modify, + .rename = rootdse_rename, + .extended = rootdse_extended, + .del = rootdse_delete, + .start_transaction = rootdse_start_trans, + .end_transaction = rootdse_end_trans, + .del_transaction = rootdse_del_trans }; int ldb_rootdse_module_init(const char *version) diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index a63a44ea8e1..2f8c5728fe4 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -509,7 +509,8 @@ static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac) continue; } - ret = dsdb_module_load_partition_usn(ac->module, schema->base_dn, ¤t_usn, NULL, NULL); + ret = dsdb_module_load_partition_usn(ac->module, schema_dn, + ¤t_usn, NULL, NULL); if (ret != LDB_SUCCESS) { ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__": Searching for schema USN failed: %s\n", @@ -2002,7 +2003,7 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) /* Create a temporary message for fetching the "sAMAccountName" */ if (el2 != NULL) { - char *tempstr, *tempstr2; + char *tempstr, *tempstr2 = NULL; const char *acct_attrs[] = { "sAMAccountName", NULL }; msg = ldb_msg_new(ac->msg); @@ -2267,6 +2268,15 @@ static int samldb_add(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } + el = ldb_msg_find_element(req->op.add.message, "userParameters"); + if (el != NULL && ldb_req_is_untrusted(req)) { + const char *reason = "samldb_add: " + "setting userParameters is not supported over LDAP, " + "see https://bugzilla.samba.org/show_bug.cgi?id=8077"; + ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason); + return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason); + } + ac = samldb_ctx_init(module, req); if (ac == NULL) { return ldb_operr(ldb); @@ -2406,6 +2416,15 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) } } + el = ldb_msg_find_element(req->op.mod.message, "userParameters"); + if (el != NULL && ldb_req_is_untrusted(req)) { + const char *reason = "samldb: " + "setting userParameters is not supported over LDAP, " + "see https://bugzilla.samba.org/show_bug.cgi?id=8077"; + ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason); + return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason); + } + ac = samldb_ctx_init(module, req); if (ac == NULL) { return ldb_operr(ldb); @@ -2552,6 +2571,11 @@ static int samldb_prim_group_users_check(struct samldb_ctx *ac) /* Special object (security principal?) */ return LDB_SUCCESS; } + /* do not allow deletion of well-known sids */ + if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID && + (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) { + return LDB_ERR_OTHER; + } /* Deny delete requests from groups which are primary ones */ ret = dsdb_module_search(ac->module, ac, &res, @@ -2757,7 +2781,6 @@ static int check_rename_constraints(struct ldb_message *msg, static int samldb_rename_search_base_callback(struct ldb_request *req, struct ldb_reply *ares) { - struct ldb_request *rename_req; struct samldb_ctx *ac; int ret; diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index 3ce7ef9935c..996b1f22386 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -144,6 +144,8 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) WERROR status; bool rodc = false; int ret; + struct schema_data_private_data *mc; + mc = talloc_get_type(ldb_module_get_private(module), struct schema_data_private_data); ldb = ldb_module_get_ctx(module); @@ -162,12 +164,6 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } - if (schema->base_dn == NULL) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "schema_data_add: base_dn NULL\n"); - return LDB_ERR_OPERATIONS_ERROR; - } - ret = samdb_rodc(ldb, &rodc); if (ret != LDB_SUCCESS) { DEBUG(4, (__location__ ": unable to tell if we are an RODC \n")); @@ -190,7 +186,7 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) * the provision code needs to create * the schema root object. */ - cmp = ldb_dn_compare(req->op.add.message->dn, schema->base_dn); + cmp = ldb_dn_compare(req->op.add.message->dn, mc->schema_dn); if (cmp == 0) { return ldb_next_request(module, req); } @@ -201,7 +197,7 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) return ldb_oom(ldb); } - cmp = ldb_dn_compare(parent_dn, schema->base_dn); + cmp = ldb_dn_compare(parent_dn, mc->schema_dn); if (cmp != 0) { ldb_debug_set(ldb, LDB_DEBUG_ERROR, "schema_data_add: no direct child :%s\n", @@ -257,6 +253,8 @@ static int schema_data_modify(struct ldb_module *module, struct ldb_request *req bool rodc = false; int ret; struct ldb_control *sd_propagation_control; + struct schema_data_private_data *mc; + mc = talloc_get_type(ldb_module_get_private(module), struct schema_data_private_data); ldb = ldb_module_get_ctx(module); @@ -295,7 +293,7 @@ static int schema_data_modify(struct ldb_module *module, struct ldb_request *req return ldb_next_request(module, req); } - cmp = ldb_dn_compare(req->op.mod.message->dn, schema->base_dn); + cmp = ldb_dn_compare(req->op.mod.message->dn, mc->schema_dn); if (cmp == 0) { static const char * const constrained_attrs[] = { "schemaInfo", diff --git a/source4/dsdb/samdb/ldb_modules/schema_load.c b/source4/dsdb/samdb/ldb_modules/schema_load.c index faaf3f2071c..17c20338b81 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_load.c +++ b/source4/dsdb/samdb/ldb_modules/schema_load.c @@ -39,7 +39,10 @@ struct schema_load_private_data { struct tdb_wrap *metadata; }; -static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_dn, uint64_t current_usn, +static int dsdb_schema_from_db(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + uint64_t current_usn, + uint64_t schema_seq_num, struct dsdb_schema **schema); /* @@ -68,13 +71,13 @@ static int schema_metadata_open(struct ldb_module *module) } sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url"); - if (strncmp("tdb://", sam_name, 6) == 0) { - sam_name += 6; - } if (!sam_name) { talloc_free(tmp_ctx); return ldb_operr(ldb); } + if (strncmp("tdb://", sam_name, 6) == 0) { + sam_name += 6; + } filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name); if (!filename) { talloc_free(tmp_ctx); @@ -113,8 +116,8 @@ static int schema_metadata_get_uint64(struct ldb_module *module, TALLOC_CTX *tmp_ctx; if (!data || !data->metadata) { - return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR, - "schema: metadata tdb not initialized"); + *value = default_value; + return LDB_SUCCESS; } tmp_ctx = talloc_new(NULL); @@ -155,12 +158,15 @@ static int schema_metadata_get_uint64(struct ldb_module *module, return LDB_SUCCESS; } -static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct dsdb_schema *schema, bool is_global_schema) +static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct tevent_context *ev, + struct dsdb_schema *schema, bool is_global_schema) { - uint64_t current_usn, value; + TALLOC_CTX *mem_ctx; + uint64_t current_usn, schema_seq_num = 0; int ret; struct ldb_context *ldb = ldb_module_get_ctx(module); struct dsdb_schema *new_schema; + struct ldb_dn *schema_dn = ldb_get_schema_basedn(ldb); time_t ts, lastts; struct schema_load_private_data *private_data = talloc_get_type(ldb_module_get_private(module), struct schema_load_private_data); @@ -174,11 +180,11 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct return schema; } - lastts = schema->last_refresh; - ts = time(NULL); - if (lastts > (ts - schema->refresh_interval)) { - DEBUG(11, ("Less than %d seconds since last reload, returning cached version ts = %d\n", (int)schema->refresh_interval, (int)lastts)); - return schema; + SMB_ASSERT(ev == ldb_get_event_context(ldb)); + + mem_ctx = talloc_new(module); + if (mem_ctx == NULL) { + return NULL; } /* @@ -189,29 +195,59 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct * continue to hit the database to get the highest USN. */ - ret = schema_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0); - if (ret == LDB_SUCCESS) { - schema->metadata_usn = value; - } else { - /* From an old provision it can happen that the tdb didn't exists yet */ - DEBUG(0, ("Error while searching for the schema usn in the metadata\n")); - schema->metadata_usn = 0; + ret = schema_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &schema_seq_num, 0); + + if (schema != NULL) { + lastts = schema->last_refresh; + ts = time(NULL); + if (lastts > (ts - schema->refresh_interval)) { + DEBUG(11, ("Less than %d seconds since last reload, " + "returning cached version ts = %d\n", + (int)schema->refresh_interval, + (int)lastts)); + TALLOC_FREE(mem_ctx); + return schema; + } + + if (ret == LDB_SUCCESS) { + schema->metadata_usn = schema_seq_num; + } else { + /* From an old provision it can happen that the tdb didn't exists yet */ + DEBUG(0, ("Error while searching for the schema usn in the metadata ignoring: %d:%s:%s\n", + ret, ldb_strerror(ret), ldb_errstring(ldb))); + schema->metadata_usn = 0; + } + schema->last_refresh = ts; + } - schema->last_refresh = ts; - ret = dsdb_module_load_partition_usn(module, schema->base_dn, ¤t_usn, NULL, NULL); - if (ret != LDB_SUCCESS || current_usn == schema->loaded_usn) { + ret = dsdb_module_load_partition_usn(module, schema_dn, ¤t_usn, NULL, NULL); + if (ret != LDB_SUCCESS || (schema && (current_usn == schema->loaded_usn))) { + TALLOC_FREE(mem_ctx); return schema; } - ret = dsdb_schema_from_db(module, schema->base_dn, current_usn, &new_schema); + ret = dsdb_schema_from_db(module, mem_ctx, current_usn, schema_seq_num, &new_schema); if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "dsdb_schema_from_db() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + TALLOC_FREE(mem_ctx); return schema; } + ret = dsdb_set_schema(ldb, new_schema); + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "dsdb_set_schema() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + TALLOC_FREE(mem_ctx); + return schema; + } if (is_global_schema) { dsdb_make_schema_global(ldb, new_schema); } + TALLOC_FREE(mem_ctx); return new_schema; } @@ -220,13 +256,17 @@ static struct dsdb_schema *dsdb_schema_refresh(struct ldb_module *module, struct Given an LDB module (pointing at the schema DB), and the DN, set the populated schema */ -static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_dn, uint64_t current_usn, +static int dsdb_schema_from_db(struct ldb_module *module, + TALLOC_CTX *mem_ctx, + uint64_t current_usn, + uint64_t schema_seq_num, struct dsdb_schema **schema) { struct ldb_context *ldb = ldb_module_get_ctx(module); TALLOC_CTX *tmp_ctx; char *error_string; int ret; + struct ldb_dn *schema_dn = ldb_get_schema_basedn(ldb); struct ldb_result *schema_res; struct ldb_result *res; static const char *schema_attrs[] = { @@ -289,37 +329,11 @@ static int dsdb_schema_from_db(struct ldb_module *module, struct ldb_dn *schema_ goto failed; } - (*schema)->refresh_in_progress = true; - - /* If we have the readOnlySchema opaque, then don't check for - * runtime schema updates, as they are not permitted (we would - * have to update the backend server schema too */ - if (!ldb_get_opaque(ldb, "readOnlySchema")) { - (*schema)->refresh_fn = dsdb_schema_refresh; - (*schema)->loaded_from_module = module; - (*schema)->loaded_usn = current_usn; - } - - /* "dsdb_set_schema()" steals schema into the ldb_context */ - ret = dsdb_set_schema(ldb, (*schema)); - - (*schema)->refresh_in_progress = false; + (*schema)->loaded_usn = current_usn; + (*schema)->metadata_usn = schema_seq_num; (*schema)->last_refresh = time(NULL); - if (ret != LDB_SUCCESS) { - ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "schema_load_init: dsdb_set_schema() failed: %d:%s: %s", - ret, ldb_strerror(ret), ldb_errstring(ldb)); - goto failed; - } - - /* Ensure this module won't go away before the callback. This - * causes every schema to have the LDB that originally loaded - * the first schema as a talloc child. */ - if (talloc_reference(*schema, ldb) == NULL) { - ldb_oom(ldb); - ret = LDB_ERR_OPERATIONS_ERROR; - } + talloc_steal(mem_ctx, *schema); failed: if (flags & LDB_FLG_ENABLE_TRACING) { @@ -334,11 +348,10 @@ failed: static int schema_load_init(struct ldb_module *module) { struct schema_load_private_data *private_data; - struct dsdb_schema *schema; struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema; + void *readOnlySchema; int ret; - uint64_t current_usn; - struct ldb_dn *schema_dn; private_data = talloc_zero(module, struct schema_load_private_data); if (private_data == NULL) { @@ -352,39 +365,69 @@ static int schema_load_init(struct ldb_module *module) return ret; } - if (dsdb_get_schema(ldb, NULL)) { - return LDB_SUCCESS; - } + schema = dsdb_get_schema(ldb, NULL); + + /* We might already have a schema */ + if (schema != NULL) { + /* Hook up the refresh function */ + if (dsdb_uses_global_schema(ldb)) { + ret = dsdb_set_schema_refresh_function(ldb, dsdb_schema_refresh, module); + + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_set_schema_refresh_fns() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + return ret; + } + } - schema_dn = ldb_get_schema_basedn(ldb); - if (!schema_dn) { - ldb_reset_err_string(ldb); - ldb_debug(ldb, LDB_DEBUG_WARNING, - "schema_load_init: no schema dn present: (skip schema loading)\n"); return LDB_SUCCESS; } - ret = dsdb_module_load_partition_usn(module, schema_dn, ¤t_usn, NULL, NULL); - if (ret != LDB_SUCCESS) { - /* Ignore the error and just reload the DB more often */ - current_usn = 0; - } + readOnlySchema = ldb_get_opaque(ldb, "readOnlySchema"); - ret = dsdb_schema_from_db(module, schema_dn, current_usn, &schema); - /* We don't care too much on the result of this action - * the most probable reason for this to fail is that the tdb didn't - * exists yet and this will be corrected by the partition module. - */ - if (ret == LDB_SUCCESS && schema_metadata_open(module) == LDB_SUCCESS) { - uint64_t value; + /* If we have the readOnlySchema opaque, then don't check for + * runtime schema updates, as they are not permitted (we would + * have to update the backend server schema too */ + if (readOnlySchema != NULL) { + struct dsdb_schema *new_schema; + ret = dsdb_schema_from_db(module, private_data, 0, 0, &new_schema); + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_schema_from_db() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + return ret; + } - ret = schema_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0); - if (ret == LDB_SUCCESS) { - schema->metadata_usn = value; - } else { - schema->metadata_usn = 0; + /* "dsdb_set_schema()" steals schema into the ldb_context */ + ret = dsdb_set_schema(ldb, new_schema); + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_set_schema() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + return ret; + } + + } else { + ret = dsdb_set_schema_refresh_function(ldb, dsdb_schema_refresh, module); + + if (ret != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_set_schema_refresh_fns() failed: %d:%s: %s", + ret, ldb_strerror(ret), ldb_errstring(ldb)); + return ret; } } + + schema = dsdb_get_schema(ldb, NULL); + + /* We do this, invoking the refresh handler, so we know that it works */ + if (schema == NULL) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "schema_load_init: dsdb_get_schema failed"); + return LDB_ERR_OPERATIONS_ERROR; + } + return ret; } diff --git a/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c b/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c index e3d8485c611..284aa1b6e2d 100644 --- a/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c +++ b/source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c @@ -489,12 +489,12 @@ static int secrets_tdb_sync_init(struct ldb_module *module) ldb_module_set_private(module, data); secrets_ldb = (const char *)ldb_get_opaque(ldb, "ldb_url"); - if (strncmp("tdb://", secrets_ldb, 6) == 0) { - secrets_ldb += 6; - } if (!secrets_ldb) { return ldb_operr(ldb); } + if (strncmp("tdb://", secrets_ldb, 6) == 0) { + secrets_ldb += 6; + } private_dir = talloc_strdup(data, secrets_ldb); p = strrchr(private_dir, '/'); if (p) { diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index 451c7a1c666..87e3c65ef83 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -362,7 +362,7 @@ static const struct ldb_map_attribute entryuuid_attributes[] = }, { .local_name = "distinguishedName", - .type = LDB_MAP_RENAME, + .type = LDB_MAP_RENDROP, .u = { .rename = { .remote_name = "entryDN" diff --git a/source4/dsdb/samdb/ldb_modules/update_keytab.c b/source4/dsdb/samdb/ldb_modules/update_keytab.c index bec4a83abfc..ebf77dc9a82 100644 --- a/source4/dsdb/samdb/ldb_modules/update_keytab.c +++ b/source4/dsdb/samdb/ldb_modules/update_keytab.c @@ -377,7 +377,8 @@ static int update_kt_prepare_commit(struct ldb_module *module) struct update_kt_private *data = talloc_get_type(ldb_module_get_private(module), struct update_kt_private); struct dn_list *p; struct smb_krb5_context *smb_krb5_context; - int krb5_ret = smb_krb5_init_context(data, ldb_get_event_context(ldb), ldb_get_opaque(ldb, "loadparm"), + int krb5_ret = smb_krb5_init_context(data, + ldb_get_opaque(ldb, "loadparm"), &smb_krb5_context); TALLOC_CTX *tmp_ctx; @@ -397,7 +398,7 @@ static int update_kt_prepare_commit(struct ldb_module *module) const char *realm; char *upper_realm; struct ldb_message_element *spn_el = ldb_msg_find_element(p->msg, "servicePrincipalName"); - char **SPNs = NULL; + const char **SPNs = NULL; int num_SPNs = 0; int i; @@ -411,13 +412,13 @@ static int update_kt_prepare_commit(struct ldb_module *module) } num_SPNs = spn_el->num_values; - SPNs = talloc_array(tmp_ctx, char *, num_SPNs); + SPNs = talloc_array(tmp_ctx, const char *, num_SPNs); if (!SPNs) { ldb_oom(ldb); goto fail; } for (i = 0; i < num_SPNs; i++) { - SPNs[i] = talloc_asprintf(tmp_ctx, "%*.*s@%s", + SPNs[i] = talloc_asprintf(SPNs, "%*.*s@%s", (int)spn_el->values[i].length, (int)spn_el->values[i].length, (const char *)spn_el->values[i].data, @@ -432,7 +433,7 @@ static int update_kt_prepare_commit(struct ldb_module *module) krb5_ret = smb_krb5_update_keytab(tmp_ctx, smb_krb5_context->krb5_context, keytab_name_from_msg(tmp_ctx, ldb, p->msg), ldb_msg_find_attr_as_string(p->msg, "samAccountName", NULL), - realm, (const char **)SPNs, num_SPNs, + realm, SPNs, num_SPNs, ldb_msg_find_attr_as_string(p->msg, "saltPrincipal", NULL), ldb_msg_find_attr_as_string(p->msg, "secret", NULL), ldb_msg_find_attr_as_string(p->msg, "priorSecret", NULL), diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index f7803e56cb1..8d587a4cb38 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -174,6 +174,19 @@ int dsdb_module_search_tree(struct ldb_module *module, ret = ldb_wait(req->handle, LDB_WAIT_ALL); } + if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) { + if (res->count == 0) { + talloc_free(tmp_ctx); + ldb_reset_err_string(ldb_module_get_ctx(module)); + return LDB_ERR_NO_SUCH_OBJECT; + } + if (res->count != 1) { + talloc_free(tmp_ctx); + ldb_reset_err_string(ldb_module_get_ctx(module)); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + } + talloc_free(req); if (ret == LDB_SUCCESS) { *_res = talloc_steal(mem_ctx, res); |