X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Fnsswitch%2Fidmap_ad.c;h=87f73f99f0965dd42691ebae743f8a1a7368c7bb;hb=d1491cc5005c216588e6dfe957a2247132b6c9ef;hp=6195684d96c9e4f30c1e59c8a3d56fbc6b1a9b50;hpb=7165944469a7d3a249ac070cd702f9b812be4bae;p=ira%2Fwip.git diff --git a/source3/nsswitch/idmap_ad.c b/source3/nsswitch/idmap_ad.c index 6195684d96c..87f73f99f09 100644 --- a/source3/nsswitch/idmap_ad.c +++ b/source3/nsswitch/idmap_ad.c @@ -7,7 +7,7 @@ * * Copyright (C) Andrew Tridgell 2001 * Copyright (C) Andrew Bartlett 2003 - * Copyright (C) Gerald (Jerry) Carter 2004 + * Copyright (C) Gerald (Jerry) Carter 2004-2007 * Copyright (C) Luke Howard 2001-2004 * * This program is free software; you can redistribute it and/or modify @@ -32,72 +32,60 @@ #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache" -NTSTATUS init_module(void); - -static ADS_STRUCT *ad_idmap_ads = NULL; - -static char *attr_uidnumber = NULL; -static char *attr_gidnumber = NULL; - -static ADS_STATUS ad_idmap_check_attr_mapping(ADS_STRUCT *ads) -{ - ADS_STATUS status; - enum wb_posix_mapping map_type; - - if (attr_uidnumber != NULL && attr_gidnumber != NULL) { - return ADS_ERROR(LDAP_SUCCESS); - } - - SMB_ASSERT(ads->server.workgroup); +#define IDMAP_AD_MAX_IDS 30 +#define CHECK_ALLOC_DONE(mem) do { \ + if (!mem) { \ + DEBUG(0, ("Out of memory!\n")); \ + ret = NT_STATUS_NO_MEMORY; \ + goto done; \ + } \ +} while (0) - map_type = get_nss_info(ads->server.workgroup); +struct idmap_ad_context { + uint32_t filter_low_id; + uint32_t filter_high_id; +}; - if ((map_type == WB_POSIX_MAP_SFU) || - (map_type == WB_POSIX_MAP_RFC2307)) { +NTSTATUS init_module(void); - status = ads_check_posix_schema_mapping(ads, map_type); - if (ADS_ERR_OK(status)) { - attr_uidnumber = SMB_STRDUP(ads->schema.posix_uidnumber_attr); - attr_gidnumber = SMB_STRDUP(ads->schema.posix_gidnumber_attr); - ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber); - ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber); - return ADS_ERROR(LDAP_SUCCESS); - } else { - DEBUG(0,("ads_check_posix_schema_mapping failed: %s\n", ads_errstr(status))); - /* return status; */ - } - } - - /* fallback to XAD defaults */ - attr_uidnumber = SMB_STRDUP("uidNumber"); - attr_gidnumber = SMB_STRDUP("gidNumber"); - ADS_ERROR_HAVE_NO_MEMORY(attr_uidnumber); - ADS_ERROR_HAVE_NO_MEMORY(attr_gidnumber); +static ADS_STRUCT *ad_idmap_ads = NULL; +static struct posix_schema *ad_schema = NULL; +static enum wb_posix_mapping ad_map_type = WB_POSIX_MAP_UNKNOWN; - return ADS_ERROR(LDAP_SUCCESS); -} +/************************************************************************ + ***********************************************************************/ -static ADS_STRUCT *ad_idmap_cached_connection(void) +static ADS_STRUCT *ad_idmap_cached_connection_internal(void) { ADS_STRUCT *ads; ADS_STATUS status; BOOL local = False; + fstring dc_name; + struct in_addr dc_ip; if (ad_idmap_ads != NULL) { + + time_t expire; + time_t now = time(NULL); + ads = ad_idmap_ads; + expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire); + /* check for a valid structure */ + DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n", + (uint32)expire-(uint32)now, (uint32) expire, (uint32) now)); - DEBUG(7, ("Current tickets expire at %d, time is now %d\n", - (uint32) ads->auth.expire, (uint32) time(NULL))); - if ( ads->config.realm && (ads->auth.expire > time(NULL))) { + if ( ads->config.realm && (expire > time(NULL))) { return ads; } else { /* we own this ADS_STRUCT so make sure it goes away */ + DEBUG(7,("Deleting expired krb5 credential cache\n")); ads->is_mine = True; ads_destroy( &ads ); ads_kdestroy(WINBIND_CCACHE_NAME); ad_idmap_ads = NULL; + TALLOC_FREE( ad_schema ); } } @@ -106,8 +94,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 +106,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,42 +119,60 @@ static ADS_STRUCT *ad_idmap_cached_connection(void) ads->is_mine = False; - status = ad_idmap_check_attr_mapping(ads); - if (!ADS_ERR_OK(status)) { - DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n")); + ad_idmap_ads = ads; + + return ads; +} + +/************************************************************************ + ***********************************************************************/ + +static ADS_STRUCT *ad_idmap_cached_connection(void) +{ + ADS_STRUCT *ads = ad_idmap_cached_connection_internal(); + + if ( !ads ) return NULL; - } - ad_idmap_ads = ads; + /* if we have a valid ADS_STRUCT and the schema model is + defined, then we can return here. */ + + if ( ad_schema ) + return ads; + + /* Otherwise, set the schema model */ + + if ( (ad_map_type == WB_POSIX_MAP_SFU) || + (ad_map_type == WB_POSIX_MAP_RFC2307) ) + { + ADS_STATUS schema_status; + + schema_status = ads_check_posix_schema_mapping( NULL, ads, ad_map_type, &ad_schema); + if ( !ADS_ERR_OK(schema_status) ) { + DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n")); + return NULL; + } + } + return ads; } -struct idmap_ad_context { - uint32_t filter_low_id, filter_high_id; /* Filter range */ -}; +/************************************************************************ + ***********************************************************************/ -/* Initialize and check conf is appropriate */ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params) { struct idmap_ad_context *ctx; char *config_option; - const char *range; - ADS_STRUCT *ads; + const char *range = NULL; + const char *schema_mode = NULL; - /* verify AD is reachable (not critical, we may just be offline at start) */ - ads = ad_idmap_cached_connection(); - if (ads == 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; @@ -180,43 +189,36 @@ static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom, const char *params } } - /* idmap AD can work well only if it is the default module (trusts) - * with additional BUILTIN and alloc using TDB */ - if ( ! dom->default_domain) { - DEBUG(1, ("WARNING: idmap_ad is not configured as the default domain.\n" - "For best results we suggest you to configure this module as\n" - "default and configure BULTIN to use idmap_tdb\n" - "ex: idmap domains = BUILTIN %s\n" - " idmap alloc config: range = 5000 - 9999\n" - " idmap config %s: default = yes\n" - " idmap config %s: backend = ad\n" - " idmap config %s: range = 10000 - 10000000 #this is optional\n" - "NOTE: make sure the ranges do not overlap\n", - dom->name, dom->name, dom->name, dom->name)); - } - if ( ! dom->readonly) { - DEBUG(1, ("WARNING: forcing to readonly, as idmap_ad can't write on AD.\n")); - dom->readonly = true; /* force readonly */ + /* schema mode */ + if ( ad_map_type == WB_POSIX_MAP_UNKNOWN ) + ad_map_type = WB_POSIX_MAP_RFC2307; + schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL); + if ( schema_mode && schema_mode[0] ) { + if ( strequal(schema_mode, "sfu") ) + ad_map_type = WB_POSIX_MAP_SFU; + else if ( strequal(schema_mode, "rfc2307" ) ) + ad_map_type = WB_POSIX_MAP_RFC2307; + else + DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n", + schema_mode)); } dom->private_data = ctx; talloc_free(config_option); + return NT_STATUS_OK; } -#define IDMAP_AD_MAX_IDS 30 -#define CHECK_ALLOC_DONE(mem) do { if (!mem) { DEBUG(0, ("Out of memory!\n")); ret = NT_STATUS_NO_MEMORY; goto done; } } while (0) +/************************************************************************ + Search up to IDMAP_AD_MAX_IDS entries in maps for a match. + ***********************************************************************/ -/* this function searches up to IDMAP_AD_MAX_IDS entries in maps for a match */ static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, uint32_t id) { int i; - for (i = 0; i < IDMAP_AD_MAX_IDS; i++) { - if (maps[i] == NULL) { /* end of the run */ - return NULL; - } + for (i = 0; maps[i] && ixid.type == type) && (maps[i]->xid.id == id)) { return maps[i]; } @@ -225,6 +227,26 @@ static struct id_map *find_map_by_id(struct id_map **maps, enum id_type type, ui return NULL; } +/************************************************************************ + Search up to IDMAP_AD_MAX_IDS entries in maps for a match + ***********************************************************************/ + +static struct id_map *find_map_by_sid(struct id_map **maps, DOM_SID *sid) +{ + int i; + + for (i = 0; maps[i] && isid, sid)) { + return maps[i]; + } + } + + return NULL; +} + +/************************************************************************ + ***********************************************************************/ + static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids) { NTSTATUS ret; @@ -234,131 +256,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; + LDAPMessage *entry = NULL; char *filter = NULL; - BOOL multi = False; int idx = 0; int bidx = 0; int count; int i; + char *u_filter = NULL; + char *g_filter = NULL; - ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); + ctx = talloc_get_type(dom->private_data, struct idmap_ad_context); - memctx = talloc_new(ctx); - if ( ! memctx) { + if ( (memctx = talloc_new(ctx)) == NULL ) { DEBUG(0, ("Out of memory!\n")); return NT_STATUS_NO_MEMORY; } - ads = ad_idmap_cached_connection(); - if (ads == NULL) { + if ( (ads = ad_idmap_cached_connection()) == NULL ) { DEBUG(1, ("ADS uninitialized\n")); ret = NT_STATUS_UNSUCCESSFUL; goto done; } - /* attr_uidnumber and attr_gidnumber are surely successfully initialized now */ - attrs[2] = attr_uidnumber; - attrs[3] = attr_gidnumber; - - if ( ! ids[1]) { - /* if we are requested just one mapping use the simple filter */ - switch (ids[0]->xid.type) { - case ID_TYPE_UID: + attrs[2] = ad_schema->posix_uidnumber_attr; + attrs[3] = ad_schema->posix_gidnumber_attr; - filter = talloc_asprintf(memctx, - "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))", - ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST, - attr_uidnumber, - (unsigned long)ids[0]->xid.id); +again: + bidx = idx; + for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) { + switch (ids[idx]->xid.type) { + case ID_TYPE_UID: + if ( ! u_filter) { + u_filter = talloc_asprintf(memctx, "(&(|" + "(sAMAccountType=%d)" + "(sAMAccountType=%d)" + "(sAMAccountType=%d))(|", + ATYPE_NORMAL_ACCOUNT, + ATYPE_WORKSTATION_TRUST, + ATYPE_INTERDOMAIN_TRUST); + } + u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)", + ad_schema->posix_uidnumber_attr, + (unsigned long)ids[idx]->xid.id); + CHECK_ALLOC_DONE(u_filter); break; + case ID_TYPE_GID: - - filter = talloc_asprintf(memctx, - "(&(|(sAMAccountType=%d)(sAMAccountType=%d))(%s=%lu))", - ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP, - attr_gidnumber, - (unsigned long)ids[0]->xid.id); + if ( ! g_filter) { + g_filter = talloc_asprintf(memctx, "(&(|" + "(sAMAccountType=%d)" + "(sAMAccountType=%d))(|", + ATYPE_SECURITY_GLOBAL_GROUP, + ATYPE_SECURITY_LOCAL_GROUP); + } + g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)", + ad_schema->posix_gidnumber_attr, + (unsigned long)ids[idx]->xid.id); + CHECK_ALLOC_DONE(g_filter); break; + default: DEBUG(3, ("Unknown ID type\n")); - ret = NT_STATUS_INVALID_PARAMETER; - goto done; + ids[idx]->status = ID_UNKNOWN; + continue; } - CHECK_ALLOC_DONE(filter); - DEBUG(10, ("Filter: [%s]\n", filter)); - } else { - /* multiple mappings */ - multi = True; } - -again: - if (multi) { - char *u_filter = NULL; - char *g_filter = NULL; - - bidx = idx; - for (i = 0; (i < IDMAP_AD_MAX_IDS) && ids[idx]; i++, idx++) { - switch (ids[idx]->xid.type) { - case ID_TYPE_UID: - - if ( ! u_filter) { - u_filter = talloc_asprintf(memctx, "(&(|" - "(sAMAccountType=%d)" - "(sAMAccountType=%d)" - "(sAMAccountType=%d))(|", - ATYPE_NORMAL_ACCOUNT, - ATYPE_WORKSTATION_TRUST, - ATYPE_INTERDOMAIN_TRUST); - } - u_filter = talloc_asprintf_append(u_filter, "(%s=%lu)", - attr_uidnumber, - (unsigned long)ids[idx]->xid.id); - CHECK_ALLOC_DONE(u_filter); - break; - - case ID_TYPE_GID: - if ( ! g_filter) { - g_filter = talloc_asprintf(memctx, "(&(|" - "(sAMAccountType=%d)" - "(sAMAccountType=%d))(|", - ATYPE_SECURITY_GLOBAL_GROUP, - ATYPE_SECURITY_LOCAL_GROUP); - } - g_filter = talloc_asprintf_append(g_filter, "(%s=%lu)", - attr_gidnumber, - (unsigned long)ids[idx]->xid.id); - CHECK_ALLOC_DONE(g_filter); - break; - - default: - DEBUG(3, ("Unknown ID type\n")); - ids[idx]->mapped = false; - continue; - } - } - filter = talloc_asprintf(memctx, "(|"); + filter = talloc_asprintf(memctx, "(|"); + CHECK_ALLOC_DONE(filter); + if ( u_filter) { + filter = talloc_asprintf_append(filter, "%s))", u_filter); CHECK_ALLOC_DONE(filter); - if ( u_filter) { - filter = talloc_asprintf_append(filter, "%s))", u_filter); - CHECK_ALLOC_DONE(filter); TALLOC_FREE(u_filter); - } - if ( g_filter) { - filter = talloc_asprintf_append(filter, "%s))", g_filter); - CHECK_ALLOC_DONE(filter); - TALLOC_FREE(g_filter); - } - filter = talloc_asprintf_append(filter, ")"); + } + if ( g_filter) { + filter = talloc_asprintf_append(filter, "%s))", g_filter); CHECK_ALLOC_DONE(filter); - DEBUG(10, ("Filter: [%s]\n", filter)); - } else { - bidx = 0; - idx = 1; + TALLOC_FREE(g_filter); } + filter = talloc_asprintf_append(filter, ")"); + CHECK_ALLOC_DONE(filter); rc = ads_search_retry(ads, &res, filter, attrs); if (!ADS_ERR_OK(rc)) { @@ -367,13 +347,12 @@ 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")); } - for (i = 0; i < count; i++) { - LDAPMessage *entry = NULL; + entry = res; + for (i = 0; (i < count) && entry; i++) { DOM_SID sid; enum id_type type; struct id_map *map; @@ -381,13 +360,14 @@ again: uint32_t atype; if (i == 0) { /* first entry */ - entry = ads_first_entry(ads, res); + entry = ads_first_entry(ads, entry); } else { /* following ones */ entry = ads_next_entry(ads, entry); } - if ( ! entry) { + + if ( !entry ) { DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); - continue; + break; } /* first check if the SID is present */ @@ -417,10 +397,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))) { @@ -438,7 +423,7 @@ again: sid_copy(map->sid, &sid); /* mapped */ - map->mapped = True; + map->status = ID_MAPPED; DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_static(map->sid), @@ -450,32 +435,25 @@ 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 unknown ones as unmapped */ + for (i = 0; ids[i]; i++) { + if (ids[i]->status == ID_UNKNOWN) + ids[i]->status = ID_UNMAPPED; + } + done: talloc_free(memctx); 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) { @@ -490,86 +468,52 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map NULL, /* attr_gidnumber */ NULL }; LDAPMessage *res = NULL; + LDAPMessage *entry = 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)) { @@ -578,13 +522,12 @@ 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")); } - for (i = 0; i < count; i++) { - LDAPMessage *entry = NULL; + entry = res; + for (i = 0; (i < count) && entry; i++) { DOM_SID sid; enum id_type type; struct id_map *map; @@ -592,13 +535,14 @@ again: uint32_t atype; if (i == 0) { /* first entry */ - entry = ads_first_entry(ads, res); + entry = ads_first_entry(ads, entry); } else { /* following ones */ entry = ads_next_entry(ads, entry); } - if ( ! entry) { + + if ( !entry ) { DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n")); - continue; + break; } /* first check if the SID is present */ @@ -634,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; } @@ -649,7 +597,7 @@ again: /* mapped */ map->xid.type = type; map->xid.id = id; - map->mapped = True; + map->status = ID_MAPPED; DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_static(map->sid), @@ -661,16 +609,26 @@ 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 */ + for (i = 0; ids[i]; i++) { + if (ids[i]->status == ID_UNKNOWN) + ids[i]->status = ID_UNMAPPED; + } + done: talloc_free(memctx); return ret; } +/************************************************************************ + ***********************************************************************/ + static NTSTATUS idmap_ad_close(struct idmap_domain *dom) { ADS_STRUCT *ads = ad_idmap_ads; @@ -682,22 +640,170 @@ static NTSTATUS idmap_ad_close(struct idmap_domain *dom) ad_idmap_ads = NULL; } - SAFE_FREE(attr_uidnumber); - SAFE_FREE(attr_gidnumber); + TALLOC_FREE( ad_schema ); + + return NT_STATUS_OK; +} + +/* + * nss_info_{sfu,rfc2307} + */ + +/************************************************************************ + Initialize the {sfu,rfc2307} state + ***********************************************************************/ + +static NTSTATUS nss_sfu_init( struct nss_domain_entry *e ) +{ + /* Sanity check if we have previously been called with a + different schema model */ + + if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) && + (ad_map_type != WB_POSIX_MAP_SFU) ) + { + DEBUG(0,("nss_sfu_init: Posix Map type has already been set. " + "Mixed schema models not supported!\n")); + return NT_STATUS_NOT_SUPPORTED; + } + + ad_map_type = WB_POSIX_MAP_SFU; + + if ( !ad_idmap_ads ) + return idmap_ad_initialize( NULL, NULL ); + + return NT_STATUS_OK; +} + +static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e ) +{ + /* Sanity check if we have previously been called with a + different schema model */ + + if ( (ad_map_type != WB_POSIX_MAP_UNKNOWN) && + (ad_map_type != WB_POSIX_MAP_RFC2307) ) + { + DEBUG(0,("nss_rfc2307_init: Posix Map type has already been set. " + "Mixed schema models not supported!\n")); + return NT_STATUS_NOT_SUPPORTED; + } + + ad_map_type = WB_POSIX_MAP_RFC2307; + + if ( !ad_idmap_ads ) + return idmap_ad_initialize( NULL, NULL ); + + return NT_STATUS_OK; +} + + +/************************************************************************ + ***********************************************************************/ +static NTSTATUS nss_ad_get_info( struct nss_domain_entry *e, + const DOM_SID *sid, + TALLOC_CTX *ctx, + ADS_STRUCT *ads, + LDAPMessage *msg, + char **homedir, + char **shell, + char **gecos, + uint32 *gid ) +{ + ADS_STRUCT *ads_internal = NULL; + + /* We are assuming that the internal ADS_STRUCT is for the + same forest as the incoming *ads pointer */ + + ads_internal = ad_idmap_cached_connection(); + + if ( !ads_internal || !ad_schema ) + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + if ( !homedir || !shell || !gecos ) + return NT_STATUS_INVALID_PARAMETER; + + *homedir = ads_pull_string( ads, ctx, msg, ad_schema->posix_homedir_attr ); + *shell = ads_pull_string( ads, ctx, msg, ad_schema->posix_shell_attr ); + *gecos = 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; + } + return NT_STATUS_OK; } +/************************************************************************ + ***********************************************************************/ + +static NTSTATUS nss_ad_close( void ) +{ + /* nothing to do. All memory is free()'d by the idmap close_fn() */ + + return NT_STATUS_OK; +} + +/************************************************************************ + Function dispatch tables for the idmap and nss plugins + ***********************************************************************/ + static struct idmap_methods ad_methods = { - .init = idmap_ad_initialize, + .init = idmap_ad_initialize, .unixids_to_sids = idmap_ad_unixids_to_sids, .sids_to_unixids = idmap_ad_sids_to_unixids, - .close_fn = idmap_ad_close + .close_fn = idmap_ad_close +}; + +/* The SFU and RFC2307 NSS plugins share everything but the init + function which sets the intended schema model to use */ + +static struct nss_info_methods nss_rfc2307_methods = { + .init = nss_rfc2307_init, + .get_nss_info = nss_ad_get_info, + .close_fn = nss_ad_close +}; + +static struct nss_info_methods nss_sfu_methods = { + .init = nss_sfu_init, + .get_nss_info = nss_ad_get_info, + .close_fn = nss_ad_close }; -/* support for new authentication subsystem */ + +/************************************************************************ + Initialize the plugins + ***********************************************************************/ + NTSTATUS idmap_ad_init(void) { - return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods); + static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL; + static NTSTATUS status_nss_rfc2307 = NT_STATUS_UNSUCCESSFUL; + static NTSTATUS status_nss_sfu = NT_STATUS_UNSUCCESSFUL; + + /* Always register the AD method first in order to get the + idmap_domain interface called */ + + if ( !NT_STATUS_IS_OK(status_idmap_ad) ) { + status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, + "ad", &ad_methods); + if ( !NT_STATUS_IS_OK(status_idmap_ad) ) + return status_idmap_ad; + } + + if ( !NT_STATUS_IS_OK( status_nss_rfc2307 ) ) { + status_nss_rfc2307 = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, + "rfc2307", &nss_rfc2307_methods ); + if ( !NT_STATUS_IS_OK(status_nss_rfc2307) ) + return status_nss_rfc2307; + } + + if ( !NT_STATUS_IS_OK( status_nss_sfu ) ) { + status_nss_sfu = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION, + "sfu", &nss_sfu_methods ); + if ( !NT_STATUS_IS_OK(status_nss_sfu) ) + return status_nss_sfu; + } + + return NT_STATUS_OK; }