winbindd: Avoid deadlock in sam_name_to_sid()
authorVolker Lendecke <vl@samba.org>
Tue, 23 Feb 2021 07:27:07 +0000 (08:27 +0100)
committerJeremy Allison <jra@samba.org>
Tue, 6 Apr 2021 22:29:34 +0000 (22:29 +0000)
"Unix Users" and "Unix Groups" can recurse into nsswitch and thus into
winbind. In the binding process, we have winbindd_off(), but if we
pass the lookupNames request to a forked lsad, lsad does not
necessarily have that setting. So lsad might turn back to winbind,
which could lead to a deadlock. Handle the nsswitch lookups in
winbind.

While there, also do the simple wellknown names and the "DOMAIN\" type
3 lookups directly in winbind.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/winbindd/winbindd_samr.c

index d8cfeab8ecb406229e29ebc4710966bd0c4a94ca..d64917df6aae9b48f5f871a2ae17e55e9b4e0df9 100644 (file)
@@ -569,14 +569,71 @@ static NTSTATUS sam_name_to_sid(struct winbindd_domain *domain,
        struct rpc_pipe_client *lsa_pipe;
        struct policy_handle lsa_policy = { 0 };
        struct dom_sid sid;
-       const char *dom_name;
+       const char *dom_name = domain_name;
        enum lsa_SidType type;
        TALLOC_CTX *tmp_ctx = talloc_stackframe();
-       NTSTATUS status;
+       NTSTATUS status = NT_STATUS_NONE_MAPPED;
        bool retry = false;
+       bool ok;
 
        DBG_NOTICE("%s\\%s\n", domain_name, name);
 
+       if (strequal(domain_name, unix_users_domain_name())) {
+               struct passwd *pwd = NULL;
+
+               if (name[0] == '\0') {
+                       sid_copy(&sid, &global_sid_Unix_Users);
+                       type = SID_NAME_DOMAIN;
+                       goto done;
+               }
+
+               pwd = Get_Pwnam_alloc(tmp_ctx, name);
+               if (pwd == NULL) {
+                       goto fail;
+               }
+               ok = sid_compose(&sid, &global_sid_Unix_Users, pwd->pw_uid);
+               if (!ok) {
+                       status = NT_STATUS_INTERNAL_ERROR;
+                       goto fail;
+               }
+               type = SID_NAME_USER;
+               goto done;
+       }
+
+       if (strequal(domain_name, unix_groups_domain_name())) {
+               struct group *grp = NULL;
+
+               if (name[0] == '\0') {
+                       sid_copy(&sid, &global_sid_Unix_Groups);
+                       type = SID_NAME_DOMAIN;
+                       goto done;
+               }
+
+               grp = getgrnam(name);
+               if (grp == NULL) {
+                       goto fail;
+               }
+               ok = sid_compose(&sid, &global_sid_Unix_Groups, grp->gr_gid);
+               if (!ok) {
+                       status = NT_STATUS_INTERNAL_ERROR;
+                       goto fail;
+               }
+               type = SID_NAME_DOM_GRP;
+               goto done;
+       }
+
+       if (name[0] == '\0') {
+               sid_copy(&sid, &domain->sid);
+               type = SID_NAME_DOMAIN;
+               goto done;
+       }
+
+       ok = lookup_wellknown_name(mem_ctx, name, &sid, &dom_name);
+       if (ok) {
+               type = SID_NAME_WKN_GRP;
+               goto done;
+       }
+
 again:
        status = open_cached_internal_pipe_conn(domain,
                                                NULL,
@@ -584,7 +641,7 @@ again:
                                                &lsa_pipe,
                                                &lsa_policy);
        if (!NT_STATUS_IS_OK(status)) {
-               goto done;
+               goto fail;
        }
 
        status = rpc_name_to_sid(tmp_ctx,
@@ -603,14 +660,15 @@ again:
        }
 
        if (!NT_STATUS_IS_OK(status)) {
-               goto done;
+               goto fail;
        }
 
+done:
        if (pdom_name != NULL) {
                *pdom_name = talloc_strdup(mem_ctx, dom_name);
                if (*pdom_name == NULL) {
                        status = NT_STATUS_NO_MEMORY;
-                       goto done;
+                       goto fail;
                }
        }
 
@@ -621,7 +679,8 @@ again:
                *ptype = type;
        }
 
-done:
+       status = NT_STATUS_OK;
+fail:
        TALLOC_FREE(tmp_ctx);
        return status;
 }