r23244: Fix loop with nscd and NSS recusive calls.
authorGerald Carter <jerry@samba.org>
Wed, 30 May 2007 19:47:35 +0000 (19:47 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:22:58 +0000 (12:22 -0500)
> Here's the problem I hit:
>
> getgrnam("foo") -> nscd -> NSS -> winbindd ->
>   winbindd_passdb.c:nam_to_sid() -> lookup_global_sam_name() ->
>   getgrnam("foo") -> nscd -> ....
>
> This is in the SAMBA_3_0 specifically but in theory could happen
> SAMBA_3_0_25 (or 26) for an unknown group.
>
> The attached patch passes down enough state for the
> name_to_sid() call to be able to determine the originating
> winbindd cmd that came into the parent.  So we can avoid
> making more NSS calls if the original call came in trough NSS
> so we don't deadlock ?  But you should still service
> lookupname() calls which are needed for example when
> doing the token access checks for a "valid groups" from
> smb.conf.
>
> I've got this in testing now.  The problem has shown up with the
> DsProvider on OS X and with nscd on SOlaris and Linux.
(This used to be commit bcc8a3290aaa0d2620e9d391ffbbf65541f6d742)

13 files changed:
source3/include/smb.h
source3/nsswitch/winbindd.h
source3/nsswitch/winbindd_async.c
source3/nsswitch/winbindd_cache.c
source3/nsswitch/winbindd_group.c
source3/nsswitch/winbindd_nss.h
source3/nsswitch/winbindd_passdb.c
source3/nsswitch/winbindd_reconnect.c
source3/nsswitch/winbindd_rpc.c
source3/nsswitch/winbindd_sid.c
source3/nsswitch/winbindd_user.c
source3/nsswitch/winbindd_util.c
source3/passdb/lookup_sid.c

index abdb3f37ba1dad25c3eb1aa1d65ddbf99c3f5ddc..7a3b487f080af1bc8e05dc14b5baad726fbe1d81 100644 (file)
@@ -247,12 +247,15 @@ typedef uint64_t NTTIME;
 
 #define SID_MAX_SIZE ((size_t)(8+(MAXSUBAUTHS*4)))
 
-#define LOOKUP_NAME_ISOLATED 1 /* Look up unqualified names */
-#define LOOKUP_NAME_REMOTE   2  /* Ask others */
-#define LOOKUP_NAME_ALL (LOOKUP_NAME_ISOLATED|LOOKUP_NAME_REMOTE)
-
-#define LOOKUP_NAME_GROUP    4  /* (unused) This is a NASTY hack for valid users = @foo
-                                * where foo also exists in as user. */
+#define LOOKUP_NAME_ISOLATED             0x00000001  /* Look up unqualified names */
+#define LOOKUP_NAME_REMOTE               0x00000002  /* Ask others */
+#define LOOKUP_NAME_GROUP                0x00000004  /* (unused) This is a NASTY hack for 
+                                                       valid users = @foo where foo also
+                                                       exists in as user. */
+#define LOOKUP_NAME_EXPLICIT             0x00000008  /* Only include
+                                                       explicitly mapped names and not 
+                                                       the Unix {User,Group} domain */
+#define LOOKUP_NAME_ALL                  (LOOKUP_NAME_ISOLATED|LOOKUP_NAME_REMOTE)
 
 /**
  * @brief Security Identifier
index e98c85940569eb95da3201388b063d55aaafa8e6..3d71aff0cd653c76e464b6f3134e6421a2da422f 100644 (file)
@@ -244,6 +244,7 @@ struct winbindd_methods {
        /* convert one user or group name to a sid */
        NTSTATUS (*name_to_sid)(struct winbindd_domain *domain,
                                TALLOC_CTX *mem_ctx,
+                               enum winbindd_cmd orig_cmd,
                                const char *domain_name,
                                const char *name,
                                DOM_SID *sid,
index b674ef6ceec83ed9d3f76311f54cebdc6e2f157a..dbe4ad012b1ed87a200fceb537fcd8e72101212a 100644 (file)
@@ -952,6 +952,7 @@ void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
                               void (*cont)(void *private_data, BOOL success,
                                            const DOM_SID *sid,
                                            enum lsa_SidType type),
+                              enum winbindd_cmd orig_cmd,
                               void *private_data)
 {
        struct winbindd_request request;
@@ -966,6 +967,7 @@ void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
 
        ZERO_STRUCT(request);
        request.cmd = WINBINDD_LOOKUPNAME;
+       request.original_cmd = orig_cmd;
        fstrcpy(request.data.name.dom_name, dom_name);
        fstrcpy(request.data.name.name, name);
 
@@ -977,7 +979,7 @@ void winbindd_lookupname_async(TALLOC_CTX *mem_ctx,
 
        s->dom_name = talloc_strdup( s, dom_name );
        s->name     = talloc_strdup( s, name );
-       s->caller_private_data = private_data;  
+       s->caller_private_data = private_data;
 
        do_async_domain(mem_ctx, domain, &request, lookupname_recv,
                        (void *)cont, s);
@@ -1012,7 +1014,7 @@ enum winbindd_result winbindd_dual_lookupname(struct winbindd_domain *domain,
                  name_domain, lp_winbind_separator(), name_user));
 
        /* Lookup name from DC using lsa_lookup_names() */
-       if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, name_domain,
+       if (!winbindd_lookup_sid_by_name(state->mem_ctx, state->request.original_cmd, domain, name_domain,
                                         name_user, &sid, &type)) {
                return WINBINDD_ERROR;
        }
index aa38bb6971349796699b13b71ad32135d08622ec..f9b045e10cb44e7b610455560cd86658424a692f 100644 (file)
@@ -1355,6 +1355,7 @@ skip_save:
 /* convert a single name to a sid in a domain */
 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
                            TALLOC_CTX *mem_ctx,
+                           enum winbindd_cmd orig_cmd,
                            const char *domain_name,
                            const char *name,
                            DOM_SID *sid,
@@ -1402,7 +1403,8 @@ do_query:
        DEBUG(10,("name_to_sid: [Cached] - doing backend query for name for domain %s\n",
                domain->name ));
 
-       status = domain->backend->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
+       status = domain->backend->name_to_sid(domain, mem_ctx, orig_cmd, 
+                                             domain_name, name, sid, type);
 
        /* and save it */
        refresh_sequence_number(domain, False);
index 1500324583d4b95e933544d2c8eb9c5178eb1cf1..05aeef2612f872cda960005b38d3927f33dfb8f3 100644 (file)
@@ -529,7 +529,7 @@ void winbindd_getgrnam(struct winbindd_cli_state *state)
        ws_name_replace( name_group, WB_REPLACE_CHAR );
         
        winbindd_lookupname_async( state->mem_ctx, domain->name, name_group,
-                                  getgrnam_recv, state );
+                                  getgrnam_recv, WINBINDD_GETGRNAM, state );
        }
 
 struct getgrsid_state {
@@ -1324,7 +1324,7 @@ void winbindd_getgroups(struct winbindd_cli_state *state)
        /* Get rid and name type from name.  The following costs 1 packet */
 
        winbindd_lookupname_async(state->mem_ctx, s->domname, s->username,
-                                 getgroups_usersid_recv, s);
+                                 getgroups_usersid_recv, WINBINDD_GETGROUPS, s);
 }
 
 static void getgroups_usersid_recv(void *private_data, BOOL success,
index 96c4b1161c651a5b4392ec61ccfcd4e613fd37c2..746b98bf7937334f5c260299295934707e3fc4c3 100644 (file)
@@ -230,6 +230,8 @@ typedef struct winbindd_gr {
 struct winbindd_request {
        uint32 length;
        enum winbindd_cmd cmd;   /* Winbindd command to execute */
+       enum winbindd_cmd original_cmd;   /* Original Winbindd command
+                                            issued to parent process */
        pid_t pid;               /* pid of calling process */
        uint32 flags;            /* flags relavant to a given request */
        fstring domain_name;    /* name of domain for which the request applies */
index 2a61908f0e01f1169d59afe8f9665e4e7245b684..8b8c4c66c62f404a9573db7df321565c5c5c477e 100644 (file)
@@ -93,16 +93,28 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 /* convert a single name to a sid in a domain */
 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
                            TALLOC_CTX *mem_ctx,
+                           enum winbindd_cmd original_cmd,
                            const char *domain_name,
                            const char *name,
                            DOM_SID *sid,
                            enum lsa_SidType *type)
 {
+       uint32 flags = LOOKUP_NAME_ALL;
+
+       switch ( original_cmd ) {
+       case WINBINDD_LOOKUPNAME:
+               /* This call is ok */
+               break;
+       default:
+               /* Avoid any NSS calls in the lookup_name by default */
+               flags |= LOOKUP_NAME_EXPLICIT;
+               DEBUG(10,("winbindd_passdb: limiting name_to_sid() to explicit mappings\n"));
+               break;
+       }
+       
        DEBUG(10, ("Finding name %s\n", name));
 
-       if ( !lookup_name( mem_ctx, name, LOOKUP_NAME_ALL, 
-               NULL, NULL, sid, type ) )
-       {
+       if ( !lookup_name( mem_ctx, name, flags, NULL, NULL, sid, type ) ) {
                return NT_STATUS_NONE_MAPPED;
        }
 
index 6b484bdd062961d96e705063f637c14669c2be92..70e5579109b8a83f82fed58edb1a72f5100f657d 100644 (file)
@@ -84,6 +84,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 /* convert a single name to a sid in a domain */
 static NTSTATUS name_to_sid(struct winbindd_domain *domain,
                            TALLOC_CTX *mem_ctx,
+                           enum winbindd_cmd orig_cmd,
                            const char *domain_name,
                            const char *name,
                            DOM_SID *sid,
@@ -91,12 +92,12 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain,
 {
        NTSTATUS result;
 
-       result = msrpc_methods.name_to_sid(domain, mem_ctx,
+       result = msrpc_methods.name_to_sid(domain, mem_ctx, orig_cmd,
                                           domain_name, name,
                                           sid, type);
 
        if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))
-               result = msrpc_methods.name_to_sid(domain, mem_ctx,
+               result = msrpc_methods.name_to_sid(domain, mem_ctx, orig_cmd,
                                                   domain_name, name,
                                                   sid, type);
 
index 4a6448348e9d943eeeb2194a30903d75731807b1..03aa42012e4fcb1b527e4c8438cc4356a2f900fd 100644 (file)
@@ -255,11 +255,12 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 
 /* convert a single name to a sid in a domain */
 NTSTATUS msrpc_name_to_sid(struct winbindd_domain *domain,
-                           TALLOC_CTX *mem_ctx,
-                           const char *domain_name,
-                           const char *name,
-                           DOM_SID *sid,
-                           enum lsa_SidType *type)
+                          TALLOC_CTX *mem_ctx,
+                          enum winbindd_cmd original_cmd,
+                          const char *domain_name,
+                          const char *name,
+                          DOM_SID *sid,
+                          enum lsa_SidType *type)
 {
        NTSTATUS result;
        DOM_SID *sids = NULL;
index 881aa1af7912c0590b117a3558970a07001b024b..147917f9789682d40744dee0615c5ffff0e57f0c 100644 (file)
@@ -103,7 +103,8 @@ void winbindd_lookupname(struct winbindd_cli_state *state)
                  name_domain, lp_winbind_separator(), name_user));
 
        winbindd_lookupname_async(state->mem_ctx, name_domain, name_user,
-                                 lookupname_recv, state);
+                                 lookupname_recv, WINBINDD_LOOKUPNAME, 
+                                 state);
 }
 
 static void lookupname_recv(void *private_data, BOOL success,
index 48b470cdd0dae54f012e23ed95d69e38062adee4..ef37e86dec38f0fb34e1b44b367597e94c4c5530 100644 (file)
@@ -400,7 +400,8 @@ void winbindd_getpwnam(struct winbindd_cli_state *state)
        /* Get rid and name type from name.  The following costs 1 packet */
 
        winbindd_lookupname_async(state->mem_ctx, domname, username,
-                                 getpwnam_name2sid_recv, state);
+                                 getpwnam_name2sid_recv, WINBINDD_GETPWNAM, 
+                                 state);
 }
 
 static void getpwnam_name2sid_recv(void *private_data, BOOL success,
index c3f8e917349a3be901fbb5ef4cd72a8a0f3b7718..082ec4440b0d869edb01260c89b7b3bd8d25be12 100644 (file)
@@ -941,6 +941,7 @@ struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
 /* Lookup a sid in a domain from a name */
 
 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
+                                enum winbindd_cmd orig_cmd,
                                 struct winbindd_domain *domain, 
                                 const char *domain_name,
                                 const char *name, DOM_SID *sid, 
@@ -949,7 +950,8 @@ BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
        NTSTATUS result;
 
        /* Lookup name */
-       result = domain->methods->name_to_sid(domain, mem_ctx, domain_name, name, sid, type);
+       result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
+                                             domain_name, name, sid, type);
 
        /* Return sid and type if lookup successful */
        if (!NT_STATUS_IS_OK(result)) {
index dbc0e75e595c845c074d9e338a5411843f47f1c0..dd7ffa8d819964bb14a500ac07daef443a6c4fd2 100644 (file)
@@ -102,7 +102,7 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx,
                        goto ok;
        }
 
-       if (strequal(domain, unix_users_domain_name())) {
+       if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_users_domain_name())) {
                if (lookup_unix_user_name(name, &sid)) {
                        type = SID_NAME_USER;
                        goto ok;
@@ -111,7 +111,7 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx,
                return False;
        }
 
-       if (strequal(domain, unix_groups_domain_name())) {
+       if (!(flags & LOOKUP_NAME_EXPLICIT) && strequal(domain, unix_groups_domain_name())) {
                if (lookup_unix_group_name(name, &sid)) {
                        type = SID_NAME_DOM_GRP;
                        goto ok;
@@ -262,13 +262,13 @@ BOOL lookup_name(TALLOC_CTX *mem_ctx,
        /* 11. Ok, windows would end here. Samba has two more options:
                Unmapped users and unmapped groups */
 
-       if (lookup_unix_user_name(name, &sid)) {
+       if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_user_name(name, &sid)) {
                domain = talloc_strdup(tmp_ctx, unix_users_domain_name());
                type = SID_NAME_USER;
                goto ok;
        }
 
-       if (lookup_unix_group_name(name, &sid)) {
+       if (!(flags & LOOKUP_NAME_EXPLICIT) && lookup_unix_group_name(name, &sid)) {
                domain = talloc_strdup(tmp_ctx, unix_groups_domain_name());
                type = SID_NAME_DOM_GRP;
                goto ok;