summaryrefslogtreecommitdiff
path: root/source4/dsdb
diff options
context:
space:
mode:
authorKarolin Seeger <kseeger@samba.org>2014-07-28 09:13:45 +0200
committerKarolin Seeger <kseeger@samba.org>2014-07-28 09:18:00 +0200
commitfcc634b483255bedf53f3aea40334c018e13dcce (patch)
tree7d59833bd515e295e70ec188e1aa2b1436b3355c /source4/dsdb
parent97d7291d12e803076022d71556c792b0cd4e60e8 (diff)
parent80a1dfddf9086700a8de5fd6005a9179b0bb3d9e (diff)
downloadsamba-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')
-rw-r--r--source4/dsdb/common/tests/dsdb_dn.c14
-rw-r--r--source4/dsdb/common/util.c59
-rw-r--r--source4/dsdb/kcc/kcc_deleted.c2
-rw-r--r--source4/dsdb/repl/drepl_out_helpers.c52
-rw-r--r--source4/dsdb/repl/replicated_objects.c14
-rw-r--r--source4/dsdb/samdb/cracknames.c38
-rw-r--r--source4/dsdb/samdb/ldb_modules/descriptor.c2
-rw-r--r--source4/dsdb/samdb/ldb_modules/dirsync.c7
-rw-r--r--source4/dsdb/samdb/ldb_modules/extended_dn_in.c37
-rw-r--r--source4/dsdb/samdb/ldb_modules/instancetype.c3
-rw-r--r--source4/dsdb/samdb/ldb_modules/objectclass.c54
-rw-r--r--source4/dsdb/samdb/ldb_modules/operational.c2
-rw-r--r--source4/dsdb/samdb/ldb_modules/partition_metadata.c34
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c1
-rw-r--r--source4/dsdb/samdb/ldb_modules/repl_meta_data.c267
-rw-r--r--source4/dsdb/samdb/ldb_modules/rootdse.c110
-rw-r--r--source4/dsdb/samdb/ldb_modules/samldb.c29
-rw-r--r--source4/dsdb/samdb/ldb_modules/schema_data.c16
-rw-r--r--source4/dsdb/samdb/ldb_modules/schema_load.c207
-rw-r--r--source4/dsdb/samdb/ldb_modules/secrets_tdb_sync.c6
-rw-r--r--source4/dsdb/samdb/ldb_modules/simple_ldap_map.c2
-rw-r--r--source4/dsdb/samdb/ldb_modules/update_keytab.c11
-rw-r--r--source4/dsdb/samdb/ldb_modules/util.c13
-rw-r--r--source4/dsdb/samdb/samdb.c7
-rw-r--r--source4/dsdb/samdb/samdb.h1
-rw-r--r--source4/dsdb/schema/schema.h10
-rw-r--r--source4/dsdb/schema/schema_init.c10
-rw-r--r--source4/dsdb/schema/schema_set.c98
-rw-r--r--source4/dsdb/schema/schema_syntax.c11
-rwxr-xr-xsource4/dsdb/tests/python/acl.py26
-rwxr-xr-xsource4/dsdb/tests/python/ldap.py27
-rwxr-xr-xsource4/dsdb/tests/python/sam.py37
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, &current_usn, NULL, NULL);
+ ret = dsdb_module_load_partition_usn(ac->module, schema_dn,
+ &current_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, &current_usn, NULL, NULL);
- if (ret != LDB_SUCCESS || current_usn == schema->loaded_usn) {
+ ret = dsdb_module_load_partition_usn(module, schema_dn, &current_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, &current_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):