1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-27 22:50:26 +03:00

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)
This commit is contained in:
Gerald Carter 2007-01-24 01:48:08 +00:00 committed by Gerald (Jerry) Carter
parent 78f5f4b260
commit b9b26be174
18 changed files with 925 additions and 488 deletions

View 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@

View 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)

View File

@ -57,19 +57,20 @@ typedef struct {
time_t current_time;
int tried_closest_dc;
} config;
/* info derived from the servers schema */
struct {
enum wb_posix_mapping map_type;
char *posix_homedir_attr;
char *posix_shell_attr;
char *posix_uidnumber_attr;
char *posix_gidnumber_attr;
char *posix_gecos_attr;
} schema;
} ADS_STRUCT;
/* used to remember the names of the posix attributes in AD */
/* see the rfc2307 & sfu nss backends */
struct posix_schema {
char *posix_homedir_attr;
char *posix_shell_attr;
char *posix_uidnumber_attr;
char *posix_gidnumber_attr;
char *posix_gecos_attr;
};
/* there are 5 possible types of errors the ads subsystem can produce */
enum ads_error_type {ENUM_ADS_ERROR_KRB5, ENUM_ADS_ERROR_GSS,
ENUM_ADS_ERROR_LDAP, ENUM_ADS_ERROR_SYSTEM, ENUM_ADS_ERROR_NT};

View 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"

View File

@ -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_ */

View 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 )

View 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);
}
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 ( (ctx = talloc_init("ads_check_posix_schema_mapping")) == NULL ) {
return ADS_ERROR(LDAP_NO_MEMORY);
}
if ( (schema = TALLOC_P(mem_ctx, struct posix_schema)) == NULL ) {
TALLOC_FREE( ctx );
return ADS_ERROR(LDAP_NO_MEMORY);
}
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);

