[Samba] Samba 3(PDC) + winbind, anyone has it working ?

gary ng garyng2000 at yahoo.com
Sat Sep 27 06:19:06 GMT 2003


Hi,

I have reported this(and seen similar problems by
others) before. I took the plunge today and trace into
the source to see what happened. The result seems to
be that winbind(or the nsswitch part) would never work
in a PDC/BDC situation, only for other trusted
domain(probably). Below is my analysis.

I have setup nsswitch.conf and pam.d/login properly so
libnss_winbind and pam_winbind are actually called(see
the detail later). The command I issued is :

#login EXAMPLE\\root

where EXAMPLE is the domain, root is the user. 

The auth.log goes like the following :
==========================
Sep 27 13:42:32 woody pam_winbind[1162]: user
'EXAMPLE\root' granted acces
Sep 27 13:42:32 woody PAM_unix[1162]: could not
identify user (from getpwnam(EXAMPLE\root))
Sep 27 13:42:32 woody login[1162]: User not known to
the underlying authentication module
==============================

The winbindd log goes like the following :

=====================================
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_pam.c:winbindd_pam_auth(190)
  Plain-text authentication for user EXAMPLE\root
returned NT_STATUS_OK (PAM: 0)
[2003/09/27 13:42:32, 5]
nsswitch/winbindd.c:winbind_client_read(462)
  read failed on sock 22, pid 1162: EOF
[2003/09/27 13:42:32, 3]
nsswitch/winbindd_user.c:winbindd_getpwnam(112)
  [ 1162]: getpwnam EXAMPLE\root
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_acct.c:wb_getpwnam(392)
  wb_getpwnam: Did not find user (root)
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_user.c:winbindd_getpwnam(124)
  winbindd_getpwnam: lookup for EXAMPLE\root failed
[2003/09/27 13:42:32, 3]
nsswitch/winbindd_user.c:winbindd_getpwnam(112)
  [ 1162]: getpwnam EXAMPLE\root
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_acct.c:wb_getpwnam(392)
  wb_getpwnam: Did not find user (root)
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_user.c:winbindd_getpwnam(124)
  winbindd_getpwnam: lookup for EXAMPLE\root failed
[2003/09/27 13:42:32, 3]
nsswitch/winbindd_user.c:winbindd_getpwnam(112)
  [ 1162]: getpwnam EXAMPLE\root
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_acct.c:wb_getpwnam(392)
  wb_getpwnam: Did not find user (root)
[2003/09/27 13:42:32, 5]
nsswitch/winbindd_user.c:winbindd_getpwnam(124)
  winbindd_getpwnam: lookup for EXAMPLE\root failed
===================================================

