nss_info plugin interface

Gerald (Jerry) Carter jerry at samba.org
Wed Jan 24 01:40:03 GMT 2007


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Folks,

Here's the current patch of the nss_info plugin interface
for the "winbind nss info" parameter.  This provides a means
to load a shared library to retrieve the home directory, login shell,
primary gid, and gecos information (see nss_info.h).

The primary hold up was to make idmap_ad.c conform to the new
interface.  I'm still not done with this but the SID/id
mappings are working against Windows 2003R2 (using rfc2307
attributes).

I'm going to go ahead and check this into SAMBA_3_0 and
continue to fix the remaining idmap_ad nss_info issues.





cheers, jerry
=====================================================================
Samba                                    ------- http://www.samba.org
Centeris                         -----------  http://www.centeris.com
"What man is a man who does not make the world better?"      --Balian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFtrjzIR7qMdg1EfYRApYWAJwLDFEKYxAa30djZ0oeALl7W6zR3ACgtsgG
ODBEEEdM9VI6dpjmfRJmkHU=
=rMmJ
-----END PGP SIGNATURE-----
-------------- next part --------------
=== added file 'source/include/nss_info.h'
--- source/include/nss_info.h	1970-01-01 00:00:00 +0000
+++ source/include/nss_info.h	2007-01-24 01:28:38 +0000
@@ -0,0 +1,68 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Idmap NSS headers
+
+   Copyright (C) Gerald Carter             2006
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#ifndef _IDMAP_NSS_H
+#define _IDMAP_NSS_H
+
+/* The interface version specifier */
+
+#define SMB_NSS_INFO_INTERFACE_VERSION	  1
+
+/* List of available backends.  All backends must 
+   register themselves */
+
+struct nss_function_entry {
+	struct nss_function_entry *prev, *next;
+	
+	const char *name;
+	struct nss_info_methods *methods;
+};
+
+/* List of configured domains.  Each domain points 
+   back to its configured backend. */
+
+struct nss_domain_entry {
+	struct nss_domain_entry *prev, *next;
+
+	const char *domain;
+
+	NTSTATUS init_status;	
+	struct nss_function_entry *backend;
+
+	/* hold state on a per domain basis */
+
+	void *state;
+};
+
+/* API */
+
+struct nss_info_methods {
+	NTSTATUS (*init)( struct nss_domain_entry *e );
+	NTSTATUS (*get_nss_info)( struct nss_domain_entry *e, 
+				  const DOM_SID *sid, 
+				  TALLOC_CTX *ctx, 
+				  ADS_STRUCT *ads, LDAPMessage *msg,
+				  char **homedir, char **shell, char **gecos, gid_t *p_gid);
+	NTSTATUS (*close_fn)( void );
+};
+
+#endif /* _IDMAP_NSS_H_ */

=== added file 'source/nsswitch/nss_info_template.c'
--- source/nsswitch/nss_info_template.c	1970-01-01 00:00:00 +0000
+++ source/nsswitch/nss_info_template.c	2007-01-24 01:28:38 +0000
@@ -0,0 +1,84 @@
+/* 
+   Unix SMB/CIFS implementation.
+   idMap nss template plugin
+
+   Copyright (C) Gerald Carter             2006
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
+
+#include "includes.h"
+#include "nss_info.h"
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_template_init( struct nss_domain_entry *e )
+{
+	return NT_STATUS_OK;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_template_get_info( struct nss_domain_entry *e,
+				       const DOM_SID *sid, 
+				       TALLOC_CTX *ctx,
+				       ADS_STRUCT *ads,
+				       LDAPMessage *msg,
+				       char **homedir,
+				       char **shell, 
+				       char **gecos,
+				       uint32 *gid )
+{     
+	if ( !homedir || !shell || !gecos )
+		return NT_STATUS_INVALID_PARAMETER;
+	
+	*homedir = talloc_strdup( ctx, lp_template_homedir() );
+	*shell   = talloc_strdup( ctx, lp_template_shell() );
+	*gecos   = NULL;
+
+	if ( !*homedir || !*shell ) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	
+	return NT_STATUS_OK;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_template_close( void )
+{
+	return NT_STATUS_OK;
+}
+
+
+/************************************************************************
+ ***********************************************************************/
+
+static struct nss_info_methods nss_template_methods = {
+	nss_template_init,
+	nss_template_get_info,
+	nss_template_close
+};
+		
+NTSTATUS nss_info_template_init( void )
+{
+	return smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, 
+				      "template", 
+				      &nss_template_methods);	
+}

=== modified file 'source/Makefile.in'
--- source/Makefile.in	2007-01-22 12:33:43 +0000
+++ source/Makefile.in	2007-01-24 01:28:38 +0000
@@ -181,7 +181,9 @@
 IDMAP_MODULES = @IDMAP_MODULES@
 CHARSET_MODULES = @CHARSET_MODULES@
 AUTH_MODULES = @AUTH_MODULES@
-MODULES = $(VFS_MODULES) $(PDB_MODULES) $(RPC_MODULES) $(IDMAP_MODULES) $(CHARSET_MODULES) $(AUTH_MODULES)
+NSS_INFO_MODULES = @NSS_INFO_MODULES@
+MODULES = $(VFS_MODULES) $(PDB_MODULES) $(RPC_MODULES) $(IDMAP_MODULES) \
+          $(CHARSET_MODULES) $(AUTH_MODULES) $(NSS_INFO_MODULES)
 
 ######################################################################
 # object file lists
@@ -289,7 +291,7 @@
 	     libads/authdata.o libads/cldap.o
 
 LIBADS_SERVER_OBJ = libads/util.o libads/kerberos_verify.o \
-		    libads/ldap_schema.o nsswitch/nss_info.o
+		    libads/ldap_schema.o 
 
 SECRETS_OBJ = passdb/secrets.o passdb/machine_sid.o 
 
@@ -745,7 +747,8 @@
 	    $(RPC_SVC_OBJ) $(RPC_WKS_OBJ) $(RPC_DFS_OBJ) $(RPC_SPOOLSS_OBJ) \
 	    $(RPC_ECHO_OBJ) $(RPC_SVCCTL_OBJ) $(RPC_EVENTLOG_OBJ) $(SMBLDAP_OBJ) \
             $(IDMAP_OBJ) libsmb/spnego.o $(PASSCHANGE_OBJ) $(RPC_UNIXINFO_OBJ) \
-            $(RPC_NTSVCS_OBJ) $(RPC_INITSHUTDOWN_OBJ) $(PASSWD_UTIL_OBJ) $(LIBGPO_OBJ)
+            $(RPC_NTSVCS_OBJ) $(RPC_INITSHUTDOWN_OBJ) utils/passwd_util.o \
+	    $(LIBGPO_OBJ) $(NSS_INFO_OBJ)
 
 WINBIND_WINS_NSS_OBJ = nsswitch/wins.o $(PARAM_OBJ) \
 	$(LIBSMB_OBJ) $(LIB_NONSMBD_OBJ) $(NSSWINS_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ)
@@ -758,6 +761,10 @@
 
 IDMAP_OBJ     = nsswitch/idmap.o nsswitch/idmap_cache.o nsswitch/idmap_util.o @IDMAP_STATIC@
 
+NSS_INFO_OBJ = nsswitch/nss_info.o @NSS_INFO_STATIC@
+
+IDMAP_NSS_OBJ = sam/idmap_nss.o @IDMAP_NSS_STATIC@
+
 WINBINDD_OBJ1 = \
 		nsswitch/winbindd.o       \
 		nsswitch/winbindd_user.o  \
@@ -785,7 +792,7 @@
 		$(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) \
 		$(PROFILE_OBJ) $(SLCACHE_OBJ) $(SMBLDAP_OBJ) \
 		$(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
-		$(DCUTIL_OBJ) $(IDMAP_OBJ) \
+		$(DCUTIL_OBJ) $(IDMAP_OBJ) $(NSS_INFO_OBJ) \
 		$(AFS_OBJ) $(AFS_SETTOKEN_OBJ) \
 		$(LIBADS_SERVER_OBJ) $(SERVER_MUTEX_OBJ) $(LDB_OBJ)
 
@@ -1549,6 +1556,12 @@
 	@$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_GPFS_OBJ) \
 		@SONAMEFLAG@`basename $@`
 
+#########################################################
+## IdMap NSS plugins
+
+## None here right now
+#########################################################
+
 bin/wbinfo at EXEEXT@: $(WBINFO_OBJ) @BUILD_POPT@ bin/.dummy
 	@echo Linking $@
 	@$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(WBINFO_OBJ) $(DYNEXP) $(LIBS) $(LDAP_LIBS) @POPTLIBS@

=== modified file 'source/configure.in'
--- source/configure.in	2007-01-23 03:12:56 +0000
+++ source/configure.in	2007-01-24 01:28:38 +0000
@@ -592,7 +592,7 @@
 
 dnl Add modules that have to be built by default here
 dnl These have to be built static:
