winbindd: allow idmap backends to mark entries with ID_[TYPE_WB_]REQUIRE_TYPE
authorStefan Metzmacher <metze@samba.org>
Tue, 15 Sep 2020 15:26:11 +0000 (17:26 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Fri, 23 Oct 2020 03:25:37 +0000 (03:25 +0000)
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 <metze@samba.org>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
librpc/idl/idmap.idl
source3/passdb/lookup_sid.c
source3/winbindd/idmap_autorid.c
source3/winbindd/idmap_ldap.c
source3/winbindd/idmap_rw.c
source3/winbindd/idmap_tdb_common.c
source3/winbindd/wb_sids2xids.c
source3/winbindd/winbindd_dual_srv.c
source3/winbindd/winbindd_getgroups.c

index 54fd888dcabe89442e8a1d5fe0786cd5d1542ffc..e58e39210c70656f95880dbe288471f0755ade7d 100644 (file)
@@ -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 {
index cd9d5f1ad6a529379a704d3a62179ca555002e3d..ff8a16619a8c14875c833c61ee097a4c47d5b7ad 100644 (file)
@@ -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;
                }
        }
 
index 67d49c41876f47adb80fe2e61c99e4fb071be3d1..ad53b5810ee7d32fc42578de767922387c5e8b85 100644 (file)
@@ -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);
index 19a55426a54b162d065412dacafb7553238ef4f4..2f879bf77e86a052fa3d6a535965bcefedde7f7b 100644 (file)
@@ -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);
index 700a946fc62f5f8f37b4730e6acd139869bf08de..71bfc14e20439153cf25508649c4540dcc469f2d 100644 (file)
@@ -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;
        }
 
index 34269e3fe56e18db8af444f00b193bc10e65e9c1..0df8f2f3103b0881cc4e16c1e9fa795f2e879d8b 100644 (file)
@@ -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;
index 3a3d47abbe554fd408c32d18f457bd61458437fd..35b6675520e96e6dab08134339c3d63adfbc1739 100644 (file)
@@ -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;
                }
index 6348f9caeed46786ccd1777418f1ec3ad6a95f45..40a30d70ff94e0e79266c46b4605e873be0e7a0a 100644 (file)
@@ -227,6 +227,12 @@ NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
        for (i=0; i<num_ids; i++) {
                struct id_map *m = id_map_ptrs[i];
 
+               if (m->status == 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",
index 63206c28134ec31edf86ddd3093f0b6b65174c83..7182156578b40cd72ae4f81b60eb4359e6ddea94 100644 (file)
@@ -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) {