goto error;
}
- if (requested_rangenum < hwm) {
- /*
- * Set a specified range below the HWM:
- * We need to check that it is not yet taken.
- */
+ /*
+ * Check that it is not yet taken.
+ * If the range is requested and < HWM, we need
+ * to check anyways, and otherwise, we also better
+ * check in order to prevent further corruption
+ * in case the db has been externally modified.
+ */
- numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
- if (!numstr) {
- ret = NT_STATUS_NO_MEMORY;
- goto error;
- }
+ numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
+ if (!numstr) {
+ DEBUG(1, ("Talloc failed!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
- if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
- DEBUG(1, ("Requested range already in use.\n"));
+ if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
+ DEBUG(1, ("Requested range '%s' is already in use.\n", numstr));
+
+ if (requested_rangenum < hwm) {
ret = NT_STATUS_INVALID_PARAMETER;
- goto error;
+ } else {
+ ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
}
- TALLOC_FREE(numstr);
- } else {
+ goto error;
+ }
+
+ if (requested_rangenum >= hwm) {
/*
* requested or automatic range >= HWM:
* increment the HWM.
"domain->range assignment: %s\n", nt_errstr(ret)));
goto error;
}
- DEBUG(5, ("Acquired new range #%d for domain %s "
- "(domain_range_index=%"PRIu32")\n", requested_rangenum, keystr,
+
+ DEBUG(5, ("%s new range #%d for domain %s "
+ "(domain_range_index=%"PRIu32")\n",
+ (acquire?"Acquired":"Stored"),
+ requested_rangenum, keystr,
range->domain_range_index));
range->rangenum = requested_rangenum;
goto done;
}
+ if (!idmap_autorid_validate_sid(range->domsid)) {
+ DEBUG(3, ("Invalid SID: '%s'\n", range->domsid));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
keystr);
DEBUG(10, ("reading domain range for key %s\n", keystr));
status = dbwrap_fetch_uint32_bystring(db, keystr, &(range->rangenum));
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to read database for key '%s': %s\n",
+ DEBUG(1, ("Failed to read database record for key '%s': %s\n",
keystr, nt_errstr(status)));
goto done;
}
ret = idmap_autorid_getrange_int(db, range);
if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(10, ("Failed to read range config for '%s': %s\n",
+ range->domsid, nt_errstr(ret)));
if (read_only) {
+ DEBUG(10, ("Not allocating new range for '%s' because "
+ "read-only is enabled.\n", range->domsid));
return NT_STATUS_NOT_FOUND;
}
}
/* initialize the given HWM to 0 if it does not exist yet */
+static NTSTATUS idmap_autorid_init_hwm_action(struct db_context *db,
+ void *private_data)
+{
+ NTSTATUS status;
+ uint32_t hwmval;
+ const char *hwm;
+
+ hwm = (char *)private_data;
+
+ status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
+ if (NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("HWM (%s) already initialized in autorid database "
+ "(value %"PRIu32").\n", hwm, hwmval));
+ return NT_STATUS_OK;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ DEBUG(0, ("Error fetching HWM (%s) from autorid "
+ "database: %s\n", hwm, nt_errstr(status)));
+ return status;
+ }
+
+ status = dbwrap_trans_store_uint32_bystring(db, hwm, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error storing HWM (%s) in autorid database: %s\n",
+ hwm, nt_errstr(status)));
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
NTSTATUS idmap_autorid_init_hwm(struct db_context *db, const char *hwm)
{
NTSTATUS status;
uint32_t hwmval;
status = dbwrap_fetch_uint32_bystring(db, hwm, &hwmval);
- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
- status = dbwrap_trans_store_int32_bystring(db, hwm, 0);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,
- ("Unable to initialise HWM (%s) in autorid "
- "database: %s\n", hwm, nt_errstr(status)));
- return NT_STATUS_INTERNAL_DB_ERROR;
- }
- } else if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("HWM (%s) already initialized in autorid database "
+ "(value %"PRIu32").\n", hwm, hwmval));
+ return NT_STATUS_OK;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
DEBUG(0, ("unable to fetch HWM (%s) from autorid "
"database: %s\n", hwm, nt_errstr(status)));
return status;
}
+ status = dbwrap_trans_do(db, idmap_autorid_init_hwm_action,
+ (void *)hwm);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Error initializing HWM (%s) in autorid database: "
+ "%s\n", hwm, nt_errstr(status)));
+ return NT_STATUS_INTERNAL_DB_ERROR;
+ }
+
+ DEBUG(1, ("Initialized HWM (%s) in autorid database.\n", hwm));
+
return NT_STATUS_OK;
}
return status;
}
-/*
- * open and initialize the database which stores the ranges for the domains
+/**
+ * Open and possibly create the database.
*/
-NTSTATUS idmap_autorid_db_init(const char *path,
+NTSTATUS idmap_autorid_db_open(const char *path,
TALLOC_CTX *mem_ctx,
struct db_context **db)
{
/* Open idmap repository */
*db = db_open(mem_ctx, path, 0, TDB_DEFAULT, O_RDWR | O_CREAT, 0644,
- DBWRAP_LOCK_ORDER_1);
+ DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
if (*db == NULL) {
DEBUG(0, ("Unable to open idmap_autorid database '%s'\n", path));
return NT_STATUS_UNSUCCESSFUL;
}
- /* Initialize high water mark for the currently used range to 0 */
+ return status;
+}
+
+/**
+ * Initialize the high watermark records in the database.
+ */
+NTSTATUS idmap_autorid_init_hwms(struct db_context *db)
+{
+ NTSTATUS status;
- status = idmap_autorid_init_hwm(*db, HWM);
- NT_STATUS_NOT_OK_RETURN(status);
+ status = idmap_autorid_init_hwm(db, HWM);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- status = idmap_autorid_init_hwm(*db, ALLOC_HWM_UID);
- NT_STATUS_NOT_OK_RETURN(status);
+ status = idmap_autorid_init_hwm(db, ALLOC_HWM_UID);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- status = idmap_autorid_init_hwm(*db, ALLOC_HWM_GID);
+ status = idmap_autorid_init_hwm(db, ALLOC_HWM_GID);
return status;
}
+NTSTATUS idmap_autorid_db_init(const char *path,
+ TALLOC_CTX *mem_ctx,
+ struct db_context **db)
+{
+ NTSTATUS status;
+
+ status = idmap_autorid_db_open(path, mem_ctx, db);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = idmap_autorid_init_hwms(*db);
+ return status;
+}
+
+
+
struct idmap_autorid_fetch_config_state {
TALLOC_CTX *mem_ctx;
char *configstr;
"minvalue:%lu rangesize:%lu maxranges:%lu",
&minvalue, &rangesize, &maxranges) != 3) {
DEBUG(1,
- ("Found invalid configuration data"
- "creating new config\n"));
+ ("Found invalid configuration data. "
+ "Creating new config\n"));
return false;
}
DEBUG(5, ("No configuration found. Storing initial "
"configuration.\n"));
} else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Error loading configuration: %s\n",
+ nt_errstr(status)));
goto done;
}
status = idmap_autorid_saveconfig(db, &cfg);
return status;
}
+
+
+/*
+ * iteration: Work on all range mappings for a given domain
+ */
+
+struct domain_range_visitor_ctx {
+ const char *domsid;
+ NTSTATUS (*fn)(struct db_context *db,
+ const char *domsid,
+ uint32_t index,
+ uint32_t rangenum,
+ void *private_data);
+ void *private_data;
+ int count; /* number of records worked on */
+};
+
+static int idmap_autorid_visit_domain_range(struct db_record *rec,
+ void *private_data)
+{
+ struct domain_range_visitor_ctx *vi;
+ char *domsid;
+ char *sep;
+ uint32_t range_index = 0;
+ uint32_t rangenum = 0;
+ TDB_DATA key, value;
+ NTSTATUS status;
+ int ret = 0;
+ struct db_context *db;
+
+ vi = talloc_get_type_abort(private_data,
+ struct domain_range_visitor_ctx);
+
+ key = dbwrap_record_get_key(rec);
+
+ /*
+ * split string "<sid>[#<index>]" into sid string and index number
+ */
+
+ domsid = (char *)key.dptr;
+
+ DEBUG(10, ("idmap_autorid_visit_domain_range: visiting key '%s'\n",
+ domsid));
+
+ sep = strrchr(domsid, '#');
+ if (sep != NULL) {
+ char *index_str;
+ *sep = '\0';
+ index_str = sep+1;
+ if (sscanf(index_str, "%"SCNu32, &range_index) != 1) {
+ DEBUG(10, ("Found separator '#' but '%s' is not a "
+ "valid range index. Skipping record\n",
+ index_str));
+ goto done;
+ }
+ }
+
+ if (!idmap_autorid_validate_sid(domsid)) {
+ DEBUG(10, ("String '%s' is not a valid sid. "
+ "Skipping record.\n", domsid));
+ goto done;
+ }
+
+ if ((vi->domsid != NULL) && (strcmp(domsid, vi->domsid) != 0)) {
+ DEBUG(10, ("key sid '%s' does not match requested sid '%s'.\n",
+ domsid, vi->domsid));
+ goto done;
+ }
+
+ value = dbwrap_record_get_value(rec);
+
+ if (value.dsize != sizeof(uint32_t)) {
+ /* it might be a mapping of a well known sid */
+ DEBUG(10, ("value size %u != sizeof(uint32_t) for sid '%s', "
+ "skipping.\n", (unsigned)value.dsize, vi->domsid));
+ goto done;
+ }
+
+ rangenum = IVAL(value.dptr, 0);
+
+ db = dbwrap_record_get_db(rec);
+
+ status = vi->fn(db, domsid, range_index, rangenum, vi->private_data);
+ if (!NT_STATUS_IS_OK(status)) {
+ ret = -1;
+ goto done;
+ }
+
+ vi->count++;
+ ret = 0;
+
+done:
+ return ret;
+}
+
+static NTSTATUS idmap_autorid_iterate_domain_ranges_int(struct db_context *db,
+ const char *domsid,
+ NTSTATUS (*fn)(struct db_context *db,
+ const char *domsid,
+ uint32_t index,
+ uint32_t rangnum,
+ void *private_data),
+ void *private_data,
+ int *count,
+ NTSTATUS (*traverse)(struct db_context *db,
+ int (*f)(struct db_record *, void *),
+ void *private_data,
+ int *count))
+{
+ NTSTATUS status;
+ struct domain_range_visitor_ctx *vi;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ if (domsid == NULL) {
+ DEBUG(10, ("No sid provided, operating on all ranges\n"));
+ }
+
+ if (fn == NULL) {
+ DEBUG(1, ("Error: missing visitor callback\n"));
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ vi = talloc_zero(frame, struct domain_range_visitor_ctx);
+ if (vi == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ vi->domsid = domsid;
+ vi->fn = fn;
+ vi->private_data = private_data;
+
+ status = traverse(db, idmap_autorid_visit_domain_range, vi, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ if (count != NULL) {
+ *count = vi->count;
+ }
+
+done:
+ talloc_free(frame);
+ return status;
+}
+
+NTSTATUS idmap_autorid_iterate_domain_ranges(struct db_context *db,
+ const char *domsid,
+ NTSTATUS (*fn)(struct db_context *db,
+ const char *domsid,
+ uint32_t index,
+ uint32_t rangenum,
+ void *private_data),
+ void *private_data,
+ int *count)
+{
+ NTSTATUS status;
+
+ status = idmap_autorid_iterate_domain_ranges_int(db,
+ domsid,
+ fn,
+ private_data,
+ count,
+ dbwrap_traverse);
+
+ return status;
+}
+
+
+NTSTATUS idmap_autorid_iterate_domain_ranges_read(struct db_context *db,
+ const char *domsid,
+ NTSTATUS (*fn)(struct db_context *db,
+ const char *domsid,
+ uint32_t index,
+ uint32_t rangenum,
+ void *count),
+ void *private_data,
+ int *count)
+{
+ NTSTATUS status;
+
+ status = idmap_autorid_iterate_domain_ranges_int(db,
+ domsid,
+ fn,
+ private_data,
+ count,
+ dbwrap_traverse_read);
+
+ return status;
+}
+
+
+/*
+ * Delete all ranges configured for a given domain
+ */
+
+struct delete_domain_ranges_visitor_ctx {
+ bool force;
+};
+
+static NTSTATUS idmap_autorid_delete_domain_ranges_visitor(
+ struct db_context *db,
+ const char *domsid,
+ uint32_t domain_range_index,
+ uint32_t rangenum,
+ void *private_data)
+{
+ struct delete_domain_ranges_visitor_ctx *ctx;
+ NTSTATUS status;
+
+ ctx = (struct delete_domain_ranges_visitor_ctx *)private_data;
+
+ status = idmap_autorid_delete_range_by_sid(
+ db, domsid, domain_range_index, ctx->force);
+ return status;
+}
+
+struct idmap_autorid_delete_domain_ranges_ctx {
+ const char *domsid;
+ bool force;
+ int count; /* output: count records operated on */
+};
+
+static NTSTATUS idmap_autorid_delete_domain_ranges_action(struct db_context *db,
+ void *private_data)
+{
+ struct idmap_autorid_delete_domain_ranges_ctx *ctx;
+ struct delete_domain_ranges_visitor_ctx visitor_ctx;
+ int count;
+ NTSTATUS status;
+
+ ctx = (struct idmap_autorid_delete_domain_ranges_ctx *)private_data;
+
+ ZERO_STRUCT(visitor_ctx);
+ visitor_ctx.force = ctx->force;
+
+ status = idmap_autorid_iterate_domain_ranges(db,
+ ctx->domsid,
+ idmap_autorid_delete_domain_ranges_visitor,
+ &visitor_ctx,
+ &count);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ ctx->count = count;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS idmap_autorid_delete_domain_ranges(struct db_context *db,
+ const char *domsid,
+ bool force,
+ int *count)
+{
+ NTSTATUS status;
+ struct idmap_autorid_delete_domain_ranges_ctx ctx;
+
+ ZERO_STRUCT(ctx);
+ ctx.domsid = domsid;
+ ctx.force = force;
+
+ status = dbwrap_trans_do(db, idmap_autorid_delete_domain_ranges_action,
+ &ctx);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *count = ctx.count;
+
+ return NT_STATUS_OK;
+}