View 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
@ -32,56 +32,36 @@
#define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache"
#define IDMAP_AD_MAX_IDS 30
#define CHECK_ALLOC_DONE(mem) do { \
if (!mem) { \
DEBUG(0, ("Out of memory!\n")); \
ret = NT_STATUS_NO_MEMORY; \
goto done; \
} \
} while (0)
struct idmap_ad_context {
uint32_t filter_low_id;
uint32_t filter_high_id;
};
NTSTATUS init_module(void);
static ADS_STRUCT *ad_idmap_ads = NULL;
static struct posix_schema *ad_schema = NULL;
static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN;
static char *attr_uidnumber = NULL;
static char *attr_gidnumber = NULL;
/************************************************************************
***********************************************************************/
static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads)
{
ADS_STATUS status;
enum wb_posix_mapping map_type;
if (attr_uidnumber != NULL && attr_gidnumber != NULL) {
return ADS_ERROR(LDAP_SUCCESS);
}
SMB_ASSERT(ads->server.workgroup);
map_type = get_nss_info(ads->server.workgroup);
if ((map_type == WB_POSIX_MAP_SFU) ||
(map_type == WB_POSIX_MAP_RFC2307)) {
status = ads_check_posix_schema_mapping(ads, map_type);
if (ADS_ERR_OK(status)) {
attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr);
attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr);
ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
return ADS_ERROR(LDAP_SUCCESS);
} else {
DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status)));
/* return status; */
}
}
/* fallback to XAD defaults */
attr_uidnumber = SMB_STRDUP("uidNumber");
attr_gidnumber = SMB_STRDUP("gidNumber");
ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber);
ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber);
return ADS_ERROR(LDAP_SUCCESS);
}
static ADS_STRUCT *ad_idmap_cached_connection(void)
static 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"));
return NULL;
}
ad_idmap_ads = ads;
return ads;
}
struct idmap_ad_context {
uint32_t filter_low_id, filter_high_id; /* Filter range */
};
/************************************************************************
***********************************************************************/
static ADS_STRUCT *ad_idmap_cached_connection(void)
{
ADS_STRUCT *ads = ad_idmap_cached_connection_internal();
if ( !ads )
return NULL;
/* if we have a valid ADS_STRUCT and the schema model is
defined, then we can return here. */
if ( ad_schema )
return ads;
/* Otherwise, set the schema model */
if ( (ad_map_type == WB_POSIX_MAP_SFU) ||
(ad_map_type == WB_POSIX_MAP_RFC2307) )
{
ADS_STATUS schema_status;
schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema);
if ( !ADS_ERR_OK(schema_status) ) {
DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
return NULL;
}
}
return ads;
}
/************************************************************************
***********************************************************************/
/* 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:
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);
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);
break;
default:
DEBUG(3, ("Unknown ID type\n"));
ret = NT_STATUS_INVALID_PARAMETER;
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 *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;
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);
}
}
filter = talloc_asprintf(memctx, "(|");
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, ")");
CHECK_ALLOC_DONE(filter);
DEBUG(10, ("Filter: [%s]\n", filter));
} else {
bidx = 0;
idx = 1;
}
u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)",
ad_schema->posix_uidnumber_attr,
(unsigned long)ids[idx]->xid.id);
CHECK_ALLOC_DONE(u_filter);
break;
case ID_TYPE_GID:
if ( ! g_filter) {
g_filter = talloc_asprintf(memctx, "(&(|"
"(sAMAccountType=%d)"
"(sAMAccountType=%d))(|",
ATYPE_SECURITY_GLOBAL_GROUP,
ATYPE_SECURITY_LOCAL_GROUP);
}
g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)",
ad_schema->posix_gidnumber_attr,
(unsigned long)ids[idx]->xid.id);
CHECK_ALLOC_DONE(g_filter);
break;
default:
DEBUG(3, ("Unknown ID type\n"));
ids[idx]->status = ID_UNKNOWN;
continue;
}
}
filter = talloc_asprintf(memctx, "(|");
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, ")");
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;
}
static struct idmap_methods ad_methods = {
.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
};
/*
* nss_info_{sfu,rfc2307}
*/
/* support for new authentication subsystem */
NTSTATUS idmap_ad_init(void)
/************************************************************************
Initialize the {sfu,rfc2307} state
***********************************************************************/
static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
{
return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods);
/* 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,
.unixids_to_sids = idmap_ad_unixids_to_sids,
.sids_to_unixids = idmap_ad_sids_to_unixids,
.close_fn = idmap_ad_close
};
/* The SFU and RFC2307 NSS plugins share everything but the init
function which sets the intended schema model to use */
static struct nss_info_methods nss_rfc2307_methods = {
.init = nss_rfc2307_init,
.get_nss_info = nss_ad_get_info,
.close_fn = nss_ad_close
};
static struct nss_info_methods nss_sfu_methods = {
.init = nss_sfu_init,
.get_nss_info = nss_ad_get_info,
.close_fn = nss_ad_close
};
/************************************************************************
Initialize the plugins
***********************************************************************/
NTSTATUS idmap_ad_init(void)
{
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;
}

View File

