summaryrefslogtreecommitdiff
path: root/source3/winbindd/idmap_tdb2.c
diff options
context:
space:
mode:
authorMichael Adam <obnox@samba.org>2010-07-29 23:13:54 +0200
committerMichael Adam <obnox@samba.org>2010-08-14 02:10:42 +0200
commit8da3d7c39be33899b29276cb2778cb9e1771bb6e (patch)
tree8e6289ef8fe4a6972118d3f5b82ab7d6f342f7c7 /source3/winbindd/idmap_tdb2.c
parent36017ecebf87b2c04d5af37bc209a64a4c6527a7 (diff)
downloadsamba-8da3d7c39be33899b29276cb2778cb9e1771bb6e.tar.gz
samba-8da3d7c39be33899b29276cb2778cb9e1771bb6e.tar.bz2
samba-8da3d7c39be33899b29276cb2778cb9e1771bb6e.zip
s3:idmap_tdb2: add allocation of new mappings to idmap_tdb2_sids_to_unixids
This moves the new_mapping feature inside the tdb2 backend to make creations of mappings atomic. Note: The new internal function idmap_tdb2_get_new_id() that is used to allocate a new unix id is prepared to function for multiple explicitly configured idmap domains, but currently it does only work for the default domain. The extended allocation support requires extension of the data base format to store multiple counters (per domain). This will be added in a later step (TODO!).
Diffstat (limited to 'source3/winbindd/idmap_tdb2.c')
-rw-r--r--source3/winbindd/idmap_tdb2.c195
1 files changed, 173 insertions, 22 deletions
diff --git a/source3/winbindd/idmap_tdb2.c b/source3/winbindd/idmap_tdb2.c
index 0adf0f236c..1db880a48b 100644
--- a/source3/winbindd/idmap_tdb2.c
+++ b/source3/winbindd/idmap_tdb2.c
@@ -48,6 +48,8 @@ static struct idmap_tdb2_state {
} idmap_tdb2_state;
+static NTSTATUS idmap_tdb2_new_mapping(struct idmap_domain *dom,
+ struct id_map *map);
/* handle to the permanent tdb */
static struct db_context *idmap_tdb2;
@@ -285,6 +287,30 @@ static NTSTATUS idmap_tdb2_allocate_id(struct unixid *xid)
return status;
}
+/**
+ * Allocate a new unix-ID.
+ * For now this is for the default idmap domain only.
+ * Should be extended later on.
+ */
+static NTSTATUS idmap_tdb2_get_new_id(struct idmap_domain *dom,
+ struct unixid *id)
+{
+ NTSTATUS ret;
+
+ if (!strequal(dom->name, "*")) {
+ DEBUG(3, ("idmap_tdb2_get_new_id: "
+ "Refusing creation of mapping for domain'%s'. "
+ "Currently only supported for the default "
+ "domain \"*\".\n",
+ dom->name));
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ ret = idmap_tdb2_allocate_id(id);
+
+ return ret;
+}
+
/*
IDMAP MAPPING TDB BACKEND
*/
@@ -744,42 +770,97 @@ done:
/*
lookup a set of sids.
*/
-static NTSTATUS idmap_tdb2_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+
+struct idmap_tdb2_sids_to_unixids_context {
+ struct idmap_domain *dom;
+ struct id_map **ids;
+ bool allocate_unmapped;
+};
+
+static NTSTATUS idmap_tdb2_sids_to_unixids_action(struct db_context *db,
+ void *private_data)
{
- struct idmap_tdb2_context *ctx;
- NTSTATUS ret;
+ struct idmap_tdb2_sids_to_unixids_context *state;
int i;
+ struct idmap_tdb2_context *ctx;
+ NTSTATUS ret = NT_STATUS_OK;
- /* initialize the status to avoid suprise */
- for (i = 0; ids[i]; i++) {
- ids[i]->status = ID_UNKNOWN;
- }
+ state = (struct idmap_tdb2_sids_to_unixids_context *)private_data;
- ctx = talloc_get_type(dom->private_data, struct idmap_tdb2_context);
+ DEBUG(10, ("idmap_tdb2_sids_to_unixids_action: "
+ " domain: [%s], allocate: %s\n",
+ state->dom->name,
+ state->allocate_unmapped ? "yes" : "no"));
- for (i = 0; ids[i]; i++) {
- ret = idmap_tdb2_sid_to_id(ctx, ids[i]);
- if ( ! NT_STATUS_IS_OK(ret)) {
+ ctx = talloc_get_type(state->dom->private_data,
+ struct idmap_tdb2_context);
- /* if it is just a failed mapping continue */
- if (NT_STATUS_EQUAL(ret, NT_STATUS_NONE_MAPPED)) {
- /* make sure it is marked as unmapped */
- ids[i]->status = ID_UNMAPPED;
- continue;
+ for (i = 0; state->ids[i]; i++) {
+ if ((state->ids[i]->status == ID_UNKNOWN) ||
+ /* retry if we could not map in previous run: */
+ (state->ids[i]->status == ID_UNMAPPED))
+ {
+ NTSTATUS ret2;
+
+ ret2 = idmap_tdb2_sid_to_id(ctx, state->ids[i]);
+ if (!NT_STATUS_IS_OK(ret2)) {
+
+ /* if it is just a failed mapping, continue */
+ if (NT_STATUS_EQUAL(ret2, NT_STATUS_NONE_MAPPED)) {
+
+ /* make sure it is marked as unmapped */
+ state->ids[i]->status = ID_UNMAPPED;
+ ret = STATUS_SOME_UNMAPPED;
+ } else {
+ /* some fatal error occurred, return immediately */
+ ret = ret2;
+ goto done;
+ }
+ } else {
+ /* all ok, id is mapped */
+ state->ids[i]->status = ID_MAPPED;
}
+ }
- /* some fatal error occurred, return immediately */
- goto done;
+ if ((state->ids[i]->status == ID_UNMAPPED) &&
+ state->allocate_unmapped)
+ {
+ ret = idmap_tdb2_new_mapping(state->dom, state->ids[i]);
+ if (!NT_STATUS_IS_OK(ret)) {
+ goto done;
+ }
}
+ }
- /* all ok, id is mapped */
- ids[i]->status = ID_MAPPED;
+done:
+ return ret;
+}
+
+static NTSTATUS idmap_tdb2_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
+{
+ NTSTATUS ret;
+ int i;
+ struct idmap_tdb2_sids_to_unixids_context state;
+
+ /* initialize the status to avoid suprise */
+ for (i = 0; ids[i]; i++) {
+ ids[i]->status = ID_UNKNOWN;
}
- ret = NT_STATUS_OK;
+ state.dom = dom;
+ state.ids = ids;
+ state.allocate_unmapped = false;
+
+ ret = idmap_tdb2_sids_to_unixids_action(idmap_tdb2, &state);
+
+ if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) {
+ state.allocate_unmapped = true;
+ ret = dbwrap_trans_do(idmap_tdb2,
+ idmap_tdb2_sids_to_unixids_action,
+ &state);
+ }
-done:
return ret;
}
@@ -845,6 +926,76 @@ done:
return ret;
}
+/**
+ * Create a new mapping for an unmapped SID, also allocating a new ID.
+ * This should be run inside a transaction.
+ *
+ * TODO:
+* Properly integrate this with multi domain idmap config:
+ * Currently, the allocator is default-config only.
+ */
+static NTSTATUS idmap_tdb2_new_mapping(struct idmap_domain *dom, struct id_map *map)
+{
+ NTSTATUS ret;
+ char *sidstr;
+ TDB_DATA data;
+ TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+ if (map == NULL) {
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if ((map->xid.type != ID_TYPE_UID) && (map->xid.type != ID_TYPE_GID)) {
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (map->sid == NULL) {
+ ret = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* check wheter the SID is already mapped in the db */
+ sidstr = sid_string_talloc(mem_ctx, map->sid);
+ if (sidstr == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ ret = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ data = dbwrap_fetch_bystring(idmap_tdb2, mem_ctx, sidstr);
+ if (data.dptr) {
+ ret = NT_STATUS_OBJECT_NAME_COLLISION;
+ goto done;
+ }
+
+ /* unmapped - get a new id */
+ ret = idmap_tdb2_get_new_id(dom, &map->xid);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(3, ("Could not allocate id: %s\n", nt_errstr(ret)));
+ goto done;
+ }
+
+ DEBUG(10, ("Setting mapping: %s <-> %s %lu\n",
+ sid_string_dbg(map->sid),
+ (map->xid.type == ID_TYPE_UID) ? "UID" : "GID",
+ (unsigned long)map->xid.id));
+
+ map->status = ID_MAPPED;
+
+ /* store the mapping */
+ ret = idmap_tdb2_set_mapping(dom, map);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(3, ("Could not store the new mapping: %s\n",
+ nt_errstr(ret)));
+ }
+
+done:
+ talloc_free(mem_ctx);
+ return ret;
+}
+
/*
Close the idmap tdb instance
*/