diff options
-rw-r--r-- | source3/winbindd/idmap_tdb2.c | 195 |
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 */ |