-default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsa rpc_samr rpc_winreg rpc_initshutdown rpc_lsa_ds rpc_wkssvc rpc_svcctl rpc_ntsvcs rpc_net rpc_netdfs rpc_srvsvc rpc_spoolss rpc_eventlog rpc_unixinfo auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin vfs_default"
+default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsa rpc_samr rpc_winreg rpc_initshutdown rpc_lsa_ds rpc_wkssvc rpc_svcctl rpc_ntsvcs rpc_net rpc_netdfs rpc_srvsvc rpc_spoolss rpc_eventlog rpc_unixinfo auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin vfs_default nss_info_template"
 
 dnl These are preferably build shared, and static if dlopen() is not available
 default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy charset_CP850 charset_CP437 auth_script"
@@ -5862,6 +5862,11 @@
 MODULE_idmap_passdb=STATIC
 MODULE_idmap_nss=STATIC
 
+MODULE_idmap_passdb=STATIC
+MODULE_idmap_nss=STATIC
+
+MODULE_nss_info_template=STATIC
+
 AC_ARG_WITH(static-modules,
 [  --with-static-modules=MODULES  Comma-separated list of names of modules to statically link in],
 [ if test $withval; then
@@ -5912,6 +5917,9 @@
 SMB_MODULE(idmap_ad, nsswitch/idmap_ad.o, "bin/ad.$SHLIBEXT", IDMAP)
 SMB_SUBSYSTEM(IDMAP, nsswitch/idmap.o)
 
+SMB_MODULE(nss_info_template, nsswitch/nss_info_template.o, "bin/template.$SHLIBEXT", NSS_INFO)
+SMB_SUBSYSTEM(NSS_INFO, nsswitch/nss_info.o)
+
 SMB_MODULE(charset_weird, modules/weird.o, "bin/weird.$SHLIBEXT", CHARSET)
 SMB_MODULE(charset_CP850, modules/CP850.o, "bin/CP850.$SHLIBEXT", CHARSET)
 SMB_MODULE(charset_CP437, modules/CP437.o, "bin/CP437.$SHLIBEXT", CHARSET)

=== modified file 'source/include/ads.h'
--- source/include/ads.h	2007-01-17 23:11:59 +0000
+++ source/include/ads.h	2007-01-24 01:28:38 +0000
@@ -57,19 +57,20 @@
 		time_t current_time;
 		int tried_closest_dc;
 	} config;
-
-	/* info derived from the servers schema */
-	struct {
-		enum wb_posix_mapping map_type;
-		char *posix_homedir_attr;
-		char *posix_shell_attr;
-		char *posix_uidnumber_attr;
-		char *posix_gidnumber_attr;
-		char *posix_gecos_attr;
-	} schema;
-
 } ADS_STRUCT;
 
+/* used to remember the names of the posix attributes in AD */
+/* see the rfc2307 & sfu nss backends */
+
+struct posix_schema {
+	char *posix_homedir_attr;
+	char *posix_shell_attr;
+	char *posix_uidnumber_attr;
+	char *posix_gidnumber_attr;
+	char *posix_gecos_attr;
+};
+
+
 /* there are 5 possible types of errors the ads subsystem can produce */
 enum ads_error_type {ENUM_ADS_ERROR_KRB5, ENUM_ADS_ERROR_GSS, 
 		     ENUM_ADS_ERROR_LDAP, ENUM_ADS_ERROR_SYSTEM, ENUM_ADS_ERROR_NT};

=== modified file 'source/include/includes.h'
--- source/include/includes.h	2007-01-03 13:15:27 +0000
+++ source/include/includes.h	2007-01-24 01:28:38 +0000
@@ -768,6 +768,8 @@
     /* NUM_FLUSH_REASONS must remain the last value in the enumeration. */
     NUM_FLUSH_REASONS};
 
+#include "nss_info.h"
+
 /***** automatically generated prototypes *****/
 #ifndef NO_PROTO_H
 #include "proto.h"

=== modified file 'source/libads/ads_struct.c'
--- source/libads/ads_struct.c	2006-12-15 00:15:57 +0000
+++ source/libads/ads_struct.c	2007-01-24 01:28:38 +0000
@@ -161,12 +161,6 @@
 		SAFE_FREE((*ads)->config.server_site_name);
 		SAFE_FREE((*ads)->config.client_site_name);
 		
-		SAFE_FREE((*ads)->schema.posix_uidnumber_attr);
-		SAFE_FREE((*ads)->schema.posix_gidnumber_attr);
-		SAFE_FREE((*ads)->schema.posix_shell_attr);
-		SAFE_FREE((*ads)->schema.posix_homedir_attr);
-		SAFE_FREE((*ads)->schema.posix_gecos_attr);
-		
 		ZERO_STRUCTP(*ads);
 
 		if ( is_mine )

=== modified file 'source/libads/ldap_schema.c'
--- source/libads/ldap_schema.c	2006-09-20 01:19:51 +0000
+++ source/libads/ldap_schema.c	2007-01-24 01:28:38 +0000
@@ -186,7 +186,10 @@
  * @return ADS_STATUS status of search (False if one or more attributes couldn't be
  * found in Active Directory)
  **/ 
