X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Fwinbindd%2Fidmap_ad.c;h=315a9444a19ae16f66d1cdf899c567d31504bd99;hb=7736e592ffd0664c75a9c9c5c476b3cc9ed1de75;hp=df1d3695ebb2dc84456b450ab5b192a76a56198b;hpb=db64deb6819b814ffb49901aa00ef8fb7e480787;p=sfrench%2Fsamba-autobuild%2F.git diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c index df1d3695ebb..315a9444a19 100644 --- a/source3/winbindd/idmap_ad.c +++ b/source3/winbindd/idmap_ad.c @@ -1,15 +1,7 @@ /* - * idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts + * idmap_ad: map between Active Directory and RFC 2307 accounts * - * Unix SMB/CIFS implementation. - * - * Winbind ADS backend functions - * - * Copyright (C) Andrew Tridgell 2001 - * Copyright (C) Andrew Bartlett 2003 - * Copyright (C) Gerald (Jerry) Carter 2004-2007 - * Copyright (C) Luke Howard 2001-2004 - * Copyright (C) Michael Adam 2008,2010 + * Copyright (C) Volker Lendecke 2015 * * 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 @@ -27,989 +19,949 @@ #include "includes.h" #include "winbindd.h" -#include "../libds/common/flags.h" -#include "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 +#include "tldap_gensec_bind.h" +#include "tldap_util.h" +#include "passdb.h" +#include "lib/param/param.h" +#include "utils/net.h" +#include "auth/gensec/gensec.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "libads/ldap_schema_oids.h" +#include "../libds/common/flags.h" +#include "libcli/ldap/ldap_ndr.h" +#include "libcli/security/dom_sid.h" -#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_schema_names; struct idmap_ad_context { - ADS_STRUCT *ads; - struct posix_schema *ad_schema; - enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */ + struct idmap_domain *dom; + struct tldap_context *ld; + struct idmap_ad_schema_names *schema; + const char *default_nc; + + bool unix_primary_group; + bool unix_nss_info; }; -/************************************************************************ - ***********************************************************************/ +static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom, + struct idmap_ad_context **pctx); -static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom) +static char *get_schema_path(TALLOC_CTX *mem_ctx, struct tldap_context *ld) { - 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); + struct tldap_message *rootdse; - status = ads_idmap_cached_connection(&ctx->ads, dom->name); - if (!ADS_ERR_OK(status)) { - return status; + rootdse = tldap_rootdse(ld); + if (rootdse == NULL) { + return NULL; } - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); - - /* 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; + return tldap_talloc_single_attribute(rootdse, "schemaNamingContext", + mem_ctx); } -static int idmap_ad_context_destructor(struct idmap_ad_context *ctx) +static char *get_default_nc(TALLOC_CTX *mem_ctx, struct tldap_context *ld) { - if (ctx->ads != NULL) { - /* we own this ADS_STRUCT so make sure it goes away */ - ctx->ads->is_mine = True; - ads_destroy( &ctx->ads ); - ctx->ads = NULL; + struct tldap_message *rootdse; + + rootdse = tldap_rootdse(ld); + if (rootdse == NULL) { + return NULL; } - return 0; + + return tldap_talloc_single_attribute(rootdse, "defaultNamingContext", + mem_ctx); } -/************************************************************************ - ***********************************************************************/ +struct idmap_ad_schema_names { + char *name; + char *uid; + char *gid; + char *gecos; + char *dir; + char *shell; +}; -static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom) +static TLDAPRC get_attrnames_by_oids(struct tldap_context *ld, + TALLOC_CTX *mem_ctx, + const char *schema_path, + size_t num_oids, + const char **oids, + char **names) { - struct idmap_ad_context *ctx; - char *config_option; - const char *schema_mode = NULL; - - ctx = talloc_zero(dom, struct idmap_ad_context); - if (ctx == NULL) { - DEBUG(0, ("Out of memory!\n")); - return NT_STATUS_NO_MEMORY; + char *filter; + const char *attrs[] = { "lDAPDisplayName", "attributeId" }; + size_t i; + TLDAPRC rc; + struct tldap_message **msgs; + size_t num_msgs; + + filter = talloc_strdup(mem_ctx, "(|"); + if (filter == NULL) { + return TLDAP_NO_MEMORY; + } + + for (i=0; iname); - if (config_option == NULL) { - DEBUG(0, ("Out of memory!\n")); - talloc_free(ctx); - return NT_STATUS_NO_MEMORY; + filter = talloc_asprintf_append_buffer(filter, ")"); + if (filter == NULL) { + return TLDAP_NO_MEMORY; } - /* default map type */ - ctx->ad_map_type = WB_POSIX_MAP_RFC2307; - - /* schema mode */ - schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL); - if ( schema_mode && schema_mode[0] ) { - if ( strequal(schema_mode, "sfu") ) - ctx->ad_map_type = WB_POSIX_MAP_SFU; - else if ( strequal(schema_mode, "sfu20" ) ) - ctx->ad_map_type = WB_POSIX_MAP_SFU20; - else if ( strequal(schema_mode, "rfc2307" ) ) - ctx->ad_map_type = WB_POSIX_MAP_RFC2307; - else - DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n", - schema_mode)); + rc = tldap_search(ld, schema_path, TLDAP_SCOPE_SUB, filter, + attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, + 0, 0, 0, mem_ctx, &msgs);; + TALLOC_FREE(filter); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + return rc; } - dom->private_data = ctx; - - talloc_free(config_option); - - return NT_STATUS_OK; -} - -/************************************************************************ - ***********************************************************************/ - -static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) -{ - NTSTATUS ret; - TALLOC_CTX *memctx; - struct idmap_ad_context *ctx; - ADS_STATUS rc; - const char *attrs[] = { "sAMAccountType", - "objectSid", - NULL, /* uidnumber */ - NULL, /* gidnumber */ - NULL }; - LDAPMessage *res = NULL; - LDAPMessage *entry = NULL; - char *filter = NULL; - int idx = 0; - int bidx = 0; - int count; - int i; - char *u_filter = NULL; - char *g_filter = NULL; - - /* initialize the status to avoid suprise */ - for (i = 0; ids[i]; i++) { - ids[i]->status = ID_UNKNOWN; + for (i=0; iprivate_data, struct idmap_ad_context); + for (i=0; iad_schema->posix_uidnumber_attr; - attrs[3] = ctx->ad_schema->posix_gidnumber_attr; - -again: - bidx = idx; - for (i = 0; (i < IDMAP_LDAP_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_buffer(u_filter, "(%s=%lu)", - ctx->ad_schema->posix_uidnumber_attr, - (unsigned long)ids[idx]->xid.id); - CHECK_ALLOC_DONE(u_filter); - break; + oid = tldap_talloc_single_attribute( + msg, "attributeId", msg); + if (oid == NULL) { + continue; + } - case ID_TYPE_GID: - if ( ! g_filter) { - g_filter = talloc_asprintf(memctx, "(&(|" - "(sAMAccountType=%d)" - "(sAMAccountType=%d))(|", - ATYPE_SECURITY_GLOBAL_GROUP, - ATYPE_SECURITY_LOCAL_GROUP); + for (j=0; jad_schema->posix_gidnumber_attr, - (unsigned long)ids[idx]->xid.id); - CHECK_ALLOC_DONE(g_filter); - break; + } + TALLOC_FREE(oid); - default: - DEBUG(3, ("Error: mapping requested but Unknown ID type\n")); - ids[idx]->status = ID_UNKNOWN; + if (j == num_oids) { + /* not found */ continue; } - } - filter = talloc_asprintf(memctx, "(|"); - CHECK_ALLOC_DONE(filter); - if ( u_filter) { - filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter); - CHECK_ALLOC_DONE(filter); - TALLOC_FREE(u_filter); - } - if ( g_filter) { - filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter); - CHECK_ALLOC_DONE(filter); - TALLOC_FREE(g_filter); - } - filter = talloc_asprintf_append_buffer(filter, ")"); - CHECK_ALLOC_DONE(filter); - rc = ads_search_retry(ctx->ads, &res, filter, attrs); - if (!ADS_ERR_OK(rc)) { - DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc))); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; + names[j] = tldap_talloc_single_attribute( + msg, "lDAPDisplayName", mem_ctx); } - if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) { - DEBUG(10, ("No IDs found\n")); - } + TALLOC_FREE(msgs); - entry = res; - for (i = 0; (i < count) && entry; i++) { - struct dom_sid sid; - enum id_type type; - struct id_map *map; - uint32_t id; - uint32_t atype; - - if (i == 0) { /* first entry */ - entry = ads_first_entry(ctx->ads, entry); - } else { /* following ones */ - entry = ads_next_entry(ctx->ads, entry); - } + return TLDAP_SUCCESS; +} - if ( !entry ) { - DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); - break; +static TLDAPRC get_posix_schema_names(struct tldap_context *ld, + const char *schema_mode, + TALLOC_CTX *mem_ctx, + struct idmap_ad_schema_names **pschema) +{ + char *schema_path; + struct idmap_ad_schema_names *schema; + char *names[6]; + const char *oids_sfu[] = { + ADS_ATTR_SFU_UIDNUMBER_OID, + ADS_ATTR_SFU_GIDNUMBER_OID, + ADS_ATTR_SFU_HOMEDIR_OID, + ADS_ATTR_SFU_SHELL_OID, + ADS_ATTR_SFU_GECOS_OID, + ADS_ATTR_SFU_UID_OID + }; + const char *oids_sfu20[] = { + ADS_ATTR_SFU20_UIDNUMBER_OID, + ADS_ATTR_SFU20_GIDNUMBER_OID, + ADS_ATTR_SFU20_HOMEDIR_OID, + ADS_ATTR_SFU20_SHELL_OID, + ADS_ATTR_SFU20_GECOS_OID, + ADS_ATTR_SFU20_UID_OID + }; + const char *oids_rfc2307[] = { + ADS_ATTR_RFC2307_UIDNUMBER_OID, + ADS_ATTR_RFC2307_GIDNUMBER_OID, + ADS_ATTR_RFC2307_HOMEDIR_OID, + ADS_ATTR_RFC2307_SHELL_OID, + ADS_ATTR_RFC2307_GECOS_OID, + ADS_ATTR_RFC2307_UID_OID + }; + const char **oids; + + TLDAPRC rc; + + schema = talloc(mem_ctx, struct idmap_ad_schema_names); + if (schema == NULL) { + return TLDAP_NO_MEMORY; + } + + schema_path = get_schema_path(schema, ld); + if (schema_path == NULL) { + TALLOC_FREE(schema); + return TLDAP_NO_MEMORY; + } + + oids = oids_rfc2307; + + if ((schema_mode != NULL) && (schema_mode[0] != '\0')) { + if (strequal(schema_mode, "sfu")) { + oids = oids_sfu; + } else if (strequal(schema_mode, "sfu20")) { + oids = oids_sfu20; + } else if (strequal(schema_mode, "rfc2307" )) { + oids = oids_rfc2307; + } else { + DBG_WARNING("Unknown schema mode %s\n", schema_mode); } + } - /* first check if the SID is present */ - if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) { - DEBUG(2, ("Could not retrieve SID from entry\n")); - continue; - } + rc = get_attrnames_by_oids(ld, schema, schema_path, 6, oids, names); + TALLOC_FREE(schema_path); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + TALLOC_FREE(schema); + return rc; + } - /* get type */ - if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) { - DEBUG(1, ("could not get SAM account type\n")); - continue; - } + schema->uid = names[0]; + schema->gid = names[1]; + schema->dir = names[2]; + schema->shell = names[3]; + schema->gecos = names[4]; + schema->name = names[5]; - switch (atype & 0xF0000000) { - case ATYPE_SECURITY_GLOBAL_GROUP: - case ATYPE_SECURITY_LOCAL_GROUP: - type = ID_TYPE_GID; - break; - case ATYPE_NORMAL_ACCOUNT: - case ATYPE_WORKSTATION_TRUST: - case ATYPE_INTERDOMAIN_TRUST: - type = ID_TYPE_UID; - break; - default: - DEBUG(1, ("unrecognized SAM account type %08x\n", atype)); - continue; - } + *pschema = schema; - if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ? - ctx->ad_schema->posix_uidnumber_attr : - ctx->ad_schema->posix_gidnumber_attr, - &id)) - { - DEBUG(1, ("Could not get SID for unix ID %u\n", (unsigned) id)); - continue; - } + return TLDAP_SUCCESS; +} - if (!idmap_unix_id_is_in_range(id, dom)) { - DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", - id, dom->low_id, dom->high_id)); - continue; - } +static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx, + const char *domname, + struct tldap_context **pld) +{ + struct netr_DsRGetDCNameInfo *dcinfo; + struct sockaddr_storage dcaddr; + struct cli_credentials *creds; + struct loadparm_context *lp_ctx; + struct tldap_context *ld; + int fd; + NTSTATUS status; + bool ok; + TLDAPRC rc; + + status = wb_dsgetdcname_gencache_get(mem_ctx, domname, &dcinfo); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("Could not get dcinfo for %s: %s\n", domname, + nt_errstr(status)); + return status; + } - map = idmap_find_map_by_id(&ids[bidx], type, id); - if (!map) { - DEBUG(2, ("WARNING: couldn't match result with requested ID\n")); - continue; - } + if (dcinfo->dc_unc == NULL) { + TALLOC_FREE(dcinfo); + return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + } + if (dcinfo->dc_unc[0] == '\\') { + dcinfo->dc_unc += 1; + } + if (dcinfo->dc_unc[0] == '\\') { + dcinfo->dc_unc += 1; + } - sid_copy(map->sid, &sid); + ok = resolve_name(dcinfo->dc_unc, &dcaddr, 0x20, true); + if (!ok) { + DBG_DEBUG("Could not resolve name %s\n", dcinfo->dc_unc); + TALLOC_FREE(dcinfo); + return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + } - /* mapped */ - map->status = ID_MAPPED; + status = open_socket_out(&dcaddr, 389, 10000, &fd); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("open_socket_out failed: %s\n", nt_errstr(status)); + TALLOC_FREE(dcinfo); + return status; + } - DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid), - (unsigned long)map->xid.id, - map->xid.type)); + ld = tldap_context_create(dcinfo, fd); + if (ld == NULL) { + DBG_DEBUG("tldap_context_create failed\n"); + close(fd); + TALLOC_FREE(dcinfo); + return NT_STATUS_NO_MEMORY; } - if (res) { - ads_msgfree(ctx->ads, res); + /* + * Here we use or own machine account as + * we run as domain member. + */ + status = pdb_get_trust_credentials(lp_workgroup(), + lp_realm(), + dcinfo, + &creds); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("pdb_get_trust_credentials() failed - %s\n", + nt_errstr(status)); + TALLOC_FREE(dcinfo); + return status; } - if (ids[idx]) { /* still some values to map */ - goto again; + lp_ctx = loadparm_init_s3(dcinfo, loadparm_s3_helpers()); + if (lp_ctx == NULL) { + DBG_DEBUG("loadparm_init_s3 failed\n"); + TALLOC_FREE(dcinfo); + return NT_STATUS_NO_MEMORY; } - ret = NT_STATUS_OK; + rc = tldap_gensec_bind(ld, creds, "ldap", dcinfo->dc_unc, NULL, lp_ctx, + GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + DBG_DEBUG("tldap_gensec_bind failed: %s\n", + tldap_errstr(dcinfo, ld, rc)); + TALLOC_FREE(dcinfo); + return NT_STATUS_LDAP(TLDAP_RC_V(rc)); + } - /* mark all unknown/expired ones as unmapped */ - for (i = 0; ids[i]; i++) { - if (ids[i]->status != ID_MAPPED) - ids[i]->status = ID_UNMAPPED; + rc = tldap_fetch_rootdse(ld); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + DBG_DEBUG("tldap_fetch_rootdse failed: %s\n", + tldap_errstr(dcinfo, ld, rc)); + TALLOC_FREE(dcinfo); + return NT_STATUS_LDAP(TLDAP_RC_V(rc)); } -done: - talloc_free(memctx); - return ret; + *pld = talloc_move(mem_ctx, &ld); + TALLOC_FREE(dcinfo); + return NT_STATUS_OK; } -/************************************************************************ - ***********************************************************************/ +static int idmap_ad_context_destructor(struct idmap_ad_context *ctx) +{ + if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) { + ctx->dom->private_data = NULL; + } + return 0; +} -static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids) +static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx, + struct idmap_domain *dom, + const char *domname, + struct idmap_ad_context **pctx) { - NTSTATUS ret; - TALLOC_CTX *memctx; struct idmap_ad_context *ctx; - ADS_STATUS rc; - const char *attrs[] = { "sAMAccountType", - "objectSid", - NULL, /* attr_uidnumber */ - NULL, /* attr_gidnumber */ - NULL }; - LDAPMessage *res = NULL; - LDAPMessage *entry = NULL; - char *filter = NULL; - int idx = 0; - int bidx = 0; - int count; - int i; - char *sidstr; - - /* initialize the status to avoid suprise */ - for (i = 0; ids[i]; i++) { - ids[i]->status = ID_UNKNOWN; - } + const char *schema_mode; + NTSTATUS status; + TLDAPRC rc; - /* Only do query if we are online */ - if (idmap_is_offline()) { - return NT_STATUS_FILE_IS_OFFLINE; + ctx = talloc(mem_ctx, struct idmap_ad_context); + if (ctx == NULL) { + return NT_STATUS_NO_MEMORY; } + ctx->dom = dom; - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + talloc_set_destructor(ctx, idmap_ad_context_destructor); - if ( (memctx = talloc_new(ctx)) == NULL ) { - DEBUG(0, ("Out of memory!\n")); - return NT_STATUS_NO_MEMORY; + status = idmap_ad_get_tldap_ctx(ctx, domname, &ctx->ld); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("idmap_ad_get_tldap_ctx failed: %s\n", + nt_errstr(status)); + TALLOC_FREE(ctx); + return status; } - rc = ad_idmap_cached_connection(dom); - if (!ADS_ERR_OK(rc)) { - DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc))); - ret = NT_STATUS_UNSUCCESSFUL; - /* ret = ads_ntstatus(rc); */ - goto done; + ctx->default_nc = get_default_nc(ctx, ctx->ld); + if (ctx->default_nc == NULL) { + DBG_DEBUG("No default nc\n"); + TALLOC_FREE(ctx); + return status; } - if (ctx->ad_schema == NULL) { - DEBUG(0, ("haven't got ctx->ad_schema ! \n")); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; - } + ctx->unix_primary_group = idmap_config_bool( + domname, "unix_primary_group", false); + ctx->unix_nss_info = idmap_config_bool( + domname, "unix_nss_info", false); - attrs[2] = ctx->ad_schema->posix_uidnumber_attr; - attrs[3] = ctx->ad_schema->posix_gidnumber_attr; + schema_mode = idmap_config_const_string( + domname, "schema_mode", "rfc2307"); -again: - 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); + rc = get_posix_schema_names(ctx->ld, schema_mode, ctx, &ctx->schema); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + DBG_DEBUG("get_posix_schema_names failed: %s\n", + tldap_errstr(ctx, ctx->ld, rc)); + TALLOC_FREE(ctx); + return NT_STATUS_LDAP(TLDAP_RC_V(rc)); + } - CHECK_ALLOC_DONE(filter); + *pctx = ctx; + return NT_STATUS_OK; +} - bidx = idx; - for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) { +static NTSTATUS idmap_ad_query_user(struct idmap_domain *domain, + struct wbint_userinfo *info) +{ + struct idmap_ad_context *ctx; + TLDAPRC rc; + NTSTATUS status; + char *sidstr, *filter; + const char *attrs[4]; + size_t i, num_msgs; + struct tldap_message **msgs; + + status = idmap_ad_get_context(domain, &ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - ids[idx]->status = ID_UNKNOWN; + if (!(ctx->unix_primary_group || ctx->unix_nss_info)) { + return NT_STATUS_OK; + } - sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[idx]->sid); - filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr); + attrs[0] = ctx->schema->gid; + attrs[1] = ctx->schema->gecos; + attrs[2] = ctx->schema->dir; + attrs[3] = ctx->schema->shell; - TALLOC_FREE(sidstr); - CHECK_ALLOC_DONE(filter); + sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), &info->user_sid); + if (sidstr == NULL) { + return NT_STATUS_NO_MEMORY; } - filter = talloc_asprintf_append_buffer(filter, "))"); - CHECK_ALLOC_DONE(filter); - DEBUG(10, ("Filter: [%s]\n", filter)); - rc = ads_search_retry(ctx->ads, &res, filter, attrs); - if (!ADS_ERR_OK(rc)) { - DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc))); - ret = NT_STATUS_UNSUCCESSFUL; - goto done; + filter = talloc_asprintf(talloc_tos(), "(objectsid=%s)", sidstr); + TALLOC_FREE(sidstr); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; } - if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) { - DEBUG(10, ("No IDs found\n")); + DBG_DEBUG("Filter: [%s]\n", filter); + + rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter, + attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, + 0, 0, 0, talloc_tos(), &msgs); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + return NT_STATUS_LDAP(TLDAP_RC_V(rc)); } - entry = res; - for (i = 0; (i < count) && entry; i++) { - struct dom_sid sid; - enum id_type type; - struct id_map *map; - uint32_t id; - uint32_t atype; + TALLOC_FREE(filter); - if (i == 0) { /* first entry */ - entry = ads_first_entry(ctx->ads, entry); - } else { /* following ones */ - entry = ads_next_entry(ctx->ads, entry); - } + num_msgs = talloc_array_length(msgs); - if ( !entry ) { - DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); - break; - } + for (i=0; iads, entry, "objectSid", &sid)) { - DEBUG(2, ("Could not retrieve SID from entry\n")); + if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) { continue; } - map = idmap_find_map_by_sid(&ids[bidx], &sid); - if (!map) { - DEBUG(2, ("WARNING: couldn't match result with requested SID\n")); - continue; - } + if (ctx->unix_primary_group) { + bool ok; + uint32_t gid; - /* get type */ - if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) { - DEBUG(1, ("could not get SAM account type\n")); - continue; + ok = tldap_pull_uint32(msg, ctx->schema->gid, &gid); + if (ok) { + DBG_DEBUG("Setting primary group " + "to %"PRIu32" from attr %s\n", + gid, ctx->schema->gid); + info->primary_gid = gid; + } } - switch (atype & 0xF0000000) { - case ATYPE_SECURITY_GLOBAL_GROUP: - case ATYPE_SECURITY_LOCAL_GROUP: - type = ID_TYPE_GID; - break; - case ATYPE_NORMAL_ACCOUNT: - case ATYPE_WORKSTATION_TRUST: - case ATYPE_INTERDOMAIN_TRUST: - type = ID_TYPE_UID; - break; - default: - DEBUG(1, ("unrecognized SAM account type %08x\n", atype)); - continue; - } + if (ctx->unix_nss_info) { + char *attr; - if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ? - ctx->ad_schema->posix_uidnumber_attr : - ctx->ad_schema->posix_gidnumber_attr, - &id)) - { - DEBUG(1, ("Could not get unix ID for SID %s\n", - sid_string_dbg(map->sid))); - continue; - } - if (!idmap_unix_id_is_in_range(id, dom)) { - DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n", - id, dom->low_id, dom->high_id)); - continue; - } + attr = tldap_talloc_single_attribute( + msg, ctx->schema->dir, talloc_tos()); + if (attr != NULL) { + info->homedir = talloc_move(info, &attr); + } + TALLOC_FREE(attr); - /* mapped */ - map->xid.type = type; - map->xid.id = id; - map->status = ID_MAPPED; + attr = tldap_talloc_single_attribute( + msg, ctx->schema->shell, talloc_tos()); + if (attr != NULL) { + info->shell = talloc_move(info, &attr); + } + TALLOC_FREE(attr); - DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid), - (unsigned long)map->xid.id, - map->xid.type)); + attr = tldap_talloc_single_attribute( + msg, ctx->schema->gecos, talloc_tos()); + if (attr != NULL) { + info->full_name = talloc_move(info, &attr); + } + TALLOC_FREE(attr); + } } - if (res) { - ads_msgfree(ctx->ads, res); - } + return NT_STATUS_OK; +} - if (ids[idx]) { /* still some values to map */ - goto again; - } +static NTSTATUS idmap_ad_query_user_retry(struct idmap_domain *domain, + struct wbint_userinfo *info) +{ + const NTSTATUS status_server_down = + NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN)); + NTSTATUS status; - ret = NT_STATUS_OK; + status = idmap_ad_query_user(domain, info); - /* mark all unknown/expired ones as unmapped */ - for (i = 0; ids[i]; i++) { - if (ids[i]->status != ID_MAPPED) - ids[i]->status = ID_UNMAPPED; + if (NT_STATUS_EQUAL(status, status_server_down)) { + TALLOC_FREE(domain->private_data); + status = idmap_ad_query_user(domain, info); } -done: - talloc_free(memctx); - return ret; + 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) +static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom) { - 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; - } + dom->query_user = idmap_ad_query_user_retry; + dom->private_data = NULL; + return NT_STATUS_OK; } -static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e, - enum wb_posix_mapping new_ad_map_type) +static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom, + struct idmap_ad_context **pctx) { - 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; - } - } + struct idmap_ad_context *ctx = NULL; + NTSTATUS status; 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; + *pctx = talloc_get_type_abort(dom->private_data, + struct idmap_ad_context); + return NT_STATUS_OK; } - 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))); + status = idmap_ad_context_create(dom, dom, dom->name, &ctx); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("idmap_ad_context_create failed: %s\n", + nt_errstr(status)); + return status; } - ctx->ad_map_type = new_ad_map_type; - + dom->private_data = ctx; + *pctx = ctx; 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 ) +static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, + struct id_map **ids) { - return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307); -} + struct idmap_ad_context *ctx; + TLDAPRC rc; + NTSTATUS status; + struct tldap_message **msgs; + + size_t i, num_msgs; + char *u_filter, *g_filter, *filter; + + const char *attrs[] = { + "sAMAccountType", + "objectSid", + NULL, /* attr_uidnumber */ + NULL, /* attr_gidnumber */ + }; + + status = idmap_ad_get_context(dom, &ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + attrs[2] = ctx->schema->uid; + attrs[3] = ctx->schema->gid; -/************************************************************************ - ***********************************************************************/ + u_filter = talloc_strdup(talloc_tos(), ""); + if (u_filter == NULL) { + return NT_STATUS_NO_MEMORY; + } -static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, - const struct dom_sid *sid, - TALLOC_CTX *mem_ctx, - const char **homedir, - const char **shell, - const char **gecos, - gid_t *p_gid ) -{ - const char *attrs[] = {NULL, /* attr_homedir */ - NULL, /* attr_shell */ - NULL, /* attr_gecos */ - NULL, /* attr_gidnumber */ - NULL }; - char *filter = NULL; - LDAPMessage *msg_internal = NULL; - ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL); - NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; - char *sidstr = NULL; - struct idmap_domain *dom; - struct idmap_ad_context *ctx; + g_filter = talloc_strdup(talloc_tos(), ""); + if (g_filter == NULL) { + return NT_STATUS_NO_MEMORY; + } - DEBUG(10, ("nss_ad_get_info called for sid [%s] in domain '%s'\n", - sid_string_dbg(sid), e->domain?e->domain:"NULL")); + for (i=0; ids[i] != NULL; i++) { + struct id_map *id = ids[i]; + + id->status = ID_UNKNOWN; + + switch (id->xid.type) { + case ID_TYPE_UID: { + u_filter = talloc_asprintf_append_buffer( + u_filter, "(%s=%ju)", ctx->schema->uid, + (uintmax_t)id->xid.id); + if (u_filter == NULL) { + return NT_STATUS_NO_MEMORY; + } + break; + } + + case ID_TYPE_GID: { + g_filter = talloc_asprintf_append_buffer( + g_filter, "(%s=%ju)", ctx->schema->gid, + (uintmax_t)id->xid.id); + if (g_filter == NULL) { + return NT_STATUS_NO_MEMORY; + } + break; + } + + default: + DBG_WARNING("Unknown id type: %u\n", + (unsigned)id->xid.type); + break; + } + } - /* Only do query if we are online */ - if (idmap_is_offline()) { - return NT_STATUS_FILE_IS_OFFLINE; + filter = talloc_strdup(talloc_tos(), "(|"); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; } - dom = talloc_get_type(e->state, struct idmap_domain); - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + if (*u_filter != '\0') { + filter = talloc_asprintf_append_buffer( + filter, + "(&(|(sAMAccountType=%d)(sAMAccountType=%d)" + "(sAMAccountType=%d))(|%s))", + ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, + ATYPE_INTERDOMAIN_TRUST, u_filter); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + TALLOC_FREE(u_filter); - ads_status = ad_idmap_cached_connection(dom); - if (!ADS_ERR_OK(ads_status)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + if (*g_filter != '\0') { + filter = talloc_asprintf_append_buffer( + filter, + "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(|%s))", + ATYPE_SECURITY_GLOBAL_GROUP, + ATYPE_SECURITY_LOCAL_GROUP, + g_filter); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; + } } + TALLOC_FREE(g_filter); - if (!ctx->ad_schema) { - DEBUG(10, ("nss_ad_get_info: no ad_schema configured!\n")); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + filter = talloc_asprintf_append_buffer(filter, ")"); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; } - if (!sid || !homedir || !shell || !gecos) { - return NT_STATUS_INVALID_PARAMETER; + DBG_DEBUG("Filter: [%s]\n", filter); + + rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter, + attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, + 0, 0, 0, talloc_tos(), &msgs); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + return NT_STATUS_LDAP(TLDAP_RC_V(rc)); } - /* Have to do our own query */ + TALLOC_FREE(filter); - DEBUG(10, ("nss_ad_get_info: no ads connection given, doing our " - "own query\n")); + num_msgs = talloc_array_length(msgs); - attrs[0] = ctx->ad_schema->posix_homedir_attr; - attrs[1] = ctx->ad_schema->posix_shell_attr; - attrs[2] = ctx->ad_schema->posix_gecos_attr; - attrs[3] = ctx->ad_schema->posix_gidnumber_attr; + for (i=0; iads, &msg_internal, filter, attrs); - if (!ADS_ERR_OK(ads_status)) { - nt_status = ads_ntstatus(ads_status); - goto done; - } + ok = tldap_pull_uint32(msg, "sAMAccountType", &atype); + if (!ok) { + DBG_DEBUG("No atype in object %s\n", dn); + continue; + } - *homedir = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_homedir_attr); - *shell = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_shell_attr); - *gecos = ads_pull_string(ctx->ads, mem_ctx, msg_internal, ctx->ad_schema->posix_gecos_attr); + switch (atype & 0xF0000000) { + case ATYPE_SECURITY_GLOBAL_GROUP: + case ATYPE_SECURITY_LOCAL_GROUP: + type = ID_TYPE_GID; + break; + case ATYPE_NORMAL_ACCOUNT: + case ATYPE_WORKSTATION_TRUST: + case ATYPE_INTERDOMAIN_TRUST: + type = ID_TYPE_UID; + break; + default: + DBG_WARNING("unrecognized SAM account type %08x\n", + atype); + continue; + } - if (p_gid != NULL) { - uint32_t gid = UINT32_MAX; - bool ok; + ok = tldap_pull_uint32(msg, (type == ID_TYPE_UID) ? + ctx->schema->uid : ctx->schema->gid, + &xid); + if (!ok) { + DBG_WARNING("No unix id in object %s\n", dn); + continue; + } - ok = ads_pull_uint32(ctx->ads, msg_internal, - ctx->ad_schema->posix_gidnumber_attr, - &gid); - if (ok) { - *p_gid = gid; - } else { - *p_gid = (gid_t)-1; + ok = tldap_pull_binsid(msg, "objectSid", &sid); + if (!ok) { + DBG_DEBUG("No objectSid in object %s\n", dn); + continue; + } + + map = NULL; + for (j=0; ids[j]; j++) { + if ((type == ids[j]->xid.type) && + (xid == ids[j]->xid.id)) { + map = ids[j]; + break; + } + } + if (map == NULL) { + DBG_DEBUG("Got unexpected sid %s from object %s\n", + sid_string_tos(&sid), dn); + continue; } - } - nt_status = NT_STATUS_OK; + sid_copy(map->sid, &sid); + map->status = ID_MAPPED; -done: - if (msg_internal) { - ads_msgfree(ctx->ads, msg_internal); + DBG_DEBUG("Mapped %s -> %ju (%d)\n", sid_string_dbg(map->sid), + (uintmax_t)map->xid.id, map->xid.type); } - return nt_status; -} + TALLOC_FREE(msgs); -/********************************************************************** - *********************************************************************/ + return NT_STATUS_OK; +} -static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx, - struct nss_domain_entry *e, - const char *name, - char **alias) +static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, + struct id_map **ids) { - 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; + struct idmap_ad_context *ctx; + TLDAPRC rc; + NTSTATUS status; + struct tldap_message **msgs; + + char *filter; + size_t i, num_msgs; + + const char *attrs[] = { + "sAMAccountType", + "objectSid", + NULL, /* attr_uidnumber */ + NULL, /* attr_gidnumber */ + }; + + status = idmap_ad_get_context(dom, &ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - /* Check incoming parameters */ + attrs[2] = ctx->schema->uid; + attrs[3] = ctx->schema->gid; - if ( !e || !e->domain || !name || !*alias) { - nt_status = NT_STATUS_INVALID_PARAMETER; - goto done; + filter = talloc_asprintf( + talloc_tos(), + "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" + "(sAMAccountType=%d)(sAMAccountType=%d))(|", + ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, + ATYPE_INTERDOMAIN_TRUST, ATYPE_SECURITY_GLOBAL_GROUP, + ATYPE_SECURITY_LOCAL_GROUP); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; } - /* Only do query if we are online */ + for (i=0; ids[i]; i++) { + char *sidstr; - if (idmap_is_offline()) { - nt_status = NT_STATUS_FILE_IS_OFFLINE; - goto done; - } + ids[i]->status = ID_UNKNOWN; - dom = talloc_get_type(e->state, struct idmap_domain); - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[i]->sid); + if (sidstr == NULL) { + return NT_STATUS_NO_MEMORY; + } - ads_status = ad_idmap_cached_connection(dom); - if (!ADS_ERR_OK(ads_status)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; + filter = talloc_asprintf_append_buffer( + filter, "(objectSid=%s)", sidstr); + TALLOC_FREE(sidstr); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; + } } - if (!ctx->ad_schema) { - nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto done; + filter = talloc_asprintf_append_buffer(filter, "))"); + if (filter == NULL) { + return NT_STATUS_NO_MEMORY; } - attrs[0] = ctx->ad_schema->posix_uid_attr; + DBG_DEBUG("Filter: [%s]\n", filter); - filter = talloc_asprintf(mem_ctx, - "(sAMAccountName=%s)", - name); - if (!filter) { - nt_status = NT_STATUS_NO_MEMORY; - goto done; + rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter, + attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, + 0, 0, 0, talloc_tos(), &msgs); + if (!TLDAP_RC_IS_SUCCESS(rc)) { + return NT_STATUS_LDAP(TLDAP_RC_V(rc)); } - ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); - if (!ADS_ERR_OK(ads_status)) { - nt_status = ads_ntstatus(ads_status); - goto done; - } + TALLOC_FREE(filter); - *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr); + num_msgs = talloc_array_length(msgs); - if (!*alias) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } + for (i=0; iads, msg); - } + ok = tldap_entry_dn(msg, &dn); + if (!ok) { + DBG_DEBUG("No dn found in msg %zu\n", i); + continue; + } - return nt_status; -} + ok = tldap_pull_binsid(msg, "objectSid", &sid); + if (!ok) { + DBG_DEBUG("No objectSid in object %s\n", dn); + continue; + } -/********************************************************************** - *********************************************************************/ + map = NULL; + for (j=0; ids[j]; j++) { + if (dom_sid_equal(&sid, ids[j]->sid)) { + map = ids[j]; + break; + } + } + if (map == NULL) { + DBG_DEBUG("Got unexpected sid %s from object %s\n", + sid_string_tos(&sid), dn); + continue; + } -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; - struct idmap_domain *dom; - struct idmap_ad_context *ctx = NULL; + ok = tldap_pull_uint64(msg, "sAMAccountType", &account_type); + if (!ok) { + DBG_DEBUG("No sAMAccountType in %s\n", dn); + continue; + } - /* Check incoming parameters */ + switch (account_type & 0xF0000000) { + case ATYPE_SECURITY_GLOBAL_GROUP: + case ATYPE_SECURITY_LOCAL_GROUP: + type = ID_TYPE_GID; + break; + case ATYPE_NORMAL_ACCOUNT: + case ATYPE_WORKSTATION_TRUST: + case ATYPE_INTERDOMAIN_TRUST: + type = ID_TYPE_UID; + break; + default: + DBG_WARNING("unrecognized SAM account type %"PRIu64"\n", + account_type); + continue; + } - if ( !alias || !name) { - nt_status = NT_STATUS_INVALID_PARAMETER; - goto done; - } + ok = tldap_pull_uint64(msg, + type == ID_TYPE_UID ? + ctx->schema->uid : ctx->schema->gid, + &xid); + if (!ok) { + DBG_DEBUG("No xid in %s\n", dn); + continue; + } - /* Only do query if we are online */ + /* mapped */ + map->xid.type = type; + map->xid.id = xid; + map->status = ID_MAPPED; - if (idmap_is_offline()) { - nt_status = NT_STATUS_FILE_IS_OFFLINE; - goto done; + DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid), + (unsigned long)map->xid.id, map->xid.type)); } - dom = talloc_get_type(e->state, struct idmap_domain); - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + TALLOC_FREE(msgs); - ads_status = ad_idmap_cached_connection(dom); - if (!ADS_ERR_OK(ads_status)) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } + return NT_STATUS_OK; +} - if (!ctx->ad_schema) { - nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto done; - } +static NTSTATUS idmap_ad_unixids_to_sids_retry(struct idmap_domain *dom, + struct id_map **ids) +{ + const NTSTATUS status_server_down = + NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN)); + NTSTATUS status; - filter = talloc_asprintf(mem_ctx, - "(%s=%s)", - ctx->ad_schema->posix_uid_attr, - alias); - if (!filter) { - nt_status = NT_STATUS_NO_MEMORY; - goto done; - } + status = idmap_ad_unixids_to_sids(dom, ids); - ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs); - if (!ADS_ERR_OK(ads_status)) { - nt_status = ads_ntstatus(ads_status); - goto done; + if (NT_STATUS_EQUAL(status, status_server_down)) { + TALLOC_FREE(dom->private_data); + status = idmap_ad_unixids_to_sids(dom, ids); } - username = ads_pull_string(ctx->ads, mem_ctx, msg, - "sAMAccountName"); - if (!username) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } + return status; +} - *name = talloc_asprintf(mem_ctx, "%s\\%s", - lp_workgroup(), - username); - if (!*name) { - nt_status = NT_STATUS_NO_MEMORY; - goto done; - } +static NTSTATUS idmap_ad_sids_to_unixids_retry(struct idmap_domain *dom, + struct id_map **ids) +{ + const NTSTATUS status_server_down = + NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN)); + NTSTATUS status; - nt_status = NT_STATUS_OK; + status = idmap_ad_sids_to_unixids(dom, ids); -done: - if (filter) { - talloc_destroy(filter); - } - if (msg) { - ads_msgfree(ctx->ads, msg); + if (NT_STATUS_EQUAL(status, status_server_down)) { + TALLOC_FREE(dom->private_data); + status = idmap_ad_sids_to_unixids(dom, ids); } - return nt_status; + return status; } -/************************************************************************ - 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, -}; - -/* 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, - .map_to_alias = nss_ad_map_to_alias, - .map_from_alias = nss_ad_map_from_alias, + .unixids_to_sids = idmap_ad_unixids_to_sids_retry, + .sids_to_unixids = idmap_ad_sids_to_unixids_retry, }; -static struct nss_info_methods nss_sfu_methods = { - .init = nss_sfu_init, - .get_nss_info = nss_ad_get_info, - .map_to_alias = nss_ad_map_to_alias, - .map_from_alias = nss_ad_map_from_alias, -}; - -static struct nss_info_methods nss_sfu20_methods = { - .init = nss_sfu20_init, - .get_nss_info = nss_ad_get_info, - .map_to_alias = nss_ad_map_to_alias, - .map_from_alias = nss_ad_map_from_alias, -}; - - - -/************************************************************************ - Initialize the plugins - ***********************************************************************/ - static_decl_idmap; -NTSTATUS idmap_ad_init(void) +NTSTATUS idmap_ad_init(TALLOC_CTX *ctx) { - static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL; - static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL; - static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL; - static NTSTATUS status_nss_sfu20 = NT_STATUS_UNSUCCESSFUL; - - /* Always register the AD method first in order to get the - idmap_domain interface called */ + NTSTATUS status; - 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; + status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, + "ad", &ad_methods); + if (!NT_STATUS_IS_OK(status)) { + return status; } - if ( !NT_STATUS_IS_OK( status_nss_sfu20 ) ) { - status_nss_sfu20 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, - "sfu20", &nss_sfu20_methods ); - if ( !NT_STATUS_IS_OK(status_nss_sfu20) ) - return status_nss_sfu20; + status = idmap_ad_nss_init(ctx); + if (!NT_STATUS_IS_OK(status)) { + return status; } - return NT_STATUS_OK; + return NT_STATUS_OK; } -