*/
#include "idmap_autorid_tdb.h"
+#include "../libcli/security/dom_sid.h"
/**
* Build the database keystring for getting a range
}
}
-static NTSTATUS idmap_autorid_get_domainrange_action(struct db_context *db,
+static char *idmap_autorid_build_keystr_talloc(TALLOC_CTX *mem_ctx,
+ const char *domsid,
+ uint32_t domain_range_index)
+{
+ char *keystr;
+
+ if (domain_range_index > 0) {
+ keystr = talloc_asprintf(mem_ctx, "%s#%"PRIu32, domsid,
+ domain_range_index);
+ } else {
+ keystr = talloc_strdup(mem_ctx, domsid);
+ }
+
+ return keystr;
+}
+
+
+static bool idmap_autorid_validate_sid(const char *sid)
+{
+ struct dom_sid ignore;
+ if (sid == NULL) {
+ return false;
+ }
+
+ if (strcmp(sid, ALLOC_RANGE) == 0) {
+ return true;
+ }
+
+ return dom_sid_parse(sid, &ignore);
+}
+
+struct idmap_autorid_addrange_ctx {
+ struct autorid_range_config *range;
+ bool acquire;
+};
+
+static NTSTATUS idmap_autorid_addrange_action(struct db_context *db,
void *private_data)
{
+ struct idmap_autorid_addrange_ctx *ctx;
+ uint32_t requested_rangenum, stored_rangenum;
+ struct autorid_range_config *range;
+ bool acquire;
NTSTATUS ret;
- uint32_t rangenum, hwm;
+ uint32_t hwm;
char *numstr;
- struct autorid_range_config *range;
struct autorid_global_config *globalcfg;
fstring keystr;
+ uint32_t increment;
+ TALLOC_CTX *mem_ctx = NULL;
- range = (struct autorid_range_config *)private_data;
+ ctx = (struct idmap_autorid_addrange_ctx *)private_data;
+ range = ctx->range;
+ acquire = ctx->acquire;
+ requested_rangenum = range->rangenum;
+
+ if (db == NULL) {
+ DEBUG(3, ("Invalid database argument: NULL"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (range == NULL) {
+ DEBUG(3, ("Invalid range argument: NULL"));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ DEBUG(10, ("Adding new range for domain %s "
+ "(domain_range_index=%"PRIu32")\n",
+ range->domsid, range->domain_range_index));
+
+ if (!idmap_autorid_validate_sid(range->domsid)) {
+ DEBUG(3, ("Invalid SID: %s\n", range->domsid));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
keystr);
- ret = dbwrap_fetch_uint32_bystring(db, keystr,
- &(range->rangenum));
+ ret = dbwrap_fetch_uint32_bystring(db, keystr, &stored_rangenum);
if (NT_STATUS_IS_OK(ret)) {
/* entry is already present*/
- return ret;
- }
+ if (acquire) {
+ DEBUG(10, ("domain range already allocated - "
+ "Not adding!\n"));
+ return NT_STATUS_OK;
+ }
- DEBUG(10, ("Acquiring new range for domain %s "
- "(domain_range_index=%"PRIu32")\n",
- range->domsid, range->domain_range_index));
+ if (stored_rangenum != requested_rangenum) {
+ DEBUG(1, ("Error: requested rangenumber (%u) differs "
+ "from stored one (%u).\n",
+ requested_rangenum, stored_rangenum));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ DEBUG(10, ("Note: stored range agrees with requested "
+ "one - ok\n"));
+ return NT_STATUS_OK;
+ }
/* fetch the current HWM */
ret = dbwrap_fetch_uint32_bystring(db, HWM, &hwm);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1, ("Fatal error while fetching current "
"HWM value: %s\n", nt_errstr(ret)));
- ret = NT_STATUS_INTERNAL_ERROR;
- goto error;
+ return NT_STATUS_INTERNAL_ERROR;
}
- ret = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
+ mem_ctx = talloc_stackframe();
+
+ ret = idmap_autorid_loadconfig(db, mem_ctx, &globalcfg);
if (!NT_STATUS_IS_OK(ret)) {
- return ret;
+ DEBUG(1, ("Fatal error while fetching configuration: %s\n",
+ nt_errstr(ret)));
+ goto error;
+ }
+
+ if (acquire) {
+ /*
+ * automatically acquire the next range
+ */
+ requested_rangenum = hwm;
}
- /* do we have a range left? */
- if (hwm >= globalcfg->maxranges) {
- DEBUG(1, ("No more domain ranges available!\n"));
- talloc_free(globalcfg);
+ if (requested_rangenum >= globalcfg->maxranges) {
+ DEBUG(1, ("Not enough ranges available: New range %u must be "
+ "smaller than configured maximum number of ranges "
+ "(%u).\n",
+ requested_rangenum, globalcfg->maxranges));
ret = NT_STATUS_NO_MEMORY;
goto error;
}
- TALLOC_FREE(globalcfg);
- /* increase the HWM */
- ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &rangenum, 1);
- if (!NT_STATUS_IS_OK(ret)) {
- DEBUG(1, ("Fatal error while fetching a new "
- "domain range value!\n"));
- goto error;
+ if (requested_rangenum < hwm) {
+ /*
+ * Set a specified range below the HWM:
+ * We need to check that it is not yet taken.
+ */
+
+ numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
+ if (!numstr) {
+ ret = NT_STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ if (dbwrap_exists(db, string_term_tdb_data(numstr))) {
+ DEBUG(1, ("Requested range already in use.\n"));
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+
+ TALLOC_FREE(numstr);
+ } else {
+ /*
+ * requested or automatic range >= HWM:
+ * increment the HWM.
+ */
+
+ /* HWM always contains current max range + 1 */
+ increment = requested_rangenum + 1 - hwm;
+
+ /* increase the HWM */
+ ret = dbwrap_change_uint32_atomic_bystring(db, HWM, &hwm,
+ increment);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(1, ("Fatal error while incrementing the HWM "
+ "value in the database: %s\n",
+ nt_errstr(ret)));
+ goto error;
+ }
}
- /* store away the new mapping in both directions */
- ret = dbwrap_store_uint32_bystring(db, keystr, rangenum);
+ /*
+ * store away the new mapping in both directions
+ */
+
+ ret = dbwrap_store_uint32_bystring(db, keystr, requested_rangenum);
if (!NT_STATUS_IS_OK(ret)) {
DEBUG(1, ("Fatal error while storing new "
- "domain->range assignment!\n"));
+ "domain->range assignment: %s\n", nt_errstr(ret)));
goto error;
}
- numstr = talloc_asprintf(db, "%u", rangenum);
+ numstr = talloc_asprintf(mem_ctx, "%u", requested_rangenum);
if (!numstr) {
ret = NT_STATUS_NO_MEMORY;
goto error;
ret = dbwrap_store_bystring(db, numstr,
string_term_tdb_data(keystr), TDB_INSERT);
- talloc_free(numstr);
if (!NT_STATUS_IS_OK(ret)) {
- DEBUG(1, ("Fatal error while storing "
- "new domain->range assignment!\n"));
+ DEBUG(1, ("Fatal error while storing new "
+ "domain->range assignment: %s\n", nt_errstr(ret)));
goto error;
}
DEBUG(5, ("Acquired new range #%d for domain %s "
- "(domain_range_index=%"PRIu32")\n", rangenum, keystr,
+ "(domain_range_index=%"PRIu32")\n", requested_rangenum, keystr,
range->domain_range_index));
- range->rangenum = rangenum;
+ range->rangenum = requested_rangenum;
- return NT_STATUS_OK;
+ range->low_id = globalcfg->minvalue
+ + range->rangenum * globalcfg->rangesize;
+
+ ret = NT_STATUS_OK;
error:
+ talloc_free(mem_ctx);
return ret;
-
}
-NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
+static NTSTATUS idmap_autorid_addrange(struct db_context *db,
struct autorid_range_config *range,
- bool read_only)
+ bool acquire)
{
- NTSTATUS ret;
- struct autorid_global_config *globalcfg;
+ NTSTATUS status;
+ struct idmap_autorid_addrange_ctx ctx;
+
+ ctx.acquire = acquire;
+ ctx.range = range;
+
+ status = dbwrap_trans_do(db, idmap_autorid_addrange_action, &ctx);
+ return status;
+}
+
+NTSTATUS idmap_autorid_setrange(struct db_context *db,
+ const char *domsid,
+ uint32_t domain_range_index,
+ uint32_t rangenum)
+{
+ NTSTATUS status;
+ struct autorid_range_config range;
+
+ ZERO_STRUCT(range);
+ fstrcpy(range.domsid, domsid);
+ range.domain_range_index = domain_range_index;
+ range.rangenum = rangenum;
+
+ status = idmap_autorid_addrange(db, &range, false);
+ return status;
+}
+
+static NTSTATUS idmap_autorid_acquire_range(struct db_context *db,
+ struct autorid_range_config *range)
+{
+ return idmap_autorid_addrange(db, range, true);
+}
+
+static NTSTATUS idmap_autorid_getrange_int(struct db_context *db,
+ struct autorid_range_config *range)
+{
+ NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
+ struct autorid_global_config *globalcfg = NULL;
fstring keystr;
- /*
- * try to find mapping without locking the database,
- * if it is not found create a mapping in a transaction unless
- * read-only mode has been set
- */
+ if (db == NULL || range == NULL) {
+ DEBUG(3, ("Invalid arguments received\n"));
+ goto done;
+ }
+
idmap_autorid_build_keystr(range->domsid, range->domain_range_index,
keystr);
- ret = dbwrap_fetch_uint32_bystring(db, keystr,
- &(range->rangenum));
+ 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",
+ keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ status = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to read global configuration"));
+ goto done;
+ }
+ range->low_id = globalcfg->minvalue
+ + range->rangenum * globalcfg->rangesize;
+
+ TALLOC_FREE(globalcfg);
+done:
+ return status;
+}
+
+NTSTATUS idmap_autorid_getrange(struct db_context *db,
+ const char *domsid,
+ uint32_t domain_range_index,
+ uint32_t *rangenum,
+ uint32_t *low_id)
+{
+ NTSTATUS status;
+ struct autorid_range_config range;
+
+ if (rangenum == NULL) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCT(range);
+ fstrcpy(range.domsid, domsid);
+ range.domain_range_index = domain_range_index;
+ status = idmap_autorid_getrange_int(db, &range);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *rangenum = range.rangenum;
+
+ if (low_id != NULL) {
+ *low_id = range.low_id;
+ }
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS idmap_autorid_get_domainrange(struct db_context *db,
+ struct autorid_range_config *range,
+ bool read_only)
+{
+ NTSTATUS ret;
+
+ ret = idmap_autorid_getrange_int(db, range);
if (!NT_STATUS_IS_OK(ret)) {
if (read_only) {
return NT_STATUS_NOT_FOUND;
}
- ret = dbwrap_trans_do(db,
- idmap_autorid_get_domainrange_action, range);
- }
- ret = idmap_autorid_loadconfig(db, talloc_tos(), &globalcfg);
- if (!NT_STATUS_IS_OK(ret)) {
- return ret;
+ ret = idmap_autorid_acquire_range(db, range);
}
- range->low_id = globalcfg->minvalue
- + range->rangenum * globalcfg->rangesize;
DEBUG(10, ("Using range #%d for domain %s "
"(domain_range_index=%"PRIu32", low_id=%"PRIu32")\n",
range->rangenum, range->domsid, range->domain_range_index,
range->low_id));
- TALLOC_FREE(globalcfg);
return ret;
}
return NT_STATUS_OK;
}
+/*
+ * Delete a domain#index <-> range mapping from the database.
+ * The mapping is specified by the sid and index.
+ * If force == true, invalid mapping records are deleted as far
+ * as possible, otherwise they are left untouched.
+ */
+
+struct idmap_autorid_delete_range_by_sid_ctx {
+ const char *domsid;
+ uint32_t domain_range_index;
+ bool force;
+};
+
+static NTSTATUS idmap_autorid_delete_range_by_sid_action(struct db_context *db,
+ void *private_data)
+{
+ struct idmap_autorid_delete_range_by_sid_ctx *ctx =
+ (struct idmap_autorid_delete_range_by_sid_ctx *)private_data;
+ const char *domsid;
+ uint32_t domain_range_index;
+ uint32_t rangenum;
+ char *keystr;
+ char *range_keystr;
+ TDB_DATA data;
+ NTSTATUS status;
+ TALLOC_CTX *frame = talloc_stackframe();
+ bool is_valid_range_mapping = true;
+ bool force;
+
+ domsid = ctx->domsid;
+ domain_range_index = ctx->domain_range_index;
+ force = ctx->force;
+
+ keystr = idmap_autorid_build_keystr_talloc(frame, domsid,
+ domain_range_index);
+ if (keystr == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = dbwrap_fetch_uint32_bystring(db, keystr, &rangenum);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ range_keystr = talloc_asprintf(frame, "%"PRIu32, rangenum);
+ if (range_keystr == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = dbwrap_fetch_bystring(db, frame, range_keystr, &data);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ DEBUG(1, ("Incomplete mapping %s -> %s: no backward mapping\n",
+ keystr, range_keystr));
+ is_valid_range_mapping = false;
+ } else if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Error fetching reverse mapping for %s -> %s: %s\n",
+ keystr, range_keystr, nt_errstr(status)));
+ goto done;
+ } else if (strncmp((const char *)data.dptr, keystr, strlen(keystr))
+ != 0)
+ {
+ DEBUG(1, ("Invalid mapping: %s -> %s -> %s\n",
+ keystr, range_keystr, (const char *)data.dptr));
+ is_valid_range_mapping = false;
+ }
+
+ if (!is_valid_range_mapping && !force) {
+ DEBUG(10, ("Not deleting invalid mapping, since not in force "
+ "mode.\n"));
+ status = NT_STATUS_FILE_INVALID;
+ goto done;
+ }
+
+ status = dbwrap_delete_bystring(db, keystr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Deletion of '%s' failed: %s\n",
+ keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ if (!is_valid_range_mapping) {
+ goto done;
+ }
+
+ status = dbwrap_delete_bystring(db, range_keystr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Deletion of '%s' failed: %s\n",
+ range_keystr, nt_errstr(status)));
+ goto done;
+ }
+
+ DEBUG(10, ("Deleted range mapping %s <--> %s\n", keystr,
+ range_keystr));
+
+done:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+NTSTATUS idmap_autorid_delete_range_by_sid(struct db_context *db,
+ const char *domsid,
+ uint32_t domain_range_index,
+ bool force)
+{
+ NTSTATUS status;
+ struct idmap_autorid_delete_range_by_sid_ctx ctx;
+
+ ctx.domain_range_index = domain_range_index;
+ ctx.domsid = domsid;
+ ctx.force = force;
+
+ status = dbwrap_trans_do(db, idmap_autorid_delete_range_by_sid_action,
+ &ctx);
+ return status;
+}
+
+
/*
* open and initialize the database which stores the ranges for the domains
*/
TALLOC_FREE(frame);
return status;
}
+
+NTSTATUS idmap_autorid_saveconfigstr(struct db_context *db,
+ const char *configstr)
+{
+ bool ok;
+ NTSTATUS status;
+ struct autorid_global_config cfg;
+
+ ok = idmap_autorid_parse_configstr(configstr, &cfg);
+ if (!ok) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ status = idmap_autorid_saveconfig(db, &cfg);
+ return status;
+}