r20986: Commit the prototype of the nss_info plugin interface.
authorGerald Carter <jerry@samba.org>
Wed, 24 Jan 2007 01:48:08 +0000 (01:48 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:17:23 +0000 (12:17 -0500)
This allows a provider to supply the homedirectory, etc...
attributes for a user without requiring support in core
winbindd code.  The idmap_ad.c module has been modified
to provide the idmap 'ad' library as well as the rfc2307 and sfu
"winbind nss info" support.

The SID/id mapping is working in idmap_ad but the nss_info
still has a few quirks that I'm in the process of resolving.
(This used to be commit aaec0115e2c96935499052d9a637a20c6445986e)

18 files changed:
source3/Makefile.in
source3/configure.in
source3/include/ads.h
source3/include/includes.h
source3/include/nss_info.h [new file with mode: 0644]
source3/libads/ads_struct.c
source3/libads/ldap_schema.c
source3/nsswitch/idmap_ad.c
source3/nsswitch/nss_info.c
source3/nsswitch/nss_info_template.c [new file with mode: 0644]
source3/nsswitch/winbindd.c
source3/nsswitch/winbindd.h
source3/nsswitch/winbindd_ads.c
source3/nsswitch/winbindd_async.c
source3/nsswitch/winbindd_cache.c
source3/nsswitch/winbindd_nss.h
source3/nsswitch/winbindd_user.c
source3/param/loadparm.c

index 7d86bc764136c86785a4a211d6e7657336d4ce6e..249d466178fb6ee3e3d517be861466c6154aafdd 100644 (file)
@@ -181,7 +181,9 @@ RPC_MODULES = @RPC_MODULES@
 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_OBJ = libads/ldap.o libads/ldap_printer.o libads/sasl.o \
             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 @@ PROTO_OBJ = $(SMBD_OBJ_MAIN) $(LIBNDR_OBJ) $(LIBNDR_GEN_OBJ) \
            $(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 @@ PAM_SMBPASS_OBJ_0 = pam_smbpass/pam_smb_auth.o pam_smbpass/pam_smb_passwd.o \
 
 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 @@ WINBINDD_OBJ = \
                $(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 @@ bin/gpfs.@SHLIBEXT@: $(VFS_GPFS_OBJ)
        @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_GPFS_OBJ) \
                @SONAMEFLAG@`basename $@`
 
+#########################################################
+## IdMap NSS plugins
+
+## None here right now
+#########################################################
+
 bin/wbinfo@EXEEXT@: $(WBINFO_OBJ) @BUILD_POPT@ bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(LDFLAGS) $(WBINFO_OBJ) $(DYNEXP) $(LIBS) $(LDAP_LIBS) @POPTLIBS@
index a2b0f3e0c43e27f39533b2c199018bfdcd1e9762..0a14d4c88c85694d06dcbc25ab504b4ce3e22087 100644 (file)
@@ -592,7 +592,7 @@ AC_SUBST(DYNEXP)
 
 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_tdb=STATIC
 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_rid, nsswitch/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
 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)
index 1d8b1f3d322082aa6d1e02a8b23f9e1b9e102acf..d97ae1531f956f27b87a9c2b086a1518cdc20894 100644 (file)
@@ -57,18 +57,19 @@ typedef struct {
                time_t current_time;
                int tried_closest_dc;
        } config;
+} ADS_STRUCT;
 