-ADS_STATUS ads_check_posix_schema_mapping(ADS_STRUCT *ads, enum wb_posix_mapping map_type) 
+ADS_STATUS ads_check_posix_schema_mapping(TALLOC_CTX *mem_ctx,
+					  ADS_STRUCT *ads,
+					  enum wb_posix_mapping map_type,
+					  struct posix_schema **s ) 
 {
 	TALLOC_CTX *ctx = NULL; 
 	ADS_STATUS status;
@@ -194,6 +197,7 @@
 	size_t num_names;
 	char *schema_path = NULL;
 	int i;
+	struct posix_schema *schema = NULL;
 
 	const char *oids_sfu[] = { 	ADS_ATTR_SFU_UIDNUMBER_OID,
 					ADS_ATTR_SFU_GIDNUMBER_OID,
@@ -209,34 +213,15 @@
 
 	DEBUG(10,("ads_check_posix_schema_mapping\n"));
 
-	switch (map_type) {
+	if ( (ctx = talloc_init("ads_check_posix_schema_mapping")) == NULL ) {
+		return ADS_ERROR(LDAP_NO_MEMORY);
+	}
+
+	if ( (schema = TALLOC_P(mem_ctx, struct posix_schema)) == NULL ) {
+		TALLOC_FREE( ctx );
+		return ADS_ERROR(LDAP_NO_MEMORY);
+	}
 	
-		case WB_POSIX_MAP_TEMPLATE:
-		case WB_POSIX_MAP_UNIXINFO:
-			DEBUG(10,("ads_check_posix_schema_mapping: nothing to do\n"));
-			return ADS_ERROR(LDAP_SUCCESS);
-
-		case WB_POSIX_MAP_SFU:
-		case WB_POSIX_MAP_RFC2307:
-			break;
-
-		default:
-			DEBUG(0,("ads_check_posix_schema_mapping: "
-				 "unknown enum %d\n", map_type));
-			return ADS_ERROR(LDAP_PARAM_ERROR);
-	}
-
-	ads->schema.posix_uidnumber_attr = NULL;
-	ads->schema.posix_gidnumber_attr = NULL;
-	ads->schema.posix_homedir_attr = NULL;
-	ads->schema.posix_shell_attr = NULL;
-	ads->schema.posix_gecos_attr = NULL;
-
-	ctx = talloc_init("ads_check_posix_schema_mapping");
-	if (ctx == NULL) {
-		return ADS_ERROR(LDAP_NO_MEMORY);
-	}
-
 	status = ads_schema_path(ads, ctx, &schema_path);
 	if (!ADS_ERR_OK(status)) {
 		DEBUG(3,("ads_check_posix_mapping: Unable to retrieve schema DN!\n"));
@@ -257,10 +242,7 @@
 		DEBUG(3,("ads_check_posix_schema_mapping: failed %s\n", 
 			ads_errstr(status)));
 		goto done;
-	} 
-	
-	DEBUG(10,("ads_check_posix_schema_mapping: query succeeded, identified: %s\n",
-		wb_posix_map_str(map_type)));
+	}
 
 	for (i=0; i<num_names; i++) {
 
@@ -268,43 +250,48 @@
 
 		if (strequal(ADS_ATTR_RFC2307_UIDNUMBER_OID, oids_out[i]) ||
 		    strequal(ADS_ATTR_SFU_UIDNUMBER_OID, oids_out[i])) {
-			SAFE_FREE(ads->schema.posix_uidnumber_attr);
-			ads->schema.posix_uidnumber_attr = SMB_STRDUP(names_out[i]);
+			schema->posix_uidnumber_attr = talloc_strdup(schema, names_out[i]);
+			continue;		       
 		}
+
 		if (strequal(ADS_ATTR_RFC2307_GIDNUMBER_OID, oids_out[i]) ||
 		    strequal(ADS_ATTR_SFU_GIDNUMBER_OID, oids_out[i])) {
-			SAFE_FREE(ads->schema.posix_gidnumber_attr);
-			ads->schema.posix_gidnumber_attr = SMB_STRDUP(names_out[i]);
+			schema->posix_gidnumber_attr = talloc_strdup(schema, names_out[i]);
+			continue;		
 		}
+
 		if (strequal(ADS_ATTR_RFC2307_HOMEDIR_OID, oids_out[i]) ||
 		    strequal(ADS_ATTR_SFU_HOMEDIR_OID, oids_out[i])) {
-			SAFE_FREE(ads->schema.posix_homedir_attr);
-			ads->schema.posix_homedir_attr = SMB_STRDUP(names_out[i]);
+			schema->posix_homedir_attr = talloc_strdup(schema, names_out[i]);
+			continue;			
 		}
+
 		if (strequal(ADS_ATTR_RFC2307_SHELL_OID, oids_out[i]) ||
 		    strequal(ADS_ATTR_SFU_SHELL_OID, oids_out[i])) {
-			SAFE_FREE(ads->schema.posix_shell_attr);
-			ads->schema.posix_shell_attr = SMB_STRDUP(names_out[i]);
+			schema->posix_shell_attr = talloc_strdup(schema, names_out[i]);
+			continue;			
 		}
+
 		if (strequal(ADS_ATTR_RFC2307_GECOS_OID, oids_out[i]) ||
 		    strequal(ADS_ATTR_SFU_GECOS_OID, oids_out[i])) {
-			SAFE_FREE(ads->schema.posix_gecos_attr);
-			ads->schema.posix_gecos_attr = SMB_STRDUP(names_out[i]);
+			schema->posix_gecos_attr = talloc_strdup(schema, names_out[i]);
 		}
 	}
 
-	if (!ads->schema.posix_uidnumber_attr ||
-	    !ads->schema.posix_gidnumber_attr ||
-	    !ads->schema.posix_homedir_attr ||
-	    !ads->schema.posix_shell_attr ||
-	    !ads->schema.posix_gecos_attr) {
+	if (!schema->posix_uidnumber_attr ||
+	    !schema->posix_gidnumber_attr ||
+	    !schema->posix_homedir_attr ||
+	    !schema->posix_shell_attr ||
+	    !schema->posix_gecos_attr) {
 	    	status = ADS_ERROR(LDAP_NO_MEMORY);
+	        TALLOC_FREE( schema );		
 	    	goto done;
 	}
+
+	*s = schema;
 	
 	status = ADS_ERROR(LDAP_SUCCESS);
 	
-	ads->schema.map_type = map_type;
 done:
 	if (ctx) {
 		talloc_destroy(ctx);

=== modified file 'source/nsswitch/idmap_ad.c'
--- source/nsswitch/idmap_ad.c	2007-01-14 23:21:02 +0000
+++ source/nsswitch/idmap_ad.c	2007-01-24 01:28:38 +0000
@@ -7,7 +7,7 @@
  *
  * Copyright (C) Andrew Tridgell 2001
  * Copyright (C) Andrew Bartlett <abartlet at samba.org> 2003
- * Copyright (C) Gerald (Jerry) Carter 2004
+ * Copyright (C) Gerald (Jerry) Carter 2004-2007
  * Copyright (C) Luke Howard 2001-2004
  *
  * This program is free software; you can redistribute it and/or modify
@@ -32,56 +32,36 @@
 
 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
 
+#define IDMAP_AD_MAX_IDS 30
+#define CHECK_ALLOC_DONE(mem) do { \
+     if (!mem) { \
+           DEBUG(0, ("Out of memory!\n")); \
+           ret = NT_STATUS_NO_MEMORY; \
+           goto done; \
+      } \
+} while (0)
+
+struct idmap_ad_context {
+	uint32_t filter_low_id;
+	uint32_t filter_high_id;
+};
+
 NTSTATUS init_module(void);
 
 static ADS_STRUCT *ad_idmap_ads = NULL;
-
-static char *attr_uidnumber = NULL;
-static char *attr_gidnumber = NULL;
-
-static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
-{
-	ADS_STATUS status;
-	enum wb_posix_mapping map_type;
-
-	if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
-		return ADS_ERROR(LDAP_SUCCESS);
-	}
-
-	SMB_ASSERT(ads->server.workgroup);
-
-	map_type = get_nss_info(ads->server.workgroup);
-
-	if ((map_type == WB_POSIX_MAP_SFU) ||
-	    (map_type == WB_POSIX_MAP_RFC2307)) {
-
-		status = ads_check_posix_schema_mapping(ads, map_type);
-		if (ADS_ERR_OK(status)) {
-			attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr);
-			attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr);
-			ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
-			ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
-			return ADS_ERROR(LDAP_SUCCESS);
-		} else {
-			DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status)));
-			/* return status; */
-		}
-	}
-	
-	/* fallback to XAD defaults */
-	attr_uidnumber = SMB_STRDUP("uidNumber");
-	attr_gidnumber = SMB_STRDUP("gidNumber");
-	ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
-	ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
-
-	return ADS_ERROR(LDAP_SUCCESS);
-}
-
-static ADS_STRUCT *ad_idmap_cached_connection(void)
+static struct posix_schema *ad_schema = NULL;
+static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN;
+
+/************************************************************************
+ ***********************************************************************/
+
+static ADS_STRUCT *ad_idmap_cached_connection_internal(void)
 {
 	ADS_STRUCT *ads;
 	ADS_STATUS status;
 	BOOL local = False;
+	fstring dc_name;
+	struct in_addr dc_ip;	
 
 	if (ad_idmap_ads != NULL) {
 		ads = ad_idmap_ads;
@@ -98,6 +78,7 @@
 			ads_destroy( &ads );
 			ads_kdestroy(WINBIND_CCACHE_NAME);
 			ad_idmap_ads = NULL;
+			TALLOC_FREE( ad_schema );			
 		}
 	}
 
@@ -106,8 +87,7 @@
 		setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);
 	}
 
