From 493f5d6b078e0b0f80d1ef25043e2834cb4fcb87 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 15 Sep 2020 17:26:11 +0200 Subject: [PATCH] winbindd: allow idmap backends to mark entries with ID_[TYPE_WB_]REQUIRE_TYPE This must only be used between winbindd parent and child! It must not leak into outside world. Some backends require ID_TYPE_UID or ID_TYPE_GID as type_hint, while others may only need ID_TYPE_BOTH in order to validate that the domain exists. This will allow us to skip the wb_lookupsids_send/recv in the winbindd parent in future and only do that on demand. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14539 Signed-off-by: Stefan Metzmacher Reviewed-by: Gary Lockyer --- librpc/idl/idmap.idl | 23 +++++++++++++++++++++-- source3/passdb/lookup_sid.c | 7 +++++++ source3/winbindd/idmap_autorid.c | 6 +++--- source3/winbindd/idmap_ldap.c | 29 +++++++++++++++++++++++++++++ source3/winbindd/idmap_rw.c | 32 ++++++++++++++++++++++++++++++-- source3/winbindd/idmap_tdb_common.c | 22 +++++++++++++++++++++- source3/winbindd/wb_sids2xids.c | 11 +++++++++++ source3/winbindd/winbindd_dual_srv.c | 6 ++++++ source3/winbindd/winbindd_getgroups.c | 7 +++++++ 9 files changed, 135 insertions(+), 8 deletions(-) diff --git a/librpc/idl/idmap.idl b/librpc/idl/idmap.idl index 54fd888dcab..e58e39210c7 100644 --- a/librpc/idl/idmap.idl +++ b/librpc/idl/idmap.idl @@ -11,7 +11,18 @@ interface idmap ID_TYPE_NOT_SPECIFIED, ID_TYPE_UID, ID_TYPE_GID, - ID_TYPE_BOTH + ID_TYPE_BOTH, + /* + * This are internal between winbindd + * parent and child. + * + * It means the idmap backend/child requires a valid type_hint + * for wbint_Sids2UnixIDs(): + * + * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists + * - ID_TYPE_BOTH means that only the domain exist + */ + ID_TYPE_WB_REQUIRE_TYPE } id_type; typedef [public] struct { @@ -23,7 +34,15 @@ interface idmap ID_UNKNOWN, ID_MAPPED, ID_UNMAPPED, - ID_EXPIRED + ID_EXPIRED, + /* + * This means the idmap backend requires a valid type_hint + * in order to map a sid to a unix id. + * + * - ID_TYPE_UID or ID_TYPE_GID means the user/group exists + * - ID_TYPE_BOTH means that only the domain exist + */ + ID_REQUIRE_TYPE } id_mapping; typedef [public] struct { diff --git a/source3/passdb/lookup_sid.c b/source3/passdb/lookup_sid.c index cd9d5f1ad6a..ff8a16619a8 100644 --- a/source3/passdb/lookup_sid.c +++ b/source3/passdb/lookup_sid.c @@ -1348,6 +1348,13 @@ done: break; case ID_TYPE_NOT_SPECIFIED: break; + case ID_TYPE_WB_REQUIRE_TYPE: + /* + * these are internal between winbindd + * parent and child. + */ + smb_panic(__location__); + break; } } diff --git a/source3/winbindd/idmap_autorid.c b/source3/winbindd/idmap_autorid.c index 67d49c41876..ad53b5810ee 100644 --- a/source3/winbindd/idmap_autorid.c +++ b/source3/winbindd/idmap_autorid.c @@ -671,9 +671,9 @@ static NTSTATUS idmap_autorid_sid_to_id(struct idmap_tdb_common_context *common, * range. */ - DBG_NOTICE("Allocating range for domain %s refused\n", range.domsid); - map->status = ID_UNMAPPED; - return NT_STATUS_NONE_MAPPED; + DBG_NOTICE("Allocating range for domain %s required type_hint\n", range.domsid); + map->status = ID_REQUIRE_TYPE; + return NT_STATUS_SOME_NOT_MAPPED; allocate: ret = idmap_autorid_acquire_range(autorid_db, &range); diff --git a/source3/winbindd/idmap_ldap.c b/source3/winbindd/idmap_ldap.c index 19a55426a54..2f879bf77e8 100644 --- a/source3/winbindd/idmap_ldap.c +++ b/source3/winbindd/idmap_ldap.c @@ -251,6 +251,17 @@ static NTSTATUS idmap_ldap_allocate_id_internal(struct idmap_domain *dom, LDAP_ATTR_GIDNUMBER); break; + case ID_TYPE_BOTH: + /* + * This is not supported here yet and + * already handled in idmap_rw_new_mapping() + */ + FALL_THROUGH; + case ID_TYPE_NOT_SPECIFIED: + /* + * This is handled in idmap_rw_new_mapping() + */ + FALL_THROUGH; default: DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); return NT_STATUS_INVALID_PARAMETER; @@ -868,6 +879,7 @@ static NTSTATUS idmap_ldap_sids_to_unixids(struct idmap_domain *dom, const char **attr_list; char *filter = NULL; bool multi = False; + size_t num_required = 0; int idx = 0; int bidx = 0; int count; @@ -1076,7 +1088,21 @@ again: ids[i]->status = ID_UNMAPPED; if (ids[i]->sid != NULL) { ret = idmap_ldap_new_mapping(dom, ids[i]); + DBG_DEBUG("idmap_ldap_new_mapping returned %s\n", + nt_errstr(ret)); + if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) { + if (ids[i]->status == ID_REQUIRE_TYPE) { + num_required += 1; + continue; + } + } if (!NT_STATUS_IS_OK(ret)) { + /* + * If we can't create + * a new mapping it's unlikely + * that it will work for the + * next entry. + */ goto done; } } @@ -1084,6 +1110,9 @@ again: } ret = NT_STATUS_OK; + if (num_required > 0) { + ret = STATUS_SOME_UNMAPPED; + } done: talloc_free(memctx); diff --git a/source3/winbindd/idmap_rw.c b/source3/winbindd/idmap_rw.c index 700a946fc62..71bfc14e204 100644 --- a/source3/winbindd/idmap_rw.c +++ b/source3/winbindd/idmap_rw.c @@ -39,11 +39,39 @@ NTSTATUS idmap_rw_new_mapping(struct idmap_domain *dom, return NT_STATUS_INVALID_PARAMETER; } - if ((map->xid.type != ID_TYPE_UID) && (map->xid.type != ID_TYPE_GID)) { + if (map->sid == NULL) { return NT_STATUS_INVALID_PARAMETER; } - if (map->sid == NULL) { + switch (map->xid.type) { + case ID_TYPE_NOT_SPECIFIED: + /* + * We need to know if we need a user or group mapping. + * Ask the winbindd parent to provide a valid type hint. + */ + DBG_INFO("%s ID_TYPE_NOT_SPECIFIED => ID_REQUIRE_TYPE\n", + dom_sid_str_buf(map->sid, &buf)); + map->status = ID_REQUIRE_TYPE; + return NT_STATUS_SOME_NOT_MAPPED; + + case ID_TYPE_BOTH: + /* + * For now we still require + * an explicit type as hint + * and don't support ID_TYPE_BOTH + */ + DBG_INFO("%s ID_TYPE_BOTH => ID_REQUIRE_TYPE\n", + dom_sid_str_buf(map->sid, &buf)); + map->status = ID_REQUIRE_TYPE; + return NT_STATUS_SOME_NOT_MAPPED; + + case ID_TYPE_UID: + break; + + case ID_TYPE_GID: + break; + + default: return NT_STATUS_INVALID_PARAMETER; } diff --git a/source3/winbindd/idmap_tdb_common.c b/source3/winbindd/idmap_tdb_common.c index 34269e3fe56..0df8f2f3103 100644 --- a/source3/winbindd/idmap_tdb_common.c +++ b/source3/winbindd/idmap_tdb_common.c @@ -118,6 +118,17 @@ static NTSTATUS idmap_tdb_common_allocate_id(struct idmap_domain *dom, hwmtype = "GID"; break; + case ID_TYPE_BOTH: + /* + * This is not supported here yet and + * already handled in idmap_rw_new_mapping() + */ + FALL_THROUGH; + case ID_TYPE_NOT_SPECIFIED: + /* + * This is handled in idmap_rw_new_mapping() + */ + FALL_THROUGH; default: DEBUG(2, ("Invalid ID type (0x%x)\n", xid->type)); return NT_STATUS_INVALID_PARAMETER; @@ -529,7 +540,7 @@ static NTSTATUS idmap_tdb_common_sids_to_unixids_action(struct db_context *db, void *private_data) { struct idmap_tdb_common_sids_to_unixids_context *state = private_data; - size_t i, num_mapped = 0; + size_t i, num_mapped = 0, num_required = 0; NTSTATUS ret = NT_STATUS_OK; DEBUG(10, ("idmap_tdb_common_sids_to_unixids: " @@ -579,6 +590,12 @@ static NTSTATUS idmap_tdb_common_sids_to_unixids_action(struct db_context *db, state->ids[i]); DBG_DEBUG("idmap_tdb_common_new_mapping returned %s\n", nt_errstr(ret)); + if (NT_STATUS_EQUAL(ret, STATUS_SOME_UNMAPPED)) { + if (state->ids[i]->status == ID_REQUIRE_TYPE) { + num_required += 1; + continue; + } + } if (!NT_STATUS_IS_OK(ret)) { ret = STATUS_SOME_UNMAPPED; continue; @@ -598,6 +615,9 @@ done: } else { ret = NT_STATUS_OK; } + if (num_required > 0) { + ret = STATUS_SOME_UNMAPPED; + } } return ret; diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c index 3a3d47abbe5..35b6675520e 100644 --- a/source3/winbindd/wb_sids2xids.c +++ b/source3/winbindd/wb_sids2xids.c @@ -473,6 +473,17 @@ static void wb_sids2xids_done(struct tevent_req *subreq) for (si=0; si < src->num_ids; si++) { uint32_t di = state->tmp_idx[si]; + if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) { + /* + * This should not happen yet, as we always + * do a lookupsids and fill type_hint. + * + * Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE + * outside of winbindd! + */ + src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED; + } + if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) { dst->ids[di].xid = src->ids[si].xid; } diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 6348f9caeed..40a30d70ff9 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -227,6 +227,12 @@ NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p, for (i=0; istatus == ID_REQUIRE_TYPE) { + ids[i].xid.id = UINT32_MAX; + ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE; + continue; + } + if (!idmap_unix_id_is_in_range(m->xid.id, dom)) { DBG_DEBUG("id %"PRIu32" is out of range " "%"PRIu32"-%"PRIu32" for domain %s\n", diff --git a/source3/winbindd/winbindd_getgroups.c b/source3/winbindd/winbindd_getgroups.c index 63206c28134..7182156578b 100644 --- a/source3/winbindd/winbindd_getgroups.c +++ b/source3/winbindd/winbindd_getgroups.c @@ -202,6 +202,13 @@ static void winbindd_getgroups_sid2gid_done(struct tevent_req *subreq) case ID_TYPE_BOTH: include_gid = true; break; + case ID_TYPE_WB_REQUIRE_TYPE: + /* + * these are internal between winbindd + * parent and child. + */ + smb_panic(__location__); + break; } if (!include_gid) { -- 2.11.4.GIT