-       /* 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;
+/* 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;
+};
 
-} ADS_STRUCT;
 
 /* there are 5 possible types of errors the ads subsystem can produce */
 enum ads_error_type {ENUM_ADS_ERROR_KRB5, ENUM_ADS_ERROR_GSS, 
index b341d1ee957fef352ca50750f69734c70352be65..84bd90cc27f7eef83cf9af3a879273b52a160f6b 100644 (file)
@@ -768,6 +768,8 @@ enum flush_reason_enum {
     /* 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"
diff --git a/source3/include/nss_info.h b/source3/include/nss_info.h
new file mode 100644 (file)
index 0000000..f442bf0
--- /dev/null
@@ -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_ */
index 545995ddccc103c5df87276f3385de717b31afd8..05f066c9fa597d16e27d8cdad8966baada95e5e0 100644 (file)
@@ -161,12 +161,6 @@ void ads_destroy(ADS_STRUCT **ads)
                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 )
index b4a512cbfe2ba5a939d23e8ebaa33766f4fc88b0..5d91d985490e1e3b540001ce5df81300c374d3ab 100644 (file)
@@ -186,7 +186,10 @@ static ADS_STATUS ads_schema_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **s
  * @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 @@ ADS_STATUS ads_check_posix_schema_mapping(ADS_STRUCT *ads, enum wb_posix_mapping
        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 @@ ADS_STATUS ads_check_posix_schema_mapping(ADS_STRUCT *ads, enum wb_posix_mapping
 
        DEBUG(10,("ads_check_posix_schema_mapping\n"));
 
-       switch (map_type) {
-       
-               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);
+       if ( (ctx = talloc_init("ads_check_posix_schema_mapping")) == NULL ) {
+               return ADS_ERROR(LDAP_NO_MEMORY);
        }
 
-       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) {
+       if ( (schema = TALLOC_P(mem_ctx, struct posix_schema)) == NULL ) {
+               TALLOC_FREE( ctx );
                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 @@ ADS_STATUS ads_check_posix_schema_mapping(ADS_STRUCT *ads, enum wb_posix_mapping
                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 @@ ADS_STATUS ads_check_posix_schema_mapping(ADS_STRUCT *ads, enum wb_posix_mapping
 
                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);
index 252e2159aa64ca73a55f452aa3678942a73c1237..208ccc2d4df6c87424f2a2b701461a6e3bceb10e 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (C) Andrew Tridgell 2001
  * Copyright (C) Andrew Bartlett <abartlet@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
 
 #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
 
-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);
+#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)
 
-       map_type = get_nss_info(ads->server.workgroup);
+struct idmap_ad_context {
+       uint32_t filter_low_id;
+       uint32_t filter_high_id;
+};
 
-       if ((map_type == WB_POSIX_MAP_SFU) ||
-           (map_type == WB_POSIX_MAP_RFC2307)) {
+NTSTATUS init_module(void);
 
-               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);
+static ADS_STRUCT *ad_idmap_ads = NULL;
+static struct posix_schema *ad_schema = NULL;
+static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN;
 
-       return ADS_ERROR(LDAP_SUCCESS);
-}
+/************************************************************************
+ ***********************************************************************/
 
-static ADS_STRUCT *ad_idmap_cached_connection(void)
+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 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
                        ads_destroy( &ads );
                        ads_kdestroy(WINBIND_CCACHE_NAME);
                        ad_idmap_ads = NULL;
+                       TALLOC_FREE( ad_schema );                       
                }
        }
 
@@ -106,8 +87,7 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
                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 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
        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 @@ static ADS_STRUCT *ad_idmap_cached_connection(void)
 
        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"));
+       ad_idmap_ads = ads;
+
+       return ads;
+}
+
+/************************************************************************
+ ***********************************************************************/
+
+static ADS_STRUCT *ad_idmap_cached_connection(void)
+{
+       ADS_STRUCT *ads = ad_idmap_cached_connection_internal();
+       
+       if ( !ads )
                return NULL;
-       }
 
-       ad_idmap_ads = ads;
+       /* 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;
 }
 
-struct idmap_ad_context {
-       uint32_t filter_low_id, filter_high_id;         /* Filter range */
-};
+/************************************************************************
+ ***********************************************************************/
 
-/* Initialize and check conf is appropriate */
 static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params)
 {
        struct idmap_ad_context *ctx;
@@ -151,19 +161,16 @@ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params
        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 @@ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params
                          "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 @@ static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, ui
        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 @@ static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map
        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;
+       char *u_filter = NULL;
+       char *g_filter = NULL;
 
-       ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);      
+       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 */
-               switch (ids[0]->xid.type) {
-               case ID_TYPE_UID:
+       attrs[2] = ad_schema->posix_uidnumber_attr;
+       attrs[3] = ad_schema->posix_gidnumber_attr;
 
-                       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);
+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:
-
-                       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);
+                       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;
+
                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 @@ again:
                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 @@ again:
                        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 @@ again:
                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 @@ done:
        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 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map
                                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);
