winbindd recursion in 4.18 for local users

Andrew Walker awalker at ixsystems.com
Thu Jun 15 17:46:41 UTC 2023


Hey all,

When I create a username that contains an upper-case character (and
insert into passdb.tdb), uncached lookups in winbind of name-to-sid
for name that differs in case only basically enters into a recursive
loop until winbind hits command timeout.

username "Bob" + "Bob" -- hit, no loop
username "Bob" + "bob" -- failure / command timeout

```
  [python3 (46157)] Winbind external command LOOKUPNAME start.
  [nss_winbind (45990)] Winbind external command GETPWNAM start.
  [nss_winbind (46000)] Winbind external command GETPWNAM start.
  [nss_winbind (46010)] Winbind external command GETPWNAM start.
  [nss_winbind (46027)] Winbind external command GETPWNAM start.
  [nss_winbind (46039)] Winbind external command GETPWNAM start.
  [nss_winbind (46070)] Winbind external command GETPWNAM start.
  [nss_winbind (46079)] Winbind external command GETPWNAM start.
  [nss_winbind (46135)] Winbind external command GETPWNAM start.
```

NOTE: above is using libwbclient via python, but the same happens with wbinfo.

Basically we go winbind_lookupname_send() -> wb_lookupname() ->
winbind domain child -> forked rpc client (passdb) -> getpwnam
(lower-case "bob") -> nss_winbind -> wb_lookupname-> <repeat>


If I make the following relatively simple change to winbind the
recursion is prevented:
```

root at scalebuilder:/CODE/scale-build/sources/truenas_samba# git diff HEAD
diff --git a/source3/winbindd/wb_lookupname.c b/source3/winbindd/wb_lookupname.c
index 12dbfbef2d..bb39f01a08 100644
--- a/source3/winbindd/wb_lookupname.c
+++ b/source3/winbindd/wb_lookupname.c
@@ -20,6 +20,8 @@
 #include "includes.h"
 #include "winbindd.h"
 #include "librpc/gen_ndr/ndr_winbind_c.h"
+#include "passdb/lookup_sid.h" /* only for LOOKUP flags */
+#include "passdb/machine_sid.h"
 #include "../libcli/security/security.h"

 struct wb_lookupname_state {
@@ -74,6 +76,20 @@ struct tevent_req *wb_lookupname_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }

+       if (flags == (LOOKUP_NAME_NO_NSS | LOOKUP_NAME_REMOTE)) {
+               if (dom_sid_compare_domain(&domain->sid,
+                   get_global_sam_sid()) == 0) {
+                       D_NOTICE("Domain [%s] is our local domain, "
+                                "avoid recursive lookup\n",
+                                dom_name);
+
+                       tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
+                       return tevent_req_post(req, ev);
+               }
+
+               flags &= ~LOOKUP_NAME_REMOTE;
+       }
+
        subreq = dcerpc_wbint_LookupName_send(
                state, ev, dom_child_handle(domain),
                state->dom_name, state->name,
diff --git a/source3/winbindd/winbindd_getpwnam.c
b/source3/winbindd/winbindd_getpwnam.c
index da162a4b77..f26afb505e 100644
--- a/source3/winbindd/winbindd_getpwnam.c
+++ b/source3/winbindd/winbindd_getpwnam.c
@@ -87,7 +87,7 @@ struct tevent_req *winbindd_getpwnam_send(TALLOC_CTX *mem_ctx,
                                    state->namespace,
                                    state->domname,
                                    state->username,
-                                   LOOKUP_NAME_NO_NSS);
+                                   LOOKUP_NAME_NO_NSS | LOOKUP_NAME_REMOTE);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
```

The reasoning behind this is that nss_winbind probably shouldn't
bother with trying to return getpwnam results for our local machine
SID. Failure for other NSS modules to provide passwd entry should be
authoritative, and it's better to bail on the request quickly.

Andrew



More information about the samba-technical mailing list