diff options
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules/schema_load.c')
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema_load.c | 207 |
1 files changed, 125 insertions, 82 deletions
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; } |