-	ads = ads_init(lp_realm(), lp_workgroup(), NULL);
-	if (!ads) {
+	if ( (ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL ) {
 		DEBUG(1,("ads_init failed\n"));
 		return NULL;
 	}
@@ -119,6 +99,10 @@
 	SAFE_FREE(ads->auth.realm);
 	ads->auth.realm = SMB_STRDUP(lp_realm());
 
+	/* setup server affinity */
+
+	get_dc_name( NULL, ads->auth.realm, dc_name, &dc_ip );
+	
 	status = ads_connect(ads);
 	if (!ADS_ERR_OK(status)) {
 		DEBUG(1, ("ad_idmap_init: failed to connect to AD\n"));
@@ -128,21 +112,47 @@
 
 	ads->is_mine = False;
 
-	status = ad_idmap_check_attr_mapping(ads);
-	if (!ADS_ERR_OK(status)) {
-		DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n"));
-		return NULL;
-	}
-
 	ad_idmap_ads = ads;
-	return ads;
-}
-
-struct idmap_ad_context {
-	uint32_t filter_low_id, filter_high_id;		/* Filter range */
-};
-
-/* Initialize and check conf is appropriate */
+
+	return ads;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static ADS_STRUCT *ad_idmap_cached_connection(void)
+{
+	ADS_STRUCT *ads = ad_idmap_cached_connection_internal();
+	
+	if ( !ads )
+		return NULL;
+
+	/* if we have a valid ADS_STRUCT and the schema model is
+	   defined, then we can return here. */
+
+	if ( ad_schema )
+		return ads;
+
+	/* Otherwise, set the schema model */
+
+	if ( (ad_map_type ==  WB_POSIX_MAP_SFU) ||
+	     (ad_map_type ==  WB_POSIX_MAP_RFC2307) ) 
+	{
+		ADS_STATUS schema_status;
+		
+		schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema);
+		if ( !ADS_ERR_OK(schema_status) ) {
+			DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
+			return NULL;			
+		}
+	}
+	
+	return ads;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
 {
 	struct idmap_ad_context *ctx;
@@ -151,19 +161,16 @@
 	ADS_STRUCT *ads;
 
 	/* verify AD is reachable (not critical, we may just be offline at start) */
-	ads = ad_idmap_cached_connection();
-	if (ads == NULL) {
+	if ( (ads = ad_idmap_cached_connection()) == NULL ) {
 		DEBUG(1, ("WARNING: Could not init an AD connection! Mapping might not work.\n"));
 	}
 
-	ctx = talloc_zero(dom, struct idmap_ad_context);
-	if ( ! ctx) {
+	if ( (ctx = talloc_zero(dom, struct idmap_ad_context)) == NULL ) {
 		DEBUG(0, ("Out of memory!\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
-	if ( ! config_option) {
+	if ( (config_option = talloc_asprintf(ctx, "idmap config %s", dom->name)) == NULL ) {
 		DEBUG(0, ("Out of memory!\n"));
 		talloc_free(ctx);
 		return NT_STATUS_NO_MEMORY;
@@ -194,29 +201,28 @@
 			  "NOTE: make sure the ranges do not overlap\n",
 			  dom->name, dom->name, dom->name, dom->name));
 	}
-	if ( ! dom->readonly) {
+
+	if ( !dom->readonly ) {
 		DEBUG(1, ("WARNING: forcing to readonly, as idmap_ad can't write on AD.\n"));
-		dom->readonly = true; /* force readonly */
+		dom->readonly = true;
 	}
 
 	dom->private_data = ctx;
 
 	talloc_free(config_option);
+
 	return NT_STATUS_OK;
 }
 
-#define IDMAP_AD_MAX_IDS 30
-#define CHECK_ALLOC_DONE(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while (0)
+/************************************************************************
+ Search up to IDMAP_AD_MAX_IDS entries in maps for a match.
+ ***********************************************************************/
 
-/* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
 static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id)
 {
 	int i;
 
-	for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
-		if (maps[i] == NULL) { /* end of the run */
-			return NULL;
-		}
+	for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
 		if ((maps[i]->xid.type == type) && (maps[i]->xid.id == id)) {
 			return maps[i];
 		}
@@ -225,6 +231,26 @@
 	return NULL;	
 }
 
+/************************************************************************
+ Search up to IDMAP_AD_MAX_IDS entries in maps for a match
+ ***********************************************************************/
+
+static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
+{
+	int i;
+
+	for (i = 0; maps[i] && i<IDMAP_AD_MAX_IDS; i++) {
+		if (sid_equal(maps[i]->sid, sid)) {
+			return maps[i];
+		}
+	}
+
+	return NULL;	
+}
+
+/************************************************************************
+ ***********************************************************************/
+
 static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
 {
 	NTSTATUS ret;
@@ -234,132 +260,89 @@
 	ADS_STRUCT *ads;
 	const char *attrs[] = { "sAMAccountType", 
 				"objectSid",
-				NULL, /* attr_uidnumber */
-				NULL, /* attr_gidnumber */
+				NULL, /* uidnumber */
+				NULL, /* gidnumber */
 				NULL };
 	LDAPMessage *res = NULL;
 	char *filter = NULL;
-	BOOL multi = False;
 	int idx = 0;
 	int bidx = 0;
 	int count;
 	int i;
-
-	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);	
-
-	memctx = talloc_new(ctx);
-	if ( ! memctx) {
+	char *u_filter = NULL;
+	char *g_filter = NULL;
+
+	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
+
+	if ( (memctx = talloc_new(ctx)) == NULL ) {
 		DEBUG(0, ("Out of memory!\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	ads = ad_idmap_cached_connection();
-	if (ads == NULL) {
+	if ( (ads = ad_idmap_cached_connection()) == NULL ) {
 		DEBUG(1, ("ADS uninitialized\n"));
 		ret = NT_STATUS_UNSUCCESSFUL;
 		goto done;
 	}
 
-	/* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
-	attrs[2] = attr_uidnumber;
-	attrs[3] = attr_gidnumber;
-
-	if ( ! ids[1]) {
-		/* if we are requested just one mapping use the simple filter */
-		switch (ids[0]->xid.type) {
-		case ID_TYPE_UID:
-
-			filter = talloc_asprintf(memctx,
-				"(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
-				ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
-				attr_uidnumber,
-				(unsigned long)ids[0]->xid.id);
+	attrs[2] = ad_schema->posix_uidnumber_attr;
+	attrs[3] = ad_schema->posix_gidnumber_attr;
+
+again:
+	bidx = idx;
+	for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+		switch (ids[idx]->xid.type) {
+		case ID_TYPE_UID:     
+			if ( ! u_filter) {
+				u_filter = talloc_asprintf(memctx, "(&(|"
+							   "(sAMAccountType=%d)"
+							   "(sAMAccountType=%d)"
+							   "(sAMAccountType=%d))(|",
+							   ATYPE_NORMAL_ACCOUNT,
+							   ATYPE_WORKSTATION_TRUST,
+							   ATYPE_INTERDOMAIN_TRUST);
+			}
+			u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
+							  ad_schema->posix_uidnumber_attr,
+							  (unsigned long)ids[idx]->xid.id);
+			CHECK_ALLOC_DONE(u_filter);
 			break;
+				
 		case ID_TYPE_GID:
+			if ( ! g_filter) {
+				g_filter = talloc_asprintf(memctx, "(&(|"
+							   "(sAMAccountType=%d)"
+							   "(sAMAccountType=%d))(|",
+							   ATYPE_SECURITY_GLOBAL_GROUP,
+							   ATYPE_SECURITY_LOCAL_GROUP);
+			}
+			g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
+							  ad_schema->posix_gidnumber_attr,
+							  (unsigned long)ids[idx]->xid.id);
+			CHECK_ALLOC_DONE(g_filter);
+			break;
 
-			filter = talloc_asprintf(memctx,
-				"(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))",
-				ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP,
-				attr_gidnumber,
-				(unsigned long)ids[0]->xid.id);
-			break;
 		default:
 			DEBUG(3, ("Unknown ID type\n"));
-			ret = NT_STATUS_INVALID_PARAMETER;
-			goto done;
+			ids[idx]->status = ID_UNKNOWN;
+			continue;
 		}
-		CHECK_ALLOC_DONE(filter);
-		DEBUG(10, ("Filter: [%s]\n", filter));
-	} else {
-		/* multiple mappings */
-		multi = True;
 	}
-
-again:
-	if (multi) {
-		char *u_filter = NULL;
-		char *g_filter = NULL;
-
-		bidx = idx;
-		for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
-			switch (ids[idx]->xid.type) {
-			case ID_TYPE_UID:
-	
-				if ( ! u_filter) {
-					u_filter = talloc_asprintf(memctx, "(&(|"
-						"(sAMAccountType=%d)"
-						"(sAMAccountType=%d)"
-						"(sAMAccountType=%d))(|",
-						ATYPE_NORMAL_ACCOUNT,
-						ATYPE_WORKSTATION_TRUST,
-						ATYPE_INTERDOMAIN_TRUST);
-				}
-				u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
-					attr_uidnumber,
-					(unsigned long)ids[idx]->xid.id);
-				CHECK_ALLOC_DONE(u_filter);
-				break;
-				
-			case ID_TYPE_GID:
-				if ( ! g_filter) {
-					g_filter = talloc_asprintf(memctx, "(&(|"
-						"(sAMAccountType=%d)"
-						"(sAMAccountType=%d))(|",
-						ATYPE_SECURITY_GLOBAL_GROUP,
-						ATYPE_SECURITY_LOCAL_GROUP);
-				}
-				g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
-					attr_gidnumber,
-					(unsigned long)ids[idx]->xid.id);
-				CHECK_ALLOC_DONE(g_filter);
-				break;
-
-			default:
-				DEBUG(3, ("Unknown ID type\n"));
-				ids[idx]->status = ID_UNKNOWN;
-				continue;
-			}
-		}
-		filter = talloc_asprintf(memctx, "(|");
+	filter = talloc_asprintf(memctx, "(|");
+	CHECK_ALLOC_DONE(filter);
+	if ( u_filter) {
+		filter = talloc_asprintf_append(filter, "%s))", u_filter);
 		CHECK_ALLOC_DONE(filter);
-		if ( u_filter) {
-			filter = talloc_asprintf_append(filter, "%s))", u_filter);
-			CHECK_ALLOC_DONE(filter);
 			TALLOC_FREE(u_filter);
-		}
-		if ( g_filter) {
-			filter = talloc_asprintf_append(filter, "%s))", g_filter);
-			CHECK_ALLOC_DONE(filter);
-			TALLOC_FREE(g_filter);
-		}
-		filter = talloc_asprintf_append(filter, ")");
+	}
+	if ( g_filter) {
+		filter = talloc_asprintf_append(filter, "%s))", g_filter);
 		CHECK_ALLOC_DONE(filter);
-		DEBUG(10, ("Filter: [%s]\n", filter));
-	} else {
-		bidx = 0;
-		idx = 1;
+		TALLOC_FREE(g_filter);
 	}
-
+	filter = talloc_asprintf_append(filter, ")");
+	CHECK_ALLOC_DONE(filter);
+	DEBUG(10, ("Filter: [%s]\n", filter));
 	rc = ads_search_retry(ads, &res, filter, attrs);
 	if (!ADS_ERR_OK(rc)) {
 		DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
@@ -367,8 +350,7 @@
 		goto done;
 	}
 
-	count = ads_count_replies(ads, res);
-	if (count == 0) {
+	if ( (count = ads_count_replies(ads, res)) == 0 ) {
 		DEBUG(10, ("No IDs found\n"));
 	}
 
@@ -417,10 +399,15 @@
 			continue;
 		}
 
-		if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
+		if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
+				                 ad_schema->posix_uidnumber_attr : 
+				                 ad_schema->posix_gidnumber_attr, 
+				     &id)) 
+		{
 			DEBUG(1, ("Could not get unix ID\n"));
 			continue;
 		}
+
 		if ((id == 0) ||
 		    (ctx->filter_low_id && (id < ctx->filter_low_id)) ||
 		    (ctx->filter_high_id && (id > ctx->filter_high_id))) {
@@ -450,15 +437,16 @@
 		ads_msgfree(ads, res);
 	}
 
-	if (multi && ids[idx]) { /* still some values to map */
+	if (ids[idx]) { /* still some values to map */
 		goto again;
 	}
 
 	ret = NT_STATUS_OK;
 
-	/* mark all unknwon ones as unmapped */
+	/* mark all unknown ones as unmapped */
 	for (i = 0; ids[i]; i++) {
-		if (ids[i]->status == ID_UNKNOWN) ids[i]->status = ID_UNMAPPED;
+		if (ids[i]->status == ID_UNKNOWN) 
+			ids[i]->status = ID_UNMAPPED;
 	}
 
 done:
@@ -466,22 +454,8 @@
 	return ret;
 }
 
-/* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */
-static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid)
-{
-	int i;
-
-	for (i = 0; i < IDMAP_AD_MAX_IDS; i++) {
-		if (maps[i] == NULL) { /* end of the run */
-			return NULL;
-		}
-		if (sid_equal(maps[i]->sid, sid)) {
-			return maps[i];
-		}
-	}
-
-	return NULL;	
-}
+/************************************************************************
+ ***********************************************************************/
 
 static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
 {
@@ -497,85 +471,50 @@
 				NULL };
 	LDAPMessage *res = NULL;
 	char *filter = NULL;
-	BOOL multi = False;
 	int idx = 0;
 	int bidx = 0;
 	int count;
 	int i;
+	char *sidstr;
 
 	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);	
 
-	memctx = talloc_new(ctx);
-	if ( ! memctx) {
+	if ( (memctx = talloc_new(ctx)) == NULL ) {		
 		DEBUG(0, ("Out of memory!\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	ads = ad_idmap_cached_connection();
-	if (ads == NULL) {
+	if ( (ads = ad_idmap_cached_connection()) == NULL ) {
 		DEBUG(1, ("ADS uninitialized\n"));
 		ret = NT_STATUS_UNSUCCESSFUL;
 		goto done;
 	}
 
-	/* attr_uidnumber and attr_gidnumber are surely successfully initialized now */
-	attrs[2] = attr_uidnumber;
-	attrs[3] = attr_gidnumber;
-
-
-	if ( ! ids[1]) {
-		/* if we are requested just one mapping use the simple filter */
-		char *sidstr;
-
-		sidstr = sid_binstring(ids[0]->sid);
-		filter = talloc_asprintf(memctx, "(&(objectSid=%s)(|" /* the requested Sid */
-						 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
-						 "(sAMAccountType=%d)(sAMAccountType=%d)))", /* group account types */
-						 sidstr,
-						 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
-						 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
-		if (! filter) {
-			free(sidstr);
-			ret = NT_STATUS_NO_MEMORY;
-			goto done;
-		}
-		CHECK_ALLOC_DONE(filter);
-		DEBUG(10, ("Filter: [%s]\n", filter));
-	} else {
-		/* multiple mappings */
-		multi = True;
-	}
+	attrs[2] = ad_schema->posix_uidnumber_attr;
+	attrs[3] = ad_schema->posix_gidnumber_attr;
 
 again:
-	if (multi) {
-		char *sidstr;
-
-		filter = talloc_asprintf(memctx,
-				"(&(|"
-				    "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
-				    "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
-				  ")(|",
-					ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
-					ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
+	filter = talloc_asprintf(memctx, "(&(|"
+				 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
+				 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
+				 ")(|",
+				 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
+				 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
 		
-		CHECK_ALLOC_DONE(filter);
-
-		bidx = idx;
-		for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
-
-			sidstr = sid_binstring(ids[idx]->sid);
-			filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
+	CHECK_ALLOC_DONE(filter);
+
+	bidx = idx;
+	for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+
+		sidstr = sid_binstring(ids[idx]->sid);
+		filter = talloc_asprintf_append(filter, "(objectSid=%s)", sidstr);
 			
-			free(sidstr);
-			CHECK_ALLOC_DONE(filter);
-		}
-		filter = talloc_asprintf_append(filter, "))");
+		free(sidstr);
 		CHECK_ALLOC_DONE(filter);
-		DEBUG(10, ("Filter: [%s]\n", filter));
-	} else {
-		bidx = 0;
-		idx = 1;
 	}
+	filter = talloc_asprintf_append(filter, "))");
+	CHECK_ALLOC_DONE(filter);
+	DEBUG(10, ("Filter: [%s]\n", filter));
 
 	rc = ads_search_retry(ads, &res, filter, attrs);
 	if (!ADS_ERR_OK(rc)) {
@@ -584,8 +523,7 @@
 		goto done;
 	}
 
-	count = ads_count_replies(ads, res);
-	if (count == 0) {
+	if ( (count = ads_count_replies(ads, res)) == 0 ) {
 		DEBUG(10, ("No IDs found\n"));
 	}
 
@@ -640,7 +578,11 @@
 			continue;
 		}
 
-		if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID)?attr_uidnumber:attr_gidnumber, &id)) {
+		if (!ads_pull_uint32(ads, entry, (type==ID_TYPE_UID) ? 
+				                 ad_schema->posix_uidnumber_attr : 
+				                 ad_schema->posix_gidnumber_attr, 
+				     &id)) 
+		{
 			DEBUG(1, ("Could not get unix ID\n"));
 			continue;
 		}
@@ -667,7 +609,7 @@
 		ads_msgfree(ads, res);
 	}
 
-	if (multi && ids[idx]) { /* still some values to map */
+	if (ids[idx]) { /* still some values to map */
 		goto again;
 	}
 
@@ -675,7 +617,8 @@
 
 	/* mark all unknwon ones as unmapped */
 	for (i = 0; ids[i]; i++) {
-		if (ids[i]->status == ID_UNKNOWN) ids[i]->status = ID_UNMAPPED;
+		if (ids[i]->status == ID_UNKNOWN) 
+			ids[i]->status = ID_UNMAPPED;
 	}
 
 done:
@@ -683,6 +626,9 @@
 	return ret;
 }
 
+/************************************************************************
+ ***********************************************************************/
+
 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
 {
 	ADS_STRUCT *ads = ad_idmap_ads;
@@ -694,22 +640,176 @@
 		ad_idmap_ads = NULL;
 	}
 
-	SAFE_FREE(attr_uidnumber);
-	SAFE_FREE(attr_gidnumber);
-	
-	return NT_STATUS_OK;
-}
+	TALLOC_FREE( ad_schema );
+	
+	return NT_STATUS_OK;
+}
+
+/*
+ * nss_info_{sfu,rfc2307}
+ */
+
+/************************************************************************
+ Initialize the {sfu,rfc2307} state
+ ***********************************************************************/
+
+static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
+{
+	/* Sanity check if we have previously been called with a
+	   different schema model */
+
+	if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
+	     (ad_map_type != WB_POSIX_MAP_SFU) ) 
+	{
+		DEBUG(0,("nss_sfu_init: Posix Map type has already been set.  "
+			 "Mixed schema models not supported!\n"));
+		return NT_STATUS_NOT_SUPPORTED;
+	}
+	
+	ad_map_type =  WB_POSIX_MAP_SFU;	
+
+	if ( !ad_idmap_ads ) 
+		return idmap_ad_initialize( NULL, NULL );	
+
+	return NT_STATUS_OK;
+}
+
+static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
+{
+	/* Sanity check if we have previously been called with a
+	   different schema model */
+	 
+	if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
+	     (ad_map_type != WB_POSIX_MAP_RFC2307) ) 
+	{
+		DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set.  "
+			 "Mixed schema models not supported!\n"));
+		return NT_STATUS_NOT_SUPPORTED;
+	}
+	
+	ad_map_type =  WB_POSIX_MAP_RFC2307;
+
+	if ( !ad_idmap_ads ) 
+		return idmap_ad_initialize( NULL, NULL );	
+
+	return NT_STATUS_OK;
+}
+
+
+/************************************************************************
+ ***********************************************************************/
+static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, 
+				  const DOM_SID *sid, 
+				  TALLOC_CTX *ctx,
+				  ADS_STRUCT *ads, 
+				  LDAPMessage *msg,
+				  char **homedir,
+				  char **shell, 
+				  char **gecos,
+				  uint32 *gid )
+{
+	char *home, *sh, *gec;
+
+	if ( !ad_schema )
+		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+	
+	if ( !homedir || !shell || !gecos )
+		return NT_STATUS_INVALID_PARAMETER;
+
+	home = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr );
+	sh   = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr );
+	gec  = ads_pull_string( ads, ctx, msg, ad_schema->posix_gecos_attr );
+       
+	if ( gid ) {		
+		if ( !ads_pull_uint32(ads, msg, ad_schema->posix_gidnumber_attr, gid ) )
+			*gid = 0;		
+	}
+		
+	if ( home )
+		*homedir = talloc_strdup( ctx, home );
+	if ( sh )
+		*shell   = talloc_strdup( ctx, sh );
+	if ( gec )
+		*gecos   = talloc_strdup( ctx, gec );
+	
+	SAFE_FREE( home );
+	SAFE_FREE( sh );
+	SAFE_FREE( gec );
+	
+	return NT_STATUS_OK;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS nss_ad_close( void )
+{
+	/* nothing to do.  All memory is free()'d by the idmap close_fn() */
+
+	return NT_STATUS_OK;
+}
+
+/************************************************************************
+ Function dispatch tables for the idmap and nss plugins
+ ***********************************************************************/
 
 static struct idmap_methods ad_methods = {
-	.init = idmap_ad_initialize,
+	.init            = idmap_ad_initialize,
 	.unixids_to_sids = idmap_ad_unixids_to_sids,
 	.sids_to_unixids = idmap_ad_sids_to_unixids,
-	.close_fn = idmap_ad_close
-};
-
-/* support for new authentication subsystem */
+	.close_fn        = idmap_ad_close
+};
+
+/* The SFU and RFC2307 NSS plugins share everything but the init
+   function which sets the intended schema model to use */
+  
+static struct nss_info_methods nss_rfc2307_methods = {
+	.init         = nss_rfc2307_init,
+	.get_nss_info =	nss_ad_get_info,
+	.close_fn     = nss_ad_close
+};
+
+static struct nss_info_methods nss_sfu_methods = {
+	.init         = nss_sfu_init,
+	.get_nss_info =	nss_ad_get_info,
+	.close_fn     = nss_ad_close
+};
+
+
+/************************************************************************
+ Initialize the plugins
+ ***********************************************************************/
+
 NTSTATUS idmap_ad_init(void)
 {
-	return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);
+	static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
+	static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL;
+	static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL;
+
+	/* Always register the AD method first in order to get the
+	   idmap_domain interface called */
+
+	if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
+		status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
+						     "ad", &ad_methods);
+		if ( !NT_STATUS_IS_OK(status_idmap_ad) )
+			return status_idmap_ad;		
+	}
+	
+	if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) {
+		status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+							    "rfc2307",  &nss_rfc2307_methods );		
+		if ( !NT_STATUS_IS_OK(status_nss_rfc2307) )
+			return status_nss_rfc2307;
+	}
+
+	if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) {
+		status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
+							"sfu",  &nss_sfu_methods );		
+		if ( !NT_STATUS_IS_OK(status_nss_sfu) )
+			return status_nss_sfu;		
+	}
+
+	return NT_STATUS_OK;	
 }
 