+       CHECK_ALLOC_DONE(filter);
 
-               bidx = idx;
-               for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) {
+       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);
+               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 @@ again:
                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 @@ again:
                        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 @@ again:
                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 @@ again:
 
        /* 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 @@ done:
        return ret;
 }
 
+/************************************************************************
+ ***********************************************************************/
+
 static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
 {
        ADS_STRUCT *ads = ad_idmap_ads;
@@ -694,22 +640,176 @@ static NTSTATUS idmap_ad_close(struct idmap_domain *dom)
                ad_idmap_ads = NULL;
        }
 
-       SAFE_FREE(attr_uidnumber);
-       SAFE_FREE(attr_gidnumber);
+       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
+       .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
 };
 
-/* support for new authentication subsystem */
+
+/************************************************************************
+ 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;    
 }
 
index 6d01916754e142ad5a7877836482a0aa482cecb7..127484f53775ad31f83802475e8df13080bcf4c7 100644 (file)
 /* 
    Unix SMB/CIFS implementation.
-   nss info helpers
-   Copyright (C) Guenther Deschner 2006
+   Idmap NSS headers
 
-   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.
+   Copyright (C) Gerald Carter             2006
 
-   This program is distributed in the hope that it will be useful,
+   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"
+#include "nss_info.h"
+
+static struct nss_function_entry *backends = NULL;
+static struct nss_domain_entry *nss_domain_list = NULL;
 
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_IDMAP
+/**********************************************************************
+ **********************************************************************/
 
-static enum wb_posix_mapping wb_posix_map_type(const char *map_str)
+const char *wb_posix_map_str(enum wb_posix_mapping mtype)
 {
-       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;
+       switch (mtype) {
+               case WB_POSIX_MAP_SFU:
+                       return "sfu";
+               case WB_POSIX_MAP_RFC2307:
+                       return "rfc2307";
+               default:
+                       break;
+       }
+       return NULL;
 }
 
-/* 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)
+/**********************************************************************
+ Get idmap nss methods.
+**********************************************************************/
+
+static struct nss_function_entry *nss_get_backend(const char *name )
 {
-       const char **list = lp_winbind_nss_info();
-       enum wb_posix_mapping map_templ = WB_POSIX_MAP_TEMPLATE;
-       int i;
+       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;
+       }
 
-       DEBUG(11,("get_nss_info for %s\n", domain_name));
+       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;
 
-       if (!lp_winbind_nss_info() || !*lp_winbind_nss_info()) {
-               return WB_POSIX_MAP_TEMPLATE;
+       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);
        }
 
-       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;
+       /* 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;
 
-       DEBUG(11,("get_nss_info: using \"%s\" by default\n", list[0]));
+       return True;
+}
 
-       for (i=0; list[i]; i++) {
+/********************************************************************
+ 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;
 
-               const char *p = list[i];
-               fstring tok;
+       /* The "template" backend should alqays be registered as it
+          is a static module */
 
-               if (!next_token(&p, tok, ":", sizeof(tok))) {
-                       DEBUG(0,("get_nss_info: no \":\" delimitier found\n"));
-                       continue;
+       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;                       
                }
 
-               if (strequal(tok, domain_name)) {
-               
-                       enum wb_posix_mapping type;
+               /* 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;
+                       }
                        
-                       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; */
+                       /* try again */
+                       if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
+                               DEBUG(0,("nss_init: unregistered backend %s!.  Skipping\n",
+                                        backend));
                                continue;
                        }
 
-                       DEBUG(11,("get_nss_info: using \"%s\" for domain: %s\n", p, tok));
-                       
-                       return type;
                }
+
+               /* 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 );            
        }
 
-       return map_templ;
+       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;
 }
 
-const char *wb_posix_map_str(enum wb_posix_mapping mtype)
+/********************************************************************
+ *******************************************************************/
+
+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)
 {
-       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:
+       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;
        }