@ -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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_IDMAP
static struct nss_function_entry *backends = NULL;
static struct nss_domain_entry *nss_domain_list = NULL;
static enum wb_posix_mapping wb_posix_map_type(const char *map_str)
{
if (strequal(map_str, "template"))
return WB_POSIX_MAP_TEMPLATE;
else if (strequal(map_str, "sfu"))
return WB_POSIX_MAP_SFU;
else if (strequal(map_str, "rfc2307"))
return WB_POSIX_MAP_RFC2307;
else if (strequal(map_str, "unixinfo"))
return WB_POSIX_MAP_UNIXINFO;
return WB_POSIX_MAP_UNKNOWN;
}
/* winbind nss info = rfc2307 SO36:sfu FHAIN:rfc2307 PANKOW:template
*
* syntax is:
* 1st param: default setting
* following ":" separated list elements:
* DOMAIN:setting
* setting can be one of "sfu", "rfc2307", "template", "unixinfo"
*/
enum wb_posix_mapping get_nss_info(const char *domain_name)
{
const char **list = lp_winbind_nss_info();
enum wb_posix_mapping map_templ = WB_POSIX_MAP_TEMPLATE;
int i;
DEBUG(11,("get_nss_info for %s\n", domain_name));
if (!lp_winbind_nss_info() || !*lp_winbind_nss_info()) {
return WB_POSIX_MAP_TEMPLATE;
}
if ((map_templ = wb_posix_map_type(list[0])) == WB_POSIX_MAP_UNKNOWN) {
DEBUG(0,("get_nss_info: invalid setting: %s\n", list[0]));
return WB_POSIX_MAP_TEMPLATE;
}
DEBUG(11,("get_nss_info: using \"%s\" by default\n", list[0]));
for (i=0; list[i]; i++) {
const char *p = list[i];
fstring tok;
if (!next_token(&p, tok, ":", sizeof(tok))) {
DEBUG(0,("get_nss_info: no \":\" delimitier found\n"));
continue;
}
if (strequal(tok, domain_name)) {
enum wb_posix_mapping type;
if ((type = wb_posix_map_type(p)) == WB_POSIX_MAP_UNKNOWN) {
DEBUG(0,("get_nss_info: invalid setting: %s\n", p));
/* return WB_POSIX_MAP_TEMPLATE; */
continue;
}
DEBUG(11,("get_nss_info: using \"%s\" for domain: %s\n", p, tok));
return type;
}
}
return map_templ;
}
/**********************************************************************
**********************************************************************/
const char *wb_posix_map_str(enum wb_posix_mapping mtype)
{
switch (mtype) {
case WB_POSIX_MAP_TEMPLATE:
return "template";
case WB_POSIX_MAP_SFU:
return "sfu";
case WB_POSIX_MAP_RFC2307:
return "rfc2307";
case WB_POSIX_MAP_UNIXINFO:
return "unixinfo";
default:
break;
}
return NULL;
}
/**********************************************************************
Get idmap nss methods.
**********************************************************************/
static struct nss_function_entry *nss_get_backend(const char *name )
{
struct nss_function_entry *entry = backends;
for(entry = backends; entry; entry = entry->next) {
if ( strequal(entry->name, name) )
return entry;
}
return NULL;
}
/*********************************************************************
Allow a module to register itself as a backend.
**********************************************************************/
NTSTATUS smb_register_idmap_nss(int version, const char *name, struct nss_info_methods *methods)
{
struct nss_function_entry *entry;
if ((version != SMB_NSS_INFO_INTERFACE_VERSION)) {
DEBUG(0, ("smb_register_idmap_nss: Failed to register idmap_nss module.\n"
"The module was compiled against SMB_NSS_INFO_INTERFACE_VERSION %d,\n"
"current SMB_NSS_INFO_INTERFACE_VERSION is %d.\n"
"Please recompile against the current version of samba!\n",
version, SMB_NSS_INFO_INTERFACE_VERSION));
return NT_STATUS_OBJECT_TYPE_MISMATCH;
}
if (!name || !name[0] || !methods) {
DEBUG(0,("smb_register_idmap_nss: called with NULL pointer or empty name!\n"));
return NT_STATUS_INVALID_PARAMETER;
}
if ( nss_get_backend(name) ) {
DEBUG(0,("smb_register_idmap_nss: idmap module %s "
"already registered!\n", name));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
entry = SMB_XMALLOC_P(struct nss_function_entry);
entry->name = smb_xstrdup(name);
entry->methods = methods;
DLIST_ADD(backends, entry);
DEBUG(5, ("smb_register_idmap_nss: Successfully added idmap "
"nss backend '%s'\n", name));
return NT_STATUS_OK;
}
/********************************************************************
*******************************************************************/
static BOOL parse_nss_parm( const char *config, char **backend, char **domain )
{
char *p;
char *q;
int len;
*backend = *domain = NULL;
if ( !config )
return False;
p = strchr( config, ':' );
/* if no : then the string must be the backend name only */
if ( !p ) {
*backend = SMB_STRDUP( config );
return (*backend != NULL);
}
/* split the string and return the two parts */
if ( strlen(p+1) > 0 ) {
*domain = SMB_STRDUP( p+1 );
}
len = PTR_DIFF(p,config)+1;
if ( (q = SMB_MALLOC_ARRAY( char, len )) == NULL ) {
SAFE_FREE( *backend );
return False;
}
StrnCpy( q, config, len-1);
q[len-1] = '\0';
*backend = q;
return True;
}
/********************************************************************
Each nss backend must not store global state, but rather be able
to initialize the state on a per domain basis.
*******************************************************************/
NTSTATUS nss_init( const char **nss_list )
{
NTSTATUS status;
int i;
char *backend, *domain;
struct nss_function_entry *nss_backend;
struct nss_domain_entry *nss_domain;
/* The "template" backend should alqays be registered as it
is a static module */
if ( (nss_backend = nss_get_backend( "template" )) == NULL ) {
static_init_nss_info;
}
/* Create the list of nss_domains (loading any shared plugins
as necessary) */
for ( i=0; nss_list && nss_list[i]; i++ ) {
if ( !parse_nss_parm(nss_list[i], &backend, &domain) ) {
DEBUG(0,("nss_init: failed to parse \"%s\"!\n",
nss_list[0]));
continue;
}
/* validate the backend */
if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
/* attempt to register the backend */
status = smb_probe_module( "nss_info", backend );
if ( !NT_STATUS_IS_OK(status) ) {
continue;
}
/* try again */
if ( (nss_backend = nss_get_backend( backend )) == NULL ) {
DEBUG(0,("nss_init: unregistered backend %s!. Skipping\n",
backend));
continue;
}
}
/* fill in the nss_domain_entry and add it to the
list of domains */
nss_domain = TALLOC_ZERO_P( nss_domain_list, struct nss_domain_entry );
if ( !nss_domain ) {
DEBUG(0,("nss_init: talloc() failure!\n"));
return NT_STATUS_NO_MEMORY;
}
nss_domain->backend = nss_backend;
nss_domain->domain = talloc_strdup( nss_domain, domain );
status = nss_domain->backend->methods->init( nss_domain );
if ( NT_STATUS_IS_OK( status ) ) {
DLIST_ADD( nss_domain_list, nss_domain );
} else {
DEBUG(0,("nss_init: Failed to init backend for %s domain!\n",
nss_domain->domain));
}
/* cleanup */
SAFE_FREE( backend );
SAFE_FREE( domain );
}
if ( !nss_domain_list ) {
DEBUG(3,("nss_init: no nss backends configured. "
"Defaulting to \"template\".\n"));
/* we shouild default to use template here */
}
return NT_STATUS_OK;
}
/********************************************************************
*******************************************************************/
NTSTATUS nss_get_info( const char *domain, const DOM_SID *user_sid,
TALLOC_CTX *ctx,
ADS_STRUCT *ads, LDAPMessage *msg,
char **homedir, char **shell, char **gecos,
gid_t *p_gid)
{
struct nss_domain_entry *p;
struct nss_info_methods *m;
for ( p=nss_domain_list; p; p=p->next ) {
if ( strequal( p->domain, domain ) )
break;
}
/* If we didn't find a match, then use the default nss info */
if ( !p ) {
if ( !nss_domain_list ) {
return NT_STATUS_NOT_FOUND;
}
p = nss_domain_list;
}
m = p->backend->methods;
return m->get_nss_info( p, user_sid, ctx, ads, msg,
homedir, shell, gecos, p_gid );
}
/********************************************************************
*******************************************************************/
NTSTATUS nss_close( const char *parameters )
{
struct nss_domain_entry *p = nss_domain_list;
struct nss_domain_entry *q;
while ( p && p->backend && p->backend->methods ) {
/* close the backend */
p->backend->methods->close_fn();
/* free the memory */
q = p;
p = p->next;
TALLOC_FREE( q );
}
return NT_STATUS_OK;
}
/********************************************************************
Invoke the init function for a given domain's backend
*******************************************************************/
NTSTATUS idmap_nss_init_domain( const char *domain )
{
struct nss_domain_entry *p;
DEBUG(10,("idmap_nss_init_domain: Searching for %s's init() function\n",
domain));
for ( p=nss_domain_list; p; p=p->next ) {
if ( strequal( p->domain, domain ) ) {
DEBUG(10,("idmap_nss_init_domain: Calling init function for %s\n",
domain));
return p->backend->methods->init( p );
}
}
return NT_STATUS_NO_SUCH_DOMAIN;
}

View File

@ -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);
}

View 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. */

View 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;

View 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");

View 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)
{

View 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;

View File

@ -447,6 +447,7 @@ struct winbindd_response {
fstring full_name;
fstring homedir;
fstring shell;
uint32 primary_gid;
uint32 group_rid;
} user_info;
struct {

View 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;

View 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;