=== modified file 'source/nsswitch/nss_info.c'
--- source/nsswitch/nss_info.c	2006-12-12 15:28:10 +0000
+++ source/nsswitch/nss_info.c	2007-01-24 01:28:38 +0000
@@ -1,111 +1,305 @@
 /* 
    Unix SMB/CIFS implementation.
-   nss info helpers
-   Copyright (C) Guenther Deschner 2006
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
+   Idmap NSS headers
+
+   Copyright (C) Gerald Carter             2006
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+   
+   This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+   
+   You should have received a copy of the GNU Library General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA  02111-1307, USA.   
+*/
 
 #include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_IDMAP
-
-static enum wb_posix_mapping wb_posix_map_type(const char *map_str)
-{
-	if (strequal(map_str, "template")) 
-		return WB_POSIX_MAP_TEMPLATE;
-	else if (strequal(map_str, "sfu"))
-		return WB_POSIX_MAP_SFU;
-	else if (strequal(map_str, "rfc2307"))
-		return WB_POSIX_MAP_RFC2307;
-	else if (strequal(map_str, "unixinfo"))
-		return WB_POSIX_MAP_UNIXINFO;
-	
-	return WB_POSIX_MAP_UNKNOWN;
-}
-
-/* winbind nss info = rfc2307 SO36:sfu FHAIN:rfc2307 PANKOW:template
- *
- * syntax is:
- *	1st param: default setting
- *	following ":" separated list elements:
- *		DOMAIN:setting
- *	setting can be one of "sfu", "rfc2307", "template", "unixinfo"
- */
-
-enum wb_posix_mapping get_nss_info(const char *domain_name)
-{
-	const char **list = lp_winbind_nss_info();
-	enum wb_posix_mapping map_templ = WB_POSIX_MAP_TEMPLATE;
-	int i;
-
-	DEBUG(11,("get_nss_info for %s\n", domain_name));
-
-	if (!lp_winbind_nss_info() || !*lp_winbind_nss_info()) {
-		return WB_POSIX_MAP_TEMPLATE;
-	}
-
-	if ((map_templ = wb_posix_map_type(list[0])) == WB_POSIX_MAP_UNKNOWN) {
-		DEBUG(0,("get_nss_info: invalid setting: %s\n", list[0]));
-		return WB_POSIX_MAP_TEMPLATE;
-	}
-
-	DEBUG(11,("get_nss_info: using \"%s\" by default\n", list[0]));
-
-	for (i=0; list[i]; i++) {
-
-		const char *p = list[i];
-		fstring tok;
-
-		if (!next_token(&p, tok, ":", sizeof(tok))) {
-			DEBUG(0,("get_nss_info: no \":\" delimitier found\n"));
-			continue;
-		}
-
-		if (strequal(tok, domain_name)) {
-		
-			enum wb_posix_mapping type;
-			
-			if ((type = wb_posix_map_type(p)) == WB_POSIX_MAP_UNKNOWN) {
-				DEBUG(0,("get_nss_info: invalid setting: %s\n", p));
-				/* return WB_POSIX_MAP_TEMPLATE; */
-				continue;
-			}
-
-			DEBUG(11,("get_nss_info: using \"%s\" for domain: %s\n", p, tok));
-			
-			return type;
-		}
-	}
-
-	return map_templ;
-}
+#include "nss_info.h"
+
+static struct nss_function_entry *backends = NULL;
+static struct nss_domain_entry *nss_domain_list = NULL;
+
+/**********************************************************************
+ **********************************************************************/
 
 const char *wb_posix_map_str(enum wb_posix_mapping mtype)
 {
 	switch (mtype) {
-		case WB_POSIX_MAP_TEMPLATE:
-			return "template";
 		case WB_POSIX_MAP_SFU:
 			return "sfu";
 		case WB_POSIX_MAP_RFC2307:
 			return "rfc2307";
-		case WB_POSIX_MAP_UNIXINFO:
-			return "unixinfo";
 		default:
 			break;
 	}
 	return NULL;
 }