-       return NULL;
+       
+       /* 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;        
+}
+
diff --git a/source3/nsswitch/nss_info_template.c b/source3/nsswitch/nss_info_template.c
new file mode 100644 (file)
index 0000000..e1076fb
--- /dev/null
@@ -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);   
+}
index c8c5496ebf050a070b8ef73cc37e502b08089e6d..ce39df350fac40ab8c3bcf1f5c43d7e6962d6cc1 100644 (file)
@@ -1009,6 +1009,8 @@ int main(int argc, char **argv, char **envp)
                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. */
 
index 59557c49423a5bf06fdaddada01beff69aabc20e..b9e07a2321b87c60032a5c9092f4b0a74331d1ea 100644 (file)
@@ -112,6 +112,8 @@ typedef struct {
        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;
index 8cb60806f8a7bbb8f2005218e4c3fffd06d41286..fc6308deedbde054948914d679ca9cf6a5b1a724 100644 (file)
@@ -40,7 +40,6 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
 {
        ADS_STRUCT *ads;
        ADS_STATUS status;
-       enum wb_posix_mapping map_type;
 
        DEBUG(10,("ads_cached_connection\n"));
 
@@ -126,17 +125,9 @@ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain)
                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 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                               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 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                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 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
 
                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 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
                (*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 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
                           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 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 
        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 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
 
        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");
index d70d6a0806c80da5eaa331e9fb4fbeb590a4d3e6..ee81b14f2f5e4a270d1e0f413bafad3cfcccc3a0 100644 (file)
@@ -764,7 +764,9 @@ enum winbindd_result winbindd_dual_lookupsid(struct winbindd_domain *domain,
        }
 
        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 @@ static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
 {
        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 @@ static void query_user_recv(TALLOC_CTX *mem_ctx, BOOL success,
             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 @@ void query_user_async(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain,
                                   const char *full_name,
                                   const char *homedir,
                                   const char *shell,
+                                  gid_t gid,
                                   uint32 group_rid),
                      void *private_data)
 {
index 0587d8b2b37ba36a33f2054740ed5d8309eed083..423e625ced93f3439997d6654302e05b35dc0fa7 100644 (file)
@@ -827,6 +827,7 @@ static void wcache_save_user(struct winbindd_domain *domain, NTSTATUS status, WI
        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_lockout_policy(struct winbindd_domain *domain, NTSTATUS
 }
 
 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 @@ static NTSTATUS query_user(struct winbindd_domain *domain,
        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;
index 9584e18e065a40f26f7876ebf50750f4418f69a0..95992181f5209ec4d58f6af5006c79ba62ed1c70 100644 (file)
@@ -447,6 +447,7 @@ struct winbindd_response {
                        fstring full_name;
                        fstring homedir;
                        fstring shell;
+                       uint32 primary_gid;                     
                        uint32 group_rid;
                } user_info;
                struct {
index f82b03df07dd9f20cd09970bbe2e56f9c28bd7a5..76cf9d44bdf0c37ce05de6f399308d711b7743f7 100644 (file)
@@ -41,7 +41,7 @@ static BOOL fillup_pw_field(const char *lp_template,
        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 @@ enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
        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 @@ static void getpwsid_queryuser_recv(void *private_data, BOOL success,
                                    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 @@ static void getpwsid_queryuser_recv(void *private_data, BOOL success,
                                    const char *full_name, 
                                    const char *homedir,
                                    const char *shell,
+                                   uint32 gid,
                                    uint32 group_rid)
 {
        fstring username;
@@ -241,6 +244,7 @@ static void getpwsid_queryuser_recv(void *private_data, BOOL success,
        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 @@ static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
        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;
index 172d32b5869b65deada3b9e9387bce33ac3cf3ed..e1cce4b963fc0eb65a939e41edd6b43cccbedac8 100644 (file)
@@ -1631,7 +1631,6 @@ static void init_globals(BOOL first_time_only)
        Globals.bWinbindUseDefaultDomain = False;
        Globals.bWinbindTrustedDomainsOnly = False;
        Globals.bWinbindNestedGroups = True;
-       Globals.szWinbindNssInfo = str_list_make("template", NULL);
        Globals.bWinbindRefreshTickets = False;
        Globals.bWinbindOfflineLogon = False;