diff options
Diffstat (limited to 'source3/winbindd/idmap_ad_nss.c')
-rw-r--r-- | source3/winbindd/idmap_ad_nss.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/source3/winbindd/idmap_ad_nss.c b/source3/winbindd/idmap_ad_nss.c new file mode 100644 index 0000000..3120280 --- /dev/null +++ b/source3/winbindd/idmap_ad_nss.c @@ -0,0 +1,418 @@ +/* + * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts + * + * Unix SMB/CIFS implementation. + * + * Winbind ADS backend functions + * + * Copyright (C) Andrew Tridgell 2001 + * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003 + * Copyright (C) Gerald (Jerry) Carter 2004-2007 + * Copyright (C) Luke Howard 2001-2004 + * Copyright (C) Michael Adam 2008,2010 + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program 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, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "winbindd.h" +#include "../libds/common/flags.h" +#include "winbindd_ads.h" +#include "libads/ldap_schema.h" +#include "nss_info.h" +#include "idmap.h" +#include "../libcli/ldap/ldap_ndr.h" +#include "../libcli/security/security.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_IDMAP + +#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 { + ADS_STRUCT *ads; + struct posix_schema *ad_schema; + enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */ +}; + +/************************************************************************ + ***********************************************************************/ + +static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom) +{ + ADS_STATUS status; + struct idmap_ad_context * ctx; + + DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n", + dom->name)); + + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + + status = ads_idmap_cached_connection(dom->name, ctx, &ctx->ads); + if (!ADS_ERR_OK(status)) { + return status; + } + + /* if we have a valid ADS_STRUCT and the schema model is + defined, then we can return here. */ + + if ( ctx->ad_schema ) { + return ADS_SUCCESS; + } + + /* Otherwise, set the schema model */ + + if ( (ctx->ad_map_type == WB_POSIX_MAP_SFU) || + (ctx->ad_map_type == WB_POSIX_MAP_SFU20) || + (ctx->ad_map_type == WB_POSIX_MAP_RFC2307) ) + { + status = ads_check_posix_schema_mapping( + ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema); + if ( !ADS_ERR_OK(status) ) { + DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n")); + } + } + + return status; +} + +/* + * nss_info_{sfu,sfu20,rfc2307} + */ + +/************************************************************************ + Initialize the {sfu,sfu20,rfc2307} state + ***********************************************************************/ + +static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN"; +static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE"; +static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU"; +static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20"; +static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307"; +static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO"; + +static const char *ad_map_type_string(enum wb_posix_mapping map_type) +{ + switch (map_type) { + case WB_POSIX_MAP_TEMPLATE: + return wb_posix_map_template_string; + case WB_POSIX_MAP_SFU: + return wb_posix_map_sfu_string; + case WB_POSIX_MAP_SFU20: + return wb_posix_map_sfu20_string; + case WB_POSIX_MAP_RFC2307: + return wb_posix_map_rfc2307_string; + case WB_POSIX_MAP_UNIXINFO: + return wb_posix_map_unixinfo_string; + default: + return wb_posix_map_unknown_string; + } +} + +static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e, + enum wb_posix_mapping new_ad_map_type) +{ + struct idmap_domain *dom; + struct idmap_ad_context *ctx; + + if (e->state != NULL) { + dom = talloc_get_type(e->state, struct idmap_domain); + } else { + dom = talloc_zero(e, struct idmap_domain); + if (dom == NULL) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + e->state = dom; + } + + if (e->domain != NULL) { + dom->name = talloc_strdup(dom, e->domain); + if (dom->name == NULL) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + } + + if (dom->private_data != NULL) { + ctx = talloc_get_type(dom->private_data, + struct idmap_ad_context); + } else { + ctx = talloc_zero(dom, struct idmap_ad_context); + if (ctx == NULL) { + DEBUG(0, ("Out of memory!\n")); + return NT_STATUS_NO_MEMORY; + } + ctx->ad_map_type = WB_POSIX_MAP_RFC2307; + dom->private_data = ctx; + } + + if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) && + (ctx->ad_map_type != new_ad_map_type)) + { + DEBUG(2, ("nss_ad_generic_init: " + "Warning: overriding previously set posix map type " + "%s for domain %s with map type %s.\n", + ad_map_type_string(ctx->ad_map_type), + dom->name, + ad_map_type_string(new_ad_map_type))); + } + + ctx->ad_map_type = new_ad_map_type; + + return NT_STATUS_OK; +} + +static NTSTATUS nss_sfu_init( struct nss_domain_entry *e ) +{ + return nss_ad_generic_init(e, WB_POSIX_MAP_SFU); +} + +static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e ) +{ + return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20); +} + +static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e ) +{ + return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307); +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx, + struct nss_domain_entry *e, + const char *name, + char **alias) +{ + const char *attrs[] = {NULL, /* attr_uid */ + NULL }; + char *filter = NULL; + LDAPMessage *msg = NULL; + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + struct idmap_domain *dom; + struct idmap_ad_context *ctx = NULL; + + /* Check incoming parameters */ + + if ( !e || !e->domain || !name || !*alias) { + nt_status = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + /* Only do query if we are online */ + + if (idmap_is_offline()) { + nt_status = NT_STATUS_FILE_IS_OFFLINE; + goto done; + } + + dom = talloc_get_type(e->state, struct idmap_domain); + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + + ads_status = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(ads_status)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (!ctx->ad_schema) { + nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + goto done; + } + + attrs[0] = ctx->ad_schema->posix_uid_attr; + + filter = talloc_asprintf(mem_ctx, + "(sAMAccountName=%s)", + name); + if (!filter) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + + ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); + if (!ADS_ERR_OK(ads_status)) { + nt_status = ads_ntstatus(ads_status); + goto done; + } + + *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr); + + if (!*alias) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + nt_status = NT_STATUS_OK; + +done: + if (filter) { + talloc_destroy(filter); + } + if (msg) { + ads_msgfree(ctx->ads, msg); + } + + return nt_status; +} + +/********************************************************************** + *********************************************************************/ + +static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx, + struct nss_domain_entry *e, + const char *alias, + char **name ) +{ + const char *attrs[] = {"sAMAccountName", + NULL }; + char *filter = NULL; + LDAPMessage *msg = NULL; + ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); + NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; + char *username = NULL; + struct idmap_domain *dom; + struct idmap_ad_context *ctx = NULL; + + /* Check incoming parameters */ + + if ( !alias || !name) { + nt_status = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + /* Only do query if we are online */ + + if (idmap_is_offline()) { + nt_status = NT_STATUS_FILE_IS_OFFLINE; + goto done; + } + + dom = talloc_get_type(e->state, struct idmap_domain); + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + + ads_status = ad_idmap_cached_connection(dom); + if (!ADS_ERR_OK(ads_status)) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (!ctx->ad_schema) { + nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + goto done; + } + + filter = talloc_asprintf(mem_ctx, + "(%s=%s)", + ctx->ad_schema->posix_uid_attr, + alias); + if (!filter) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + + ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); + if (!ADS_ERR_OK(ads_status)) { + nt_status = ads_ntstatus(ads_status); + goto done; + } + + username = ads_pull_string(ctx->ads, mem_ctx, msg, + "sAMAccountName"); + if (!username) { + nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto done; + } + + *name = talloc_asprintf(mem_ctx, "%s\\%s", + lp_workgroup(), + username); + if (!*name) { + nt_status = NT_STATUS_NO_MEMORY; + goto done; + } + + nt_status = NT_STATUS_OK; + +done: + TALLOC_FREE(username); + TALLOC_FREE(filter); + if (msg) { + ads_msgfree(ctx->ads, msg); + } + + return nt_status; +} + +/************************************************************************ + Function dispatch tables for the idmap and nss plugins + ***********************************************************************/ + +/* The SFU and RFC2307 NSS plugins share everything but the init + function which sets the intended schema model to use */ + +static const struct nss_info_methods nss_rfc2307_methods = { + .init = nss_rfc2307_init, + .map_to_alias = nss_ad_map_to_alias, + .map_from_alias = nss_ad_map_from_alias, +}; + +static const struct nss_info_methods nss_sfu_methods = { + .init = nss_sfu_init, + .map_to_alias = nss_ad_map_to_alias, + .map_from_alias = nss_ad_map_from_alias, +}; + +static const struct nss_info_methods nss_sfu20_methods = { + .init = nss_sfu20_init, + .map_to_alias = nss_ad_map_to_alias, + .map_from_alias = nss_ad_map_from_alias, +}; + + + +/************************************************************************ + Initialize the plugins + ***********************************************************************/ + +NTSTATUS idmap_ad_nss_init(TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + + status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, + "rfc2307", &nss_rfc2307_methods); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, + "sfu", &nss_sfu_methods); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, + "sfu20", &nss_sfu20_methods); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} |