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 | |
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')
32 files changed, 839 insertions, 368 deletions
diff --git a/source4/dsdb/common/tests/dsdb_dn.c b/source4/dsdb/common/tests/dsdb_dn.c index 9ae0c8a0494..66c7e125a47 100644 --- a/source4/dsdb/common/tests/dsdb_dn.c +++ b/source4/dsdb/common/tests/dsdb_dn.c @@ -77,6 +77,13 @@ static bool torture_dsdb_dn_attrs(struct torture_context *torture) syntax->comparison_fn(ldb, mem_ctx, &dn1, &dn2) != 0, "compare of binary+dn an dn should have failed"); + /* Test compare (false) with different binary prefix */ + dn1 = data_blob_string_const("B:6:abcdef:dc=samba,dc=org"); + dn2 = data_blob_string_const("B:4:abcd:dc=samba,dc=org"); + torture_assert(torture, + syntax->comparison_fn(ldb, mem_ctx, &dn1, &dn2) != 0, + "compare of binary+dn an dn should have failed"); + /* Test DN+String behaviour */ torture_assert(torture, syntax = ldb_samba_syntax_by_name(ldb, DSDB_SYNTAX_STRING_DN), "Failed to get DN+String schema attribute"); @@ -107,6 +114,13 @@ static bool torture_dsdb_dn_attrs(struct torture_context *torture) syntax->comparison_fn(ldb, mem_ctx, &dn1, &dn2) != 0, "compare of string+dn an dn should have failed"); + /* Test compare (false) with different string prefix */ + dn1 = data_blob_string_const("S:6:abcdef:dc=samba,dc=org"); + dn2 = data_blob_string_const("S:6:abcXYZ:dc=samba,dc=org"); + torture_assert(torture, + syntax->comparison_fn(ldb, mem_ctx, &dn1, &dn2) != 0, + "compare of string+dn an dn should have failed"); + talloc_free(mem_ctx); return true; } diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 904ca1dcc9a..0807e899e61 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -650,27 +650,42 @@ uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ct return acct_flags; } -struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx, - struct ldb_message *msg, - const char *attr) +NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx, + struct ldb_message *msg, + const char *attr, + struct lsa_BinaryString *s) { - struct lsa_BinaryString s; + int i; const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); - ZERO_STRUCT(s); + ZERO_STRUCTP(s); if (!val) { - return s; + return NT_STATUS_OK; + } + + if ((val->length % 2) != 0) { + /* + * If the on-disk data is not even in length, we know + * it is corrupt, and can not be safely pushed. We + * would either truncate, send either a un-initilaised + * byte or send a forced zero byte + */ + return NT_STATUS_INTERNAL_DB_CORRUPTION; } - s.array = talloc_array(mem_ctx, uint16_t, val->length/2); - if (!s.array) { - return s; + s->array = talloc_array(mem_ctx, uint16_t, val->length/2); + if (!s->array) { + return NT_STATUS_NO_MEMORY; } - s.length = s.size = val->length; - memcpy(s.array, val->data, val->length); + s->length = s->size = val->length; - return s; + /* The on-disk format is the 'network' format, being UTF16LE (sort of) */ + for (i = 0; i < s->length / 2; i++) { + s->array[i] = SVAL(val->data, i * 2); + } + + return NT_STATUS_OK; } /* Find an attribute, with a particular value */ @@ -978,10 +993,26 @@ int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr_name, struct lsa_BinaryString *parameters) { + int i; struct ldb_val val; + if ((parameters->length % 2) != 0) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + + val.data = talloc_array(mem_ctx, uint8_t, parameters->length); + if (val.data == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } val.length = parameters->length; - val.data = (uint8_t *)parameters->array; - return ldb_msg_add_value(msg, attr_name, &val, NULL); + for (i = 0; i < parameters->length / 2; i++) { + /* + * The on-disk format needs to be in the 'network' + * format, parmeters->array is a uint16_t array of + * length parameters->length / 2 + */ + SSVAL(val.data, i * 2, parameters->array[i]); + } + return ldb_msg_add_steal_value(msg, attr_name, &val); } /* diff --git a/source4/dsdb/kcc/kcc_deleted.c b/source4/dsdb/kcc/kcc_deleted.c index 63bb97c08dc..93d74ca3a3d 100644 --- a/source4/dsdb/kcc/kcc_deleted.c +++ b/source4/dsdb/kcc/kcc_deleted.c @@ -128,7 +128,7 @@ NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx) whenChanged = ldb_string_to_time(tstring); } if (t - whenChanged > tombstoneLifetime*60*60*24) { - ret = dsdb_delete(s->samdb, res->msgs[i]->dn, DSDB_SEARCH_SHOW_DELETED); + ret = dsdb_delete(s->samdb, res->msgs[i]->dn, DSDB_SEARCH_SHOW_RECYCLED|DSDB_MODIFY_RELAX); if (ret != LDB_SUCCESS) { DEBUG(1,(__location__ ": Failed to remove deleted object %s\n", ldb_dn_get_linearized(res->msgs[i]->dn))); diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c index 8ddce322696..bd788ddf4ab 100644 --- a/source4/dsdb/repl/drepl_out_helpers.c +++ b/source4/dsdb/repl/drepl_out_helpers.c @@ -67,14 +67,17 @@ struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx, state->conn = conn; state->drsuapi = conn->drsuapi; - if (state->drsuapi && !state->drsuapi->pipe->conn->dead) { - tevent_req_done(req); - return tevent_req_post(req, ev); - } + if (state->drsuapi != NULL) { + struct dcerpc_binding_handle *b = + state->drsuapi->pipe->binding_handle; + bool is_connected = dcerpc_binding_handle_is_connected(b); + + if (is_connected) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } - if (state->drsuapi && state->drsuapi->pipe->conn->dead) { - talloc_free(state->drsuapi); - conn->drsuapi = NULL; + TALLOC_FREE(conn->drsuapi); } state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection); @@ -379,6 +382,7 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req) NTSTATUS status; uint32_t replica_flags; struct drsuapi_DsReplicaHighWaterMark highwatermark; + struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb); r = talloc(state, struct drsuapi_DsGetNCChanges); if (tevent_req_nomem(r, req)) { @@ -426,7 +430,7 @@ static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req) replica_flags &= ~DRSUAPI_DRS_WRIT_REP; } else if (partition->rodc_replica) { bool for_schema = false; - if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) { + if (ldb_dn_compare_base(schema_dn, partition->dn) == 0) { for_schema = true; } @@ -613,6 +617,7 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req struct dreplsrv_service *service = state->op->service; struct dreplsrv_partition *partition = state->op->source_dsa->partition; struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi; + struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb); struct dsdb_schema *schema; struct dsdb_schema *working_schema = NULL; const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr; @@ -669,20 +674,23 @@ static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req * Decide what working schema to use for object conversion. * We won't need a working schema for empty replicas sent. */ - if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) { - /* create working schema to convert objects with */ - status = dsdb_repl_make_working_schema(service->samdb, - schema, - mapping_ctr, - object_count, - first_object, - &drsuapi->gensec_skey, - state, &working_schema); - if (!W_ERROR_IS_OK(status)) { - DEBUG(0,("Failed to create working schema: %s\n", - win_errstr(status))); - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); - return; + if (first_object) { + bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0; + if (is_schema) { + /* create working schema to convert objects with */ + status = dsdb_repl_make_working_schema(service->samdb, + schema, + mapping_ctr, + object_count, + first_object, + &drsuapi->gensec_skey, + state, &working_schema); + if (!W_ERROR_IS_OK(status)) { + DEBUG(0,("Failed to create working schema: %s\n", + win_errstr(status))); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } } } diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index d1d69fa8f8c..97b8b2a7a3a 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -834,13 +834,6 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb, return WERR_FOOBAR; } - /* if this replication partner didn't need to be notified - before this transaction then it still doesn't need to be - notified, as the changes came from this server */ - if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) { - *notify_uSN = seq_num2; - } - ret = ldb_transaction_commit(ldb); if (ret != LDB_SUCCESS) { /* restore previous schema */ @@ -854,6 +847,13 @@ WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb, return WERR_FOOBAR; } + /* if this replication partner didn't need to be notified + before this transaction then it still doesn't need to be + notified, as the changes came from this server */ + if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) { + *notify_uSN = seq_num2; + } + /* * Reset the Schema used by ldb. This will lead to * a schema cache being refreshed from database. diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c index 0c4cdfc2d3f..5e97efcee3f 100644 --- a/source4/dsdb/samdb/cracknames.c +++ b/source4/dsdb/samdb/cracknames.c @@ -468,7 +468,9 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, /* TODO: - fill the correct names in all cases! * - handle format_flags */ - + if (format_desired == DRSUAPI_DS_NAME_FORMAT_UNKNOWN) { + return WERR_OK; + } /* here we need to set the domain_filter and/or the result_filter */ switch (format_offered) { case DRSUAPI_DS_NAME_FORMAT_UNKNOWN: @@ -488,7 +490,10 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, if (!W_ERROR_IS_OK(werr)) { return werr; } - if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) { + if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND && + (formats[i] != DRSUAPI_DS_NAME_FORMAT_CANONICAL || + info1->status != DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR)) + { return werr; } } @@ -574,8 +579,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, } domain_filter = talloc_asprintf(mem_ctx, - "(&(objectClass=crossRef)(|(dnsRoot=%s)(netbiosName=%s))(systemFlags:%s:=%u))", - ldb_binary_encode_string(mem_ctx, domain), + "(&(objectClass=crossRef)(netbiosName=%s)(systemFlags:%s:=%u))", ldb_binary_encode_string(mem_ctx, domain), LDB_OID_COMPARATOR_AND, SYSTEM_FLAG_CR_NTDS_DOMAIN); @@ -659,7 +663,6 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, char *unparsed_name; ret = smb_krb5_init_context(mem_ctx, - ldb_get_event_context(sam_ctx), (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), &smb_krb5_context); @@ -700,7 +703,6 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, char *service; ret = smb_krb5_init_context(mem_ctx, - ldb_get_event_context(sam_ctx), (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"), &smb_krb5_context); @@ -931,9 +933,25 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ int ret; struct ldb_result *res; uint32_t dsdb_flags = 0; - struct ldb_dn *real_search_dn; + struct ldb_dn *real_search_dn = NULL; + info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND; - if (domain_res) { + /* + * From 4.1.4.2.11 of MS-DRSR + * if DS_NAME_FLAG_GCVERIFY in flags then + * rt := select all O from all + * where attrValue in GetAttrVals(O, att, false) + * else + * rt := select all O from subtree DefaultNC() + * where attrValue in GetAttrVals(O, att, false) + * endif + * return rt + */ + if (format_flags & DRSUAPI_DS_NAME_FLAG_GCVERIFY || + format_offered == DRSUAPI_DS_NAME_FORMAT_GUID) + { + dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS; + } else if (domain_res) { if (!search_dn) { struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL); real_search_dn = tmp_dn; @@ -941,13 +959,11 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ real_search_dn = search_dn; } } else { - dsdb_flags = DSDB_SEARCH_SEARCH_ALL_PARTITIONS; - real_search_dn = NULL; + real_search_dn = ldb_get_default_basedn(sam_ctx); } if (format_desired == DRSUAPI_DS_NAME_FORMAT_GUID){ dsdb_flags |= DSDB_SEARCH_SHOW_RECYCLED; } - /* search with the 'phantom root' flag */ ret = dsdb_search(sam_ctx, mem_ctx, &res, real_search_dn, 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); diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c index 361ece79f0a..4584a61d475 100644 --- a/source4/dsdb/samdb/samdb.c +++ b/source4/dsdb/samdb/samdb.c @@ -54,7 +54,6 @@ struct ldb_context *samdb_connect_url(TALLOC_CTX *mem_ctx, unsigned int flags, const char *url) { struct ldb_context *ldb; - struct dsdb_schema *schema; int ret; ldb = ldb_wrap_find(url, ev_ctx, lp_ctx, session_info, NULL, flags); @@ -74,12 +73,6 @@ struct ldb_context *samdb_connect_url(TALLOC_CTX *mem_ctx, return NULL; } - schema = dsdb_get_schema(ldb, NULL); - /* make the resulting schema global */ - if (schema) { - dsdb_make_schema_global(ldb, schema); - } - if (!ldb_wrap_add(url, ev_ctx, lp_ctx, session_info, NULL, flags, ldb)) { talloc_free(ldb); return NULL; diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 7605c65cdd7..7f77d4e3827 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -244,6 +244,7 @@ struct dsdb_extended_sec_desc_propagation_op { }; #define DSDB_ACL_CHECKS_DIRSYNC_FLAG 0x1 +#define DSDB_SAMDB_MINIMUM_ALLOWED_RID 1000 #define DSDB_METADATA_SCHEMA_SEQ_NUM "SCHEMA_SEQ_NUM" #endif /* __SAMDB_H__ */ diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index 538b8581234..457d986e3d0 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -74,6 +74,7 @@ struct dsdb_syntax { const struct dsdb_attribute *attr, const struct ldb_message_element *in); bool auto_normalise; + bool userParameters; /* Indicates the syntax userParameters should be forced to */ }; struct dsdb_attribute { @@ -201,8 +202,6 @@ struct dsdb_schema_info { struct dsdb_schema { - struct ldb_dn *base_dn; - struct dsdb_schema_prefixmap *prefixmap; /* @@ -250,8 +249,6 @@ struct dsdb_schema { } fsmo; /* Was this schema loaded from ldb (if so, then we will reload it when we detect a change in ldb) */ - struct ldb_module *loaded_from_module; - struct dsdb_schema *(*refresh_fn)(struct ldb_module *module, struct dsdb_schema *schema, bool is_global_schema); bool refresh_in_progress; time_t ts_last_change; time_t last_refresh; @@ -282,6 +279,11 @@ enum dsdb_schema_convert_target { TARGET_AD_SCHEMA_SUBENTRY }; +struct ldb_module; + +typedef struct dsdb_schema *(*dsdb_schema_refresh_fn)(struct ldb_module *module, + struct tevent_context *ev, + struct dsdb_schema *schema, bool is_global_schema); #include "dsdb/schema/proto.h" #endif /* _DSDB_SCHEMA_H */ diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index efbd38a4ba3..d0388079241 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -58,12 +58,6 @@ struct dsdb_schema *dsdb_schema_copy_shallow(TALLOC_CTX *mem_ctx, return NULL; } - /* schema base_dn */ - schema_copy->base_dn = ldb_dn_copy(schema_copy, schema->base_dn); - if (!schema_copy->base_dn) { - goto failed; - } - /* copy prexiMap & schemaInfo */ schema_copy->prefixmap = dsdb_schema_pfm_copy_shallow(schema_copy, schema->prefixmap); @@ -103,8 +97,6 @@ struct dsdb_schema *dsdb_schema_copy_shallow(TALLOC_CTX *mem_ctx, } /* leave reload_seq_number = 0 so it will be refresh ASAP */ - schema_copy->refresh_fn = schema->refresh_fn; - schema_copy->loaded_from_module = schema->loaded_from_module; return schema_copy; @@ -931,8 +923,6 @@ int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb, false); } - schema->base_dn = talloc_steal(schema, schema_res->msgs[0]->dn); - prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap"); if (!prefix_val) { *error_string = talloc_asprintf(mem_ctx, diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index ce8facbef3c..6029e46a7a1 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -443,6 +443,26 @@ failed: * Attach the schema to an opaque pointer on the ldb, * so ldb modules can find it */ +int dsdb_set_schema_refresh_function(struct ldb_context *ldb, + dsdb_schema_refresh_fn refresh_fn, + struct ldb_module *module) +{ + int ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_fn", refresh_fn); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_fn_private_data", module); + if (ret != LDB_SUCCESS) { + return ret; + } + return LDB_SUCCESS; +} + +/** + * Attach the schema to an opaque pointer on the ldb, + * so ldb modules can find it + */ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) { struct dsdb_schema *old_schema; @@ -467,6 +487,8 @@ int dsdb_set_schema(struct ldb_context *ldb, struct dsdb_schema *schema) talloc_steal(ldb, schema); } + talloc_steal(ldb, schema); + ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", NULL); if (ret != LDB_SUCCESS) { return ret; @@ -518,6 +540,16 @@ int dsdb_reference_schema(struct ldb_context *ldb, struct dsdb_schema *schema, return ret; } + ret = ldb_set_opaque(ldb, "dsdb_refresh_fn", NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_set_opaque(ldb, "dsdb_refresh_fn_private_data", NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + ret = dsdb_schema_set_indices_and_attributes(ldb, schema, write_indices_and_attributes); if (ret != LDB_SUCCESS) { return ret; @@ -533,14 +565,15 @@ int dsdb_set_global_schema(struct ldb_context *ldb) { int ret; void *use_global_schema = (void *)1; - if (!global_schema) { - return LDB_SUCCESS; - } ret = ldb_set_opaque(ldb, "dsdb_use_global_schema", use_global_schema); if (ret != LDB_SUCCESS) { return ret; } + if (global_schema == NULL) { + return LDB_SUCCESS; + } + /* Set the new attributes based on the new schema */ ret = dsdb_schema_set_indices_and_attributes(ldb, global_schema, false /* Don't write indices and attributes, it's expensive */); if (ret == LDB_SUCCESS) { @@ -567,11 +600,13 @@ bool dsdb_uses_global_schema(struct ldb_context *ldb) struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *reference_ctx) { const void *p; - struct dsdb_schema *schema_out; - struct dsdb_schema *schema_in; + struct dsdb_schema *schema_out = NULL; + struct dsdb_schema *schema_in = NULL; + dsdb_schema_refresh_fn refresh_fn; + struct ldb_module *loaded_from_module; bool use_global_schema; TALLOC_CTX *tmp_ctx = talloc_new(reference_ctx); - if (!tmp_ctx) { + if (tmp_ctx == NULL) { return NULL; } @@ -581,29 +616,38 @@ struct dsdb_schema *dsdb_get_schema(struct ldb_context *ldb, TALLOC_CTX *referen schema_in = global_schema; } else { p = ldb_get_opaque(ldb, "dsdb_schema"); - - schema_in = talloc_get_type(p, struct dsdb_schema); - if (!schema_in) { - talloc_free(tmp_ctx); - return NULL; + if (p != NULL) { + schema_in = talloc_get_type_abort(p, struct dsdb_schema); } } - if (schema_in->refresh_fn && !schema_in->refresh_in_progress) { - if (!talloc_reference(tmp_ctx, schema_in)) { - /* - * ensure that the schema_in->refresh_in_progress - * remains valid for the right amount of time - */ - talloc_free(tmp_ctx); - return NULL; + refresh_fn = ldb_get_opaque(ldb, "dsdb_schema_refresh_fn"); + if (refresh_fn) { + loaded_from_module = ldb_get_opaque(ldb, "dsdb_schema_refresh_fn_private_data"); + + SMB_ASSERT(loaded_from_module && (ldb_module_get_ctx(loaded_from_module) == ldb)); + } + + if (refresh_fn) { + /* We need to guard against recurisve calls here */ + if (ldb_set_opaque(ldb, "dsdb_schema_refresh_fn", NULL) != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "dsdb_get_schema: clearing dsdb_schema_refresh_fn failed"); + } else { + schema_out = refresh_fn(loaded_from_module, + ldb_get_event_context(ldb), + schema_in, + use_global_schema); + } + if (ldb_set_opaque(ldb, "dsdb_schema_refresh_fn", refresh_fn) != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "dsdb_get_schema: re-setting dsdb_schema_refresh_fn failed"); + } + if (!schema_out) { + schema_out = schema_in; + ldb_debug_set(ldb, LDB_DEBUG_FATAL, + "dsdb_get_schema: refresh_fn() failed"); } - schema_in->refresh_in_progress = true; - /* This may change schema, if it needs to reload it from disk */ - schema_out = schema_in->refresh_fn(schema_in->loaded_from_module, - schema_in, - use_global_schema); - schema_in->refresh_in_progress = false; } else { schema_out = schema_in; } @@ -763,10 +807,6 @@ WERROR dsdb_set_schema_from_ldif(struct ldb_context *ldb, if (!schema) { goto nomem; } - schema->base_dn = ldb_dn_new(schema, ldb, dn); - if (!schema->base_dn) { - goto nomem; - } schema->fsmo.we_are_master = true; schema->fsmo.update_allowed = true; schema->fsmo.master_dn = ldb_dn_new(schema, ldb, "@PROVISION_SCHEMA_MASTER"); diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index c2e02082582..c9ff588880b 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -2395,6 +2395,7 @@ static const struct dsdb_syntax dsdb_syntaxes[] = { .validate_ldb = dsdb_syntax_DATA_BLOB_validate_ldb, .equality = "octetStringMatch", .comment = "Octet String", + .userParameters = true },{ .name = "String(Sid)", .ldap_oid = LDB_SYNTAX_OCTET_STRING, @@ -2665,6 +2666,16 @@ const struct dsdb_syntax *dsdb_syntax_for_attribute(const struct dsdb_attribute unsigned int i; for (i=0; i < ARRAY_SIZE(dsdb_syntaxes); i++) { + /* + * We must pretend that userParamters was declared + * binary string, so we can store the 'UTF16' (not + * really string) structure as given over SAMR to samba + */ + if (dsdb_syntaxes[i].userParameters && + (strcasecmp(attr->lDAPDisplayName, "userParameters") == 0)) + { + return &dsdb_syntaxes[i]; + } if (attr->oMSyntax != dsdb_syntaxes[i].oMSyntax) continue; if (attr->oMObjectClass.length != dsdb_syntaxes[i].oMObjectClass.length) continue; diff --git a/source4/dsdb/tests/python/acl.py b/source4/dsdb/tests/python/acl.py index ecda3c5db61..7439be68d01 100755 --- a/source4/dsdb/tests/python/acl.py +++ b/source4/dsdb/tests/python/acl.py @@ -1250,6 +1250,32 @@ class AclRenameTests(AclTests): res = self.ldb_admin.search(self.base_dn, expression="(distinguishedName=%s)" % ou3_dn) self.assertNotEqual(len(res), 0) + def test_rename_u9(self): + """Rename 'User object' cross OU, with explicit deny on sd and dc""" + ou1_dn = "OU=test_rename_ou1," + self.base_dn + ou2_dn = "OU=test_rename_ou2," + self.base_dn + user_dn = "CN=test_rename_user2," + ou1_dn + rename_user_dn = "CN=test_rename_user5," + ou2_dn + # Create OU structure + self.ldb_admin.create_ou(ou1_dn) + self.ldb_admin.create_ou(ou2_dn) + self.ldb_admin.newuser(self.testuser2, self.user_pass, userou=self.ou1) + mod = "(D;;SD;;;DA)" + self.sd_utils.dacl_add_ace(user_dn, mod) + mod = "(D;;DC;;;DA)" + self.sd_utils.dacl_add_ace(ou1_dn, mod) + # Rename 'User object' having SD and CC to AU + try: + self.ldb_admin.rename(user_dn, rename_user_dn) + except LdbError, (num, _): + self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS) + else: + self.fail() + #add an allow ace so we can delete this ou + mod = "(A;;DC;;;DA)" + self.sd_utils.dacl_add_ace(ou1_dn, mod) + + #tests on Control Access Rights class AclCARTests(AclTests): diff --git a/source4/dsdb/tests/python/ldap.py b/source4/dsdb/tests/python/ldap.py index f44f4eaf57a..f6b08e4cf3f 100755 --- a/source4/dsdb/tests/python/ldap.py +++ b/source4/dsdb/tests/python/ldap.py @@ -667,7 +667,7 @@ class BasicTests(samba.tests.TestCase): def test_single_valued_attributes(self): """Test single-valued attributes""" - print "Test single-valued attributes""" + print "Test single-valued attributes" try: self.ldb.add({ @@ -767,7 +767,7 @@ class BasicTests(samba.tests.TestCase): def test_empty_messages(self): """Test empty messages""" - print "Test empty messages""" + print "Test empty messages" m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) @@ -788,7 +788,7 @@ class BasicTests(samba.tests.TestCase): def test_empty_attributes(self): """Test empty attributes""" - print "Test empty attributes""" + print "Test empty attributes" m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) @@ -900,6 +900,17 @@ class BasicTests(samba.tests.TestCase): delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) + #only write is allowed with NC_HEAD for originating updates + try: + self.ldb.add({ + "dn": "cn=ldaptestuser2,cn=users," + self.base_dn, + "objectclass": "user", + "instanceType": "3" }) + self.fail() + except LdbError, (num, _): + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) + delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn) + def test_distinguished_name(self): """Tests the 'distinguishedName' attribute""" print "Tests the 'distinguishedName' attribute" @@ -952,7 +963,7 @@ class BasicTests(samba.tests.TestCase): ldb.modify(m) self.fail() except LdbError, (num, _): - self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) m = Message() m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) @@ -976,7 +987,7 @@ class BasicTests(samba.tests.TestCase): ldb.modify(m) self.fail() except LdbError, (num, _): - self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) + self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) @@ -2649,7 +2660,7 @@ nTSecurityDescriptor:: """ + desc_base64) user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn) delete_force(self.ldb, user_dn) try: - sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI" + sddl = "O:DUG:DUD:AI(A;;RPWP;;;AU)S:PAI" desc = security.descriptor.from_sddl(sddl, security.dom_sid('S-1-5-21')) desc_base64 = base64.b64encode( ndr_pack(desc) ) self.ldb.add_ldif(""" @@ -2659,6 +2670,10 @@ sAMAccountName: """ + user_name + """ nTSecurityDescriptor:: """ + desc_base64) res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"]) self.assertTrue("nTSecurityDescriptor" in res[0]) + desc = res[0]["nTSecurityDescriptor"][0] + desc = ndr_unpack(security.descriptor, desc) + desc_sddl = desc.as_sddl(self.domain_sid) + self.assertTrue("O:S-1-5-21-513G:S-1-5-21-513D:AI(A;;RPWP;;;AU)" in desc_sddl) finally: delete_force(self.ldb, user_dn) diff --git a/source4/dsdb/tests/python/sam.py b/source4/dsdb/tests/python/sam.py index 754096a0157..b2d4d4920f5 100755 --- a/source4/dsdb/tests/python/sam.py +++ b/source4/dsdb/tests/python/sam.py @@ -586,7 +586,7 @@ class SamTests(samba.tests.TestCase): def test_sam_attributes(self): """Test the behaviour of special attributes of SAM objects""" - print "Testing the behaviour of special attributes of SAM objects\n""" + print "Testing the behaviour of special attributes of SAM objects\n" ldb.add({ "dn": "cn=ldaptestuser,cn=users," + self.base_dn, @@ -2604,7 +2604,7 @@ class SamTests(samba.tests.TestCase): def test_sam_description_attribute(self): """Test SAM description attribute""" - print "Test SAM description attribute""" + print "Test SAM description attribute" self.ldb.add({ "dn": "cn=ldaptestgroup,cn=users," + self.base_dn, @@ -2772,7 +2772,7 @@ class SamTests(samba.tests.TestCase): def test_fSMORoleOwner_attribute(self): """Test fSMORoleOwner attribute""" - print "Test fSMORoleOwner attribute""" + print "Test fSMORoleOwner attribute" ds_service_name = self.ldb.get_dsServiceName() @@ -2846,6 +2846,37 @@ class SamTests(samba.tests.TestCase): delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn) + def test_protected_sid_objects(self): + """Test deletion of objects with RID < 1000""" + self.ldb.create_ou("ou=ldaptestou," + self.base_dn) + # a list of some well-known sids + # objects in Builtin are aready covered by objectclass + protected_list = [ + ["CN=Domain Admins","CN=Users,"], + ["CN=Schema Admins","CN=Users,"], + ["CN=Enterprise Admins","CN=Users,"], + ["CN=Administrator","CN=Users,"], + ["CN=Domain Controllers","CN=Users,"], + ] + + + + for pr_object in protected_list: + try: + self.ldb.delete(pr_object[0] + "," + pr_object[1] + self.base_dn) + except LdbError, (num, _): + self.assertEquals(num, ERR_OTHER) + else: + self.fail("Deleted " + pr_object[0]) + + try: + self.ldb.rename(pr_object[0] + "," + pr_object[1] + self.base_dn, + pr_object[0] + "2," + pr_object[1] + self.base_dn) + except LdbError, (num, _): + self.fail("Could not rename " + pr_object[0]) + + self.ldb.rename(pr_object[0] + "2," + pr_object[1] + self.base_dn, + pr_object[0] + "," + pr_object[1] + self.base_dn) if not "://" in host: if os.path.isfile(host): |