> 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)
#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
/* 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,
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;
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);
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);
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;
}
/* 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,
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);
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 {
/* 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,
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 */
/* 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;
}
/* 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,
{
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);
/* 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;
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,
/* 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,
/* 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,
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)) {
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;
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;
/* 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;