As one can see, the password authentication WORKS(see
the line in auth.log(about pam_winbind) and the line
in winbindd.log(Plain Text authentication result).
However, after the authentication part, the nss part
fails because libnss_winbind invokes
winbindd_getpwnam("EXAMPLE\root"). The reason is shown
below. In winbnd_user.c, the relavent function is
listed below :

enum winbindd_result winbindd_getpwnam(struct
winbindd_cli_state *state)
{
	WINBIND_USERINFO user_info;
	WINBINDD_PW *pw;
	DOM_SID user_sid;
	NTSTATUS status;
	fstring name_domain, name_user;
	enum SID_NAME_USE name_type;
	struct winbindd_domain *domain;
	TALLOC_CTX *mem_ctx;

	/* Ensure null termination */

state->request.data.username[sizeof(state->request.data.username)-1]='\0';

	DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned
long)state->pid,
		  state->request.data.username));

	/* Parse domain and username */

	parse_domain_user(state->request.data.username,
		name_domain, name_user);

	/* if this is our local domain (or no domain), the do
a local tdb search */

	if ( !*name_domain || strequal(name_domain,
get_global_sam_name()) ) {
		if ( !(pw = wb_getpwnam(name_user)) ) {
			DEBUG(5,("winbindd_getpwnam: lookup for %s\\%s
failed\n",
				name_domain, name_user));
			return WINBINDD_ERROR;
		}
		memcpy( &state->response.data.pw, pw,
sizeof(WINBINDD_PW) );
		return WINBINDD_OK;
	}

	/* should we deal with users for our domain? */

	if ( lp_winbind_trusted_domains_only() &&
strequal(name_domain, lp_workgroup())) {
		DEBUG(7,("winbindd_getpwnam: My domain -- rejecting
getpwnam() for %s\\%s.\n",
			name_domain, name_user));
		return WINBINDD_ERROR;
	}

	if ((domain = find_domain_from_name(name_domain)) ==
NULL) {
		DEBUG(5, ("no such domain: %s\n", name_domain));
		return WINBINDD_ERROR;
	}
	
	/* Get rid and name type from name */

	if (!winbindd_lookup_sid_by_name(domain, name_user,
&user_sid, &name_type)) {
		DEBUG(1, ("user '%s' does not exist\n", name_user));
		return WINBINDD_ERROR;
	}

	if (name_type != SID_NAME_USER) {
		DEBUG(1, ("name '%s' is not a user name: %d\n",
name_user,
			  name_type));
		return WINBINDD_ERROR;
	}

	/* Get some user info.  Split the user rid from the
sid obtained
	   from the winbind_lookup_by_name() call and use it
in a
	   winbind_lookup_userinfo() */

	if (!(mem_ctx =
talloc_init("winbindd_getpwnam([%s]\\[%s])", 
					  name_domain, name_user))) {
		DEBUG(1, ("out of memory\n"));
		return WINBINDD_ERROR;
	}

	status = domain->methods->query_user(domain, mem_ctx,
&user_sid, 
					     &user_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("error getting user info for user
'[%s]\\[%s]'\n", 
			  name_domain, name_user));
		talloc_destroy(mem_ctx);
		return WINBINDD_ERROR;
	}

	/* Now take all this information and fill in a passwd
structure */	
	if (!winbindd_fill_pwent(name_domain, name_user,
				 user_info.user_sid, user_info.group_sid, 
				 user_info.full_name,
				 &state->response.data.pw)) {
		talloc_destroy(mem_ctx);
		return WINBINDD_ERROR;
	}

	talloc_destroy(mem_ctx);
	
	return WINBINDD_OK;
}       
============================
One can see that the code would test if the domain is
'my domain' or empty(in this case since I am running
winbind on a PDC/BDC), the result is true. Under this
situation wb_getpwnam is called with the domain
stripped(again confirmed by the winbindd log). So it
would call wb_getpwnam("root"). Below is the
wb_getpwnam function in winbindd_acct.c

WINBINDD_PW* wb_getpwnam( const char * name )
{
	char *keystr;
	TDB_DATA data;
	static WINBINDD_PW *pw;
	
	if ( !account_tdb && !winbindd_accountdb_init() ) {
		DEBUG(0,("wb_getpwnam: Failed to open winbindd
account db\n"));
		return NULL;
	}
		

	keystr = acct_userkey_byname( name );

	data = tdb_fetch_bystring( account_tdb, keystr );

	pw = NULL;

	if ( data.dptr ) {
		pw = string2passwd( data.dptr );
		SAFE_FREE( data.dptr );
	}

	DEBUG(5,("wb_getpwnam: %s user (%s)\n",
		(pw ? "Found" : "Did not find"), name ));

	return pw;
}
==========================================

I see two problems here. First, it doesn't care if I
choose to have the idmap backend on LDAP, it would
always goes to the tdb backend. So unless winbind sync
the tdb backend with the LDAP entries constantly, this
could be the first source of problem. Seeing this, I
tried to change the backend back to tdb and found
another issue. the winbindd_idmap.tdb on may machine
stores things in RID and there is no entry by the name
'root' so wb_getpwnam("root") would always fails(or
another other user for that matter). This is the
consistent with the winbindd log entries.

So based on what I saw, winbind is broken when running
on a PDC/BDC for its own domain. It should work for
trusted domain though(didn't check this as I don't
have a testing setup).

who should I contact if I want to follow up this issue
? 

thank you for your time to read this.
 

__________________________________
Do you Yahoo!?
The New Yahoo! Shopping - with improved product search
http://shopping.yahoo.com



More information about the samba mailing list