+
+
+/**********************************************************************
+ Get idmap nss methods.
+**********************************************************************/
+
+static struct nss_function_entry *nss_get_backend(const char *name )
+{
+	struct nss_function_entry *entry = backends;
+
+	for(entry = backends; entry; entry = entry->next) {
+		if ( strequal(entry->name, name) )
+			return entry;
+	}
+
+	return NULL;
+}
+
+/*********************************************************************
+ Allow a module to register itself as a backend.
+**********************************************************************/
+
+NTSTATUS smb_register_idmap_nss(int version, const char *name, struct nss_info_methods *methods)
+{
+	struct nss_function_entry *entry;
+
+ 	if ((version != SMB_NSS_INFO_INTERFACE_VERSION)) {
+		DEBUG(0, ("smb_register_idmap_nss: Failed to register idmap_nss module.\n"
+		          "The module was compiled against SMB_NSS_INFO_INTERFACE_VERSION %d,\n"
+		          "current SMB_NSS_INFO_INTERFACE_VERSION is %d.\n"
+		          "Please recompile against the current version of samba!\n",  
+			  version, SMB_NSS_INFO_INTERFACE_VERSION));
+		return NT_STATUS_OBJECT_TYPE_MISMATCH;
+  	}
+
+	if (!name || !name[0] || !methods) {
+		DEBUG(0,("smb_register_idmap_nss: called with NULL pointer or empty name!\n"));
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if ( nss_get_backend(name) ) {
+		DEBUG(0,("smb_register_idmap_nss: idmap module %s "
+			 "already registered!\n", name));
+		return NT_STATUS_OBJECT_NAME_COLLISION;
+	}
+
+	entry = SMB_XMALLOC_P(struct nss_function_entry);
+	entry->name = smb_xstrdup(name);
+	entry->methods = methods;
+
+	DLIST_ADD(backends, entry);
+	DEBUG(5, ("smb_register_idmap_nss: Successfully added idmap "
+		  "nss backend '%s'\n", name));
+
+	return NT_STATUS_OK;
+}
+
+/********************************************************************
+ *******************************************************************/
+
+static BOOL parse_nss_parm( const char *config, char **backend, char **domain )
+{
+	char *p;
+	char *q;
+	int len;
+
+	*backend = *domain = NULL;
+	
+	if ( !config )
+		return False;
+	
+	p = strchr( config, ':' );
+	
+	/* if no : then the string must be the backend name only */
+
+	if ( !p ) {
+		*backend = SMB_STRDUP( config );
+		return (*backend != NULL);
+	}
+
+	/* split the string and return the two parts */
+
+	if ( strlen(p+1) > 0 ) {
+		*domain = SMB_STRDUP( p+1 );
+	}
+	
+	len = PTR_DIFF(p,config)+1;
+	if ( (q = SMB_MALLOC_ARRAY( char, len )) == NULL ) {
+		SAFE_FREE( *backend );
+		return False;
+	}
+	
+	StrnCpy( q, config, len-1);
+	q[len-1] = '\0';
+	*backend = q;
+
+	return True;
+}
+
+/********************************************************************
+ Each nss backend must not store global state, but rather be able 
+ to initialize the state on a per domain basis.
+ *******************************************************************/
+
+NTSTATUS nss_init( const char **nss_list )
+{
+	NTSTATUS status;
+	int i;
+	char *backend, *domain;
+	struct nss_function_entry *nss_backend;
+	struct nss_domain_entry *nss_domain;
+
+	/* The "template" backend should alqays be registered as it
+	   is a static module */
+
+	if ( (nss_backend = nss_get_backend( "template" )) == NULL ) {
+		static_init_nss_info;	       
+	}
+
+	/* Create the list of nss_domains (loading any shared plugins
+	   as necessary) */
+
+	for ( i=0; nss_list && nss_list[i]; i++ ) {
+
+		if ( !parse_nss_parm(nss_list[i], &backend, &domain) ) 	{
+			DEBUG(0,("nss_init: failed to parse \"%s\"!\n",
+				 nss_list[0]));
+			continue;			
+		}
+
+		/* validate the backend */
+
+		if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
+			/* attempt to register the backend */
+			status = smb_probe_module( "nss_info", backend );
+			if ( !NT_STATUS_IS_OK(status) ) {
+				continue;
+			}
+			
+			/* try again */
+			if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
+				DEBUG(0,("nss_init: unregistered backend %s!.  Skipping\n",
+					 backend));
+				continue;
+			}
+
+		}
+
+     		/* fill in the nss_domain_entry and add it to the 
+		   list of domains */
+
+		nss_domain = TALLOC_ZERO_P( nss_domain_list, struct nss_domain_entry );
+		if ( !nss_domain ) {
+			DEBUG(0,("nss_init: talloc() failure!\n"));
+			return NT_STATUS_NO_MEMORY;
+		}
+		
+		nss_domain->backend = nss_backend;
+		nss_domain->domain  = talloc_strdup( nss_domain, domain );
+
+		status = nss_domain->backend->methods->init( nss_domain );
+		if ( NT_STATUS_IS_OK( status ) ) {
+			DLIST_ADD( nss_domain_list, nss_domain );
+		} else {
+			DEBUG(0,("nss_init: Failed to init backend for %s domain!\n", 
+				 nss_domain->domain));
+		}
+
+		/* cleanup */
+
+		SAFE_FREE( backend );
+		SAFE_FREE( domain );		
+	}
+
+	if ( !nss_domain_list ) {
+		DEBUG(3,("nss_init: no nss backends configured.  "
+			 "Defaulting to \"template\".\n"));
+
+
+		/* we shouild default to use template here */
+	}
+	
+		
+	return NT_STATUS_OK;
+}
+
+/********************************************************************
+ *******************************************************************/
+
+NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
+		       TALLOC_CTX *ctx,
+		       ADS_STRUCT *ads, LDAPMessage *msg,
+		       char **homedir, char **shell, char **gecos,
+		       gid_t *p_gid)
+{
+	struct nss_domain_entry *p;
+	struct nss_info_methods *m;
+	
+	for ( p=nss_domain_list; p; p=p->next ) {
+		if ( strequal( p->domain, domain ) )
+			break;
+	}
+	
+	/* If we didn't find a match, then use the default nss info */
+
+	if ( !p ) {
+		if ( !nss_domain_list ) {
+			return NT_STATUS_NOT_FOUND;
+		}
+		
+		p = nss_domain_list;		
+	}
+
+	m = p->backend->methods;
+
+	return m->get_nss_info( p, user_sid, ctx, ads, msg, 
+				homedir, shell, gecos, p_gid );
+}
+
+/********************************************************************
+ *******************************************************************/
+
+NTSTATUS nss_close( const char *parameters )
+{
+	struct nss_domain_entry *p = nss_domain_list;
+	struct nss_domain_entry *q;
+
+	while ( p && p->backend && p->backend->methods ) {
+		/* close the backend */
+		p->backend->methods->close_fn();
+
+		/* free the memory */
+		q = p;
+		p = p->next;
+		TALLOC_FREE( q );
+	}
+
+	return NT_STATUS_OK;
+}
+
+/********************************************************************
+ Invoke the init function for a given domain's backend
+ *******************************************************************/
+
+NTSTATUS idmap_nss_init_domain( const char *domain )
+{
+	struct nss_domain_entry *p;
+	
+	DEBUG(10,("idmap_nss_init_domain: Searching for %s's init() function\n", 
+		  domain));
+	
+	for ( p=nss_domain_list; p; p=p->next ) {
+		if ( strequal( p->domain, domain ) ) {
+			DEBUG(10,("idmap_nss_init_domain: Calling init function for %s\n",
+				  domain));			
+			return p->backend->methods->init( p );
+		}
+	}
+	
+	return NT_STATUS_NO_SUCH_DOMAIN;	
+}
+

