From b9b26be1744b792a54f0a77af140237b4dc5a870 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 24 Jan 2007 01:48:08 +0000 Subject: r20986: Commit the prototype of the nss_info plugin interface. 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) --- source3/Makefile.in | 21 +- source3/configure.in | 10 +- source3/include/ads.h | 21 +- source3/include/includes.h | 2 + source3/include/nss_info.h | 68 ++++ source3/libads/ads_struct.c | 6 - source3/libads/ldap_schema.c | 77 ++--- source3/nsswitch/idmap_ad.c | 604 ++++++++++++++++++++--------------- source3/nsswitch/nss_info.c | 340 +++++++++++++++----- source3/nsswitch/nss_info_template.c | 84 +++++ source3/nsswitch/winbindd.c | 2 + source3/nsswitch/winbindd.h | 2 + source3/nsswitch/winbindd_ads.c | 74 +---- source3/nsswitch/winbindd_async.c | 10 +- source3/nsswitch/winbindd_cache.c | 4 +- source3/nsswitch/winbindd_nss.h | 1 + source3/nsswitch/winbindd_user.c | 22 +- source3/param/loadparm.c | 1 - 18 files changed, 893 insertions(+), 456 deletions(-) create mode 100644 source3/include/nss_info.h create mode 100644 source3/nsswitch/nss_info_template.c diff --git a/source3/Makefile.in b/source3/Makefile.in index 7d86bc7641..249d466178 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -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@ diff --git a/source3/configure.in b/source3/configure.in index a2b0f3e0c4..0a14d4c88c 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -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) diff --git a/source3/include/ads.h b/source3/include/ads.h index 1d8b1f3d32..d97ae1531f 100644 --- a/source3/include/ads.h +++ b/source3/include/ads.h @@ -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, diff --git a/source3/include/includes.h b/source3/include/includes.h index b341d1ee95..84bd90cc27 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -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 index 0000000000..f442bf0db5 --- /dev/null +++ b/source3/include/nss_info.h @@ -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_ */ diff --git a/source3/libads/ads_struct.c b/source3/libads/ads_struct.c index 545995ddcc..05f066c9fa 100644 --- a/source3/libads/ads_struct.c +++ b/source3/libads/ads_struct.c @@ -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 ) diff --git a/source3/libads/ldap_schema.c b/source3/libads/ldap_schema.c index b4a512cbfe..5d91d98549 100644 --- a/source3/libads/ldap_schema.c +++ b/source3/libads/ldap_schema.c @@ -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; ischema.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); diff --git a/source3/nsswitch/idmap_ad.c b/source3/nsswitch/idmap_ad.c index 252e2159aa..208ccc2d4d 100644 --- a/source3/nsswitch/idmap_ad.c +++ b/source3/nsswitch/idmap_ad.c @@ -7,7 +7,7 @@ * * Copyright (C) Andrew Tridgell 2001 * Copyright (C) Andrew Bartlett 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" -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] && ixid.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] && isid, 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; } diff --git a/source3/nsswitch/nss_info.c b/source3/nsswitch/nss_info.c index 6d01916754..127484f537 100644 --- a/source3/nsswitch/nss_info.c +++ b/source3/nsswitch/nss_info.c @@ -1,111 +1,305 @@ /* 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 index 0000000000..e1076fbeaf --- /dev/null +++ b/source3/nsswitch/nss_info_template.c @@ -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); +} diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index c8c5496ebf..ce39df350f 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -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. */ diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 59557c4942..b9e07a2321 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -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; diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index 8cb60806f8..fc6308deed 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -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"); diff --git a/source3/nsswitch/winbindd_async.c b/source3/nsswitch/winbindd_async.c index d70d6a0806..ee81b14f2f 100644 --- a/source3/nsswitch/winbindd_async.c +++ b/source3/nsswitch/winbindd_async.c @@ -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) { diff --git a/source3/nsswitch/winbindd_cache.c b/source3/nsswitch/winbindd_cache.c index 0587d8b2b3..423e625ced 100644 --- a/source3/nsswitch/winbindd_cache.c +++ b/source3/nsswitch/winbindd_cache.c @@ -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; diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index 9584e18e06..95992181f5 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -447,6 +447,7 @@ struct winbindd_response { fstring full_name; fstring homedir; fstring shell; + uint32 primary_gid; uint32 group_rid; } user_info; struct { diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index f82b03df07..76cf9d44bd 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -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; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 172d32b586..e1cce4b963 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -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; -- cgit