=== modified file 'source/nsswitch/winbindd.c'
--- source/nsswitch/winbindd.c	2007-01-19 20:22:16 +0000
+++ source/nsswitch/winbindd.c	2007-01-24 01:28:38 +0000
@@ -1009,6 +1009,8 @@
 		DEBUG(1, ("Could not init idmap! - Sid/[UG]id mapping will not be available\n"));
 	}
 
+	nss_init( lp_winbind_nss_info() );
+
 	/* Unblock all signals we are interested in as they may have been
 	   blocked by the parent process. */
 

=== modified file 'source/nsswitch/winbindd.h'
--- source/nsswitch/winbindd.h	2007-01-02 22:25:11 +0000
+++ source/nsswitch/winbindd.h	2007-01-24 01:28:38 +0000
@@ -112,6 +112,8 @@
 	char *full_name;
 	char *homedir;
 	char *shell;
+	gid_t primary_gid;                   /* allow the nss_info
+						backend to set the primary group */
 	DOM_SID user_sid;                    /* NT user and primary group SIDs */
 	DOM_SID group_sid;
 } WINBIND_USERINFO;

=== modified file 'source/nsswitch/winbindd_ads.c'
--- source/nsswitch/winbindd_ads.c	2007-01-16 14:06:39 +0000
+++ source/nsswitch/winbindd_ads.c	2007-01-24 01:28:39 +0000
@@ -40,7 +40,6 @@
 {
 	ADS_STRUCT *ads;
 	ADS_STATUS status;
-	enum wb_posix_mapping map_type;
 
 	DEBUG(10,("ads_cached_connection\n"));
 
@@ -126,17 +125,9 @@
 		return NULL;
 	}
 
-	map_type = get_nss_info(domain->name);
+	/* initialize the nss backend for this domain */
 
-	if ((map_type == WB_POSIX_MAP_RFC2307)||
-	    (map_type == WB_POSIX_MAP_SFU)) {
-	
-		status = ads_check_posix_schema_mapping(ads, map_type);
-		if (!ADS_ERR_OK(status)) {
-			DEBUG(10,("ads_check_posix_schema_mapping failed "
-				  "with: %s\n", ads_errstr(status)));
-		} 
-	}
+	idmap_nss_init_domain( domain->name );
 
 	/* set the flag that says we don't own the memory even 
 	   though we do so that ads_destroy() won't destroy the 
@@ -156,17 +147,7 @@
 			       WINBIND_USERINFO **info)
 {
 	ADS_STRUCT *ads = NULL;
-	const char *attrs[] = {"userPrincipalName",
-			       "sAMAccountName",
-			       "name", "objectSid", "primaryGroupID", 
-			       "sAMAccountType", 
-			       ADS_ATTR_SFU_HOMEDIR_OID, 
-			       ADS_ATTR_SFU_SHELL_OID,
-			       ADS_ATTR_SFU_GECOS_OID,
-			       ADS_ATTR_RFC2307_HOMEDIR_OID,
-			       ADS_ATTR_RFC2307_SHELL_OID,
-			       ADS_ATTR_RFC2307_GECOS_OID,
-			       NULL};
+	const char *attrs[] = { "*", NULL };
 	int i, count;
 	ADS_STATUS rc;
 	LDAPMessage *res = NULL;
@@ -210,6 +191,8 @@
 		char *shell = NULL;
 		uint32 group;
 		uint32 atype;
+		DOM_SID user_sid;
+		gid_t primary_gid = (gid_t)-1;
 
 		if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype) ||
 		    ads_atype_map(atype) != SID_NAME_USER) {
@@ -219,17 +202,10 @@
 
 		name = ads_pull_username(ads, mem_ctx, msg);
 
-		if (get_nss_info(domain->name) && ads->schema.map_type) {
-
-			DEBUG(10,("pulling posix attributes (%s schema)\n", 
-				wb_posix_map_str(ads->schema.map_type)));
-
-			homedir = ads_pull_string(ads, mem_ctx, msg, 
-						  ads->schema.posix_homedir_attr);
-			shell 	= ads_pull_string(ads, mem_ctx, msg, 
-						  ads->schema.posix_shell_attr);
-			gecos 	= ads_pull_string(ads, mem_ctx, msg, 
-						  ads->schema.posix_gecos_attr);
+		if ( ads_pull_sid( ads, msg, "objectSid", &user_sid ) ) {
+			status = nss_get_info( domain->name, &user_sid, mem_ctx, 
+					       ads, msg, &homedir, &shell, &gecos,
+					       &primary_gid );
 		}
 
 		if (gecos == NULL) {
@@ -250,6 +226,7 @@
 		(*info)[i].full_name = gecos;
 		(*info)[i].homedir = homedir;
 		(*info)[i].shell = shell;
+		(*info)[i].primary_gid = primary_gid;
 		sid_compose(&(*info)[i].group_sid, &domain->sid, group);
 		i++;
 	}
@@ -454,17 +431,7 @@
 			   WINBIND_USERINFO *info)
 {
 	ADS_STRUCT *ads = NULL;
-	const char *attrs[] = {"userPrincipalName", 
-			       "sAMAccountName",
-			       "name", 
-			       "primaryGroupID", 
-			       ADS_ATTR_SFU_HOMEDIR_OID, 
-			       ADS_ATTR_SFU_SHELL_OID,
-			       ADS_ATTR_SFU_GECOS_OID,
-			       ADS_ATTR_RFC2307_HOMEDIR_OID,
-			       ADS_ATTR_RFC2307_SHELL_OID,
-			       ADS_ATTR_RFC2307_GECOS_OID,
-			       NULL};
+	const char *attrs[] = { "*", NULL };
 	ADS_STATUS rc;
 	int count;
 	LDAPMessage *msg = NULL;
@@ -475,9 +442,7 @@
 
 	DEBUG(3,("ads: query_user\n"));
 
-	ads = ads_cached_connection(domain);
-	
-	if (!ads) {
+	if ( (ads = ads_cached_connection(domain)) == NULL ) {
 		domain->last_status = NT_STATUS_SERVER_DISABLED;
 		goto done;
 	}
@@ -502,18 +467,9 @@
 
 	info->acct_name = ads_pull_username(ads, mem_ctx, msg);
 
-	if (get_nss_info(domain->name) && ads->schema.map_type) {
-
-		DEBUG(10,("pulling posix attributes (%s schema)\n", 
-			wb_posix_map_str(ads->schema.map_type)));
-		
-		info->homedir 	= ads_pull_string(ads, mem_ctx, msg, 
-						  ads->schema.posix_homedir_attr);
-		info->shell 	= ads_pull_string(ads, mem_ctx, msg, 
-						  ads->schema.posix_shell_attr);
-		info->full_name	= ads_pull_string(ads, mem_ctx, msg,
-						  ads->schema.posix_gecos_attr);
-	}
+	info->primary_gid = (gid_t)-1;	
+	nss_get_info( domain->name, sid, mem_ctx, ads, msg, 
+		      &info->homedir, &info->shell, &info->full_name, &info->primary_gid );	
 
 	if (info->full_name == NULL) {
 		info->full_name = ads_pull_string(ads, mem_ctx, msg, "name");

=== modified file 'source/nsswitch/winbindd_async.c'
--- source/nsswitch/winbindd_async.c	2007-01-14 23:21:02 +0000
+++ source/nsswitch/winbindd_async.c	2007-01-24 01:28:38 +0000
@@ -764,7 +764,9 @@
 	}
 
 	fstrcpy(state->response.data.name.dom_name, dom_name);
+	TALLOC_FREE(dom_name);
 	fstrcpy(state->response.data.name.name, name);
+	TALLOC_FREE(name);
 	state->response.data.name.type = type;
 
 	TALLOC_FREE(dom_name);
@@ -1397,13 +1399,13 @@
 {
 	void (*cont)(void *priv, BOOL succ, const char *acct_name,
 		     const char *full_name, const char *homedir, 
-		     const char *shell, uint32 group_rid) =
+		     const char *shell, uint32 gid, uint32 group_rid) =
 		(void (*)(void *, BOOL, const char *, const char *,
-			  const char *, const char *, uint32))c;
+			  const char *, const char *, uint32, uint32))c;
 
 	if (!success) {
 		DEBUG(5, ("Could not trigger query_user\n"));
-		cont(private_data, False, NULL, NULL, NULL, NULL, -1);
+		cont(private_data, False, NULL, NULL, NULL, NULL, -1, -1);
 		return;
 	}
 
@@ -1411,6 +1413,7 @@
 	     response->data.user_info.full_name,
 	     response->data.user_info.homedir,
 	     response->data.user_info.shell,
+	     response->data.user_info.primary_gid,
 	     response->data.user_info.group_rid);
 }
 
@@ -1421,6 +1424,7 @@
 				   const char *full_name,
 				   const char *homedir,
 				   const char *shell,
+				   gid_t gid,
 				   uint32 group_rid),
 		      void *private_data)
 {

=== modified file 'source/nsswitch/winbindd_cache.c'
--- source/nsswitch/winbindd_cache.c	2006-12-12 17:45:13 +0000
+++ source/nsswitch/winbindd_cache.c	2007-01-24 01:28:38 +0000
@@ -827,6 +827,7 @@
 	centry_put_string(centry, info->full_name);
 	centry_put_string(centry, info->homedir);
 	centry_put_string(centry, info->shell);
+	centry_put_uint32(centry, info->primary_gid);
 	centry_put_sid(centry, &info->user_sid);
 	centry_put_sid(centry, &info->group_sid);
 	centry_end(centry, "U/%s", sid_to_string(sid_string, &info->user_sid));
@@ -854,7 +855,7 @@
 }
 
 static void wcache_save_password_policy(struct winbindd_domain *domain, NTSTATUS status, SAM_UNK_INFO_1 *policy)
-{
+ {
 	struct cache_entry *centry;
 
 	centry = centry_start(domain, status);
@@ -1589,6 +1590,7 @@
 	info->full_name = centry_string(centry, mem_ctx);
 	info->homedir = centry_string(centry, mem_ctx);
 	info->shell = centry_string(centry, mem_ctx);
+	info->primary_gid = centry_uint32(centry);
 	centry_sid(centry, mem_ctx, &info->user_sid);
 	centry_sid(centry, mem_ctx, &info->group_sid);
 	status = centry->status;

=== modified file 'source/nsswitch/winbindd_nss.h'
--- source/nsswitch/winbindd_nss.h	2007-01-13 22:54:16 +0000
+++ source/nsswitch/winbindd_nss.h	2007-01-24 01:28:39 +0000
@@ -447,6 +447,7 @@
 			fstring full_name;
 			fstring homedir;
 			fstring shell;
+			uint32 primary_gid;			
 			uint32 group_rid;
 		} user_info;
 		struct {

=== modified file 'source/nsswitch/winbindd_user.c'
--- source/nsswitch/winbindd_user.c	2006-12-14 15:49:51 +0000
+++ source/nsswitch/winbindd_user.c	2007-01-24 01:28:38 +0000
@@ -41,7 +41,7 @@
 	if (out == NULL)
 		return False;
 
-	if (in && !strequal(in,"") && lp_security() == SEC_ADS && (get_nss_info(domname))) {
+	if ( in && !strequal(in,"") && lp_security() == SEC_ADS ) {
 		safe_strcpy(out, in, sizeof(fstring) - 1);
 		return True;
 	}
@@ -156,6 +156,7 @@
 	fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
 	fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
 	fstrcpy(state->response.data.user_info.shell, user_info.shell);
+	state->response.data.user_info.primary_gid = user_info.primary_gid;	
 	if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
 				&state->response.data.user_info.group_rid)) {
 		DEBUG(1, ("Could not extract group rid out of %s\n",
@@ -184,6 +185,7 @@
 				    const char *full_name, 
 				    const char *homedir,
 				    const char *shell,
+				    uint32 gid,
 				    uint32 group_rid);
 static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid);
 static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
@@ -222,6 +224,7 @@
 				    const char *full_name, 
 				    const char *homedir,
 				    const char *shell,
+				    uint32 gid,
 				    uint32 group_rid)
 {
 	fstring username;
@@ -241,6 +244,7 @@
 	s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
 	s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
 	s->shell = talloc_strdup(s->state->mem_ctx, shell);
+	s->gid = gid;	
 	sid_copy(&s->group_sid, &s->domain->sid);
 	sid_append_rid(&s->group_sid, group_rid);
 
@@ -272,13 +276,29 @@
 	struct winbindd_pw *pw;
 	fstring output_username;
 
+	/* allow the nss backend to override the primary group ID.
+	   If the gid has already been set, then keep it.
+	   This makes me feel dirty.  If the nss backend already
+	   gave us a gid, we don't really care whether the sid2gid()
+	   call worked or not.   --jerry  */
+
+	if ( s->gid == (gid_t)-1 ) {
 	if (!success) {
 		DEBUG(5, ("Could not query user's %s\\%s\n gid",
 			  s->domain->name, s->username));
 		goto failed;
 	}
 
+		/* take what the sid2gid() call gave us */
 	s->gid = gid;
+	}
+
+	/* allow the nss backend to override the primary group ID.
+	   If the gid has already been set, then keep it */
+
+	if ( s->gid == (gid_t)-1 ) {
+		s->gid = gid;
+	}
 
 	pw = &s->state->response.data.pw;
 	pw->pw_uid = s->uid;

=== modified file 'source/param/loadparm.c'
--- source/param/loadparm.c	2006-12-21 13:52:11 +0000
+++ source/param/loadparm.c	2007-01-24 01:28:38 +0000
@@ -1631,7 +1631,6 @@
 	Globals.bWinbindUseDefaultDomain = False;
 	Globals.bWinbindTrustedDomainsOnly = False;
 	Globals.bWinbindNestedGroups = True;
-	Globals.szWinbindNssInfo = str_list_make("template", NULL);
 	Globals.bWinbindRefreshTickets = False;
 	Globals.bWinbindOfflineLogon = False;
 



More information about the samba-technical mailing list