--- samba-3.0.21c/source/sam/idmap_ad.c.multiple_connections 2006-04-04 15:34:00.000000000 +0100 +++ samba-3.0.21c/source/sam/idmap_ad.c 2006-04-04 15:53:16.000000000 +0100 @@ -25,7 +25,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * With changes to make multi-AD domains work + * (cf ../nsswitch/winbindd_ads.c) + */ + + #include "includes.h" +#include "../nsswitch/winbindd.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_IDMAP @@ -35,133 +42,153 @@ NTSTATUS init_module(void); -static ADS_STRUCT *ad_idmap_ads = NULL; -static char *ad_idmap_uri = NULL; +/* + * Connection management. + * + * Like winbindd_ads.c, use a separate connection to each domain. Maybe this should be integrated + * with the code there, or with the winbindd_cm connection manager? + */ -static char *attr_uidnumber = NULL; -static char *attr_gidnumber = NULL; +/* + * Create a new connection for the cache. This ought to be the same as code in winbindd_ads + * but I have factored out the domain->private_data checking. So the + * code here is simply an edited version of the original code from idmap_ad.c + */ -static BOOL ad_idmap_check_attr_mapping(ADS_STRUCT *ads) +static ADS_STRUCT *ad_idmap_new_cached_connection(struct winbindd_domain *domain) { - if (attr_uidnumber != NULL && attr_gidnumber != NULL) { - return True; + ADS_STRUCT *ads; + ADS_STATUS status; + + DEBUG(3,("ad_idmap_new_cached_connection to %s [%s]\n", + domain->name, sid_string_static(&domain->sid))); + + SMB_ASSERT(domain->private_data == NULL); + + /* we don't want this to affect the users ccache */ + setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); + + ads = ads_init(domain->alt_name, domain->name, NULL); + if (!ads) { + DEBUG(1,("ads_init failed\n")); + return NULL; } - if (use_nss_info("sfu")) { - - if (!ads_check_sfu_mapping(ads)) { - DEBUG(0,("ad_idmap_check_attr_mapping: failed to check for SFU schema\n")); - return False; + ads->server.ldap_uri = NULL; + ads->server.ldap_server = NULL; + + /* the machine acct password might have change - fetch it every time */ + + SAFE_FREE(ads->auth.password); + SAFE_FREE(ads->auth.realm); + + if ( IS_DC ) { + DOM_SID sid; + time_t last_set_time; + + if ( !secrets_fetch_trusted_domain_password( domain->name, &ads->auth.password, &sid, &last_set_time ) ) { + ads_destroy( &ads ); + return NULL; } + ads->auth.realm = SMB_STRDUP( ads->server.realm ); + strupper_m( ads->auth.realm ); + } + else { + struct winbindd_domain *our_domain = domain; + + ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); + + /* always give preference to the alt_name in our + primary domain if possible */ + + if ( !domain->primary ) + our_domain = find_our_domain(); - attr_uidnumber = SMB_STRDUP(ads->schema.sfu_uidnumber_attr); - attr_gidnumber = SMB_STRDUP(ads->schema.sfu_gidnumber_attr); + if ( our_domain->alt_name[0] != '\0' ) { + ads->auth.realm = SMB_STRDUP( our_domain->alt_name ); + strupper_m( ads->auth.realm ); + } else { + ads->auth.realm = SMB_STRDUP( lp_realm() ); + } + } - } else { - attr_uidnumber = SMB_STRDUP("uidNumber"); - attr_gidnumber = SMB_STRDUP("gidNumber"); + status = ads_connect(ads); + if (!ADS_ERR_OK(status)) { + DEBUG(1, ("ad_idmap_new_cached_connection: failed to connect to AD %s\n", + domain->name)); + ads_destroy(&ads); + return NULL; } - return True; + ads->is_mine = False; + + domain->private_data = (void *) ads; /* cache it! */ + return ads; } -static ADS_STRUCT *ad_idmap_cached_connection(void) +static ADS_STRUCT *ad_idmap_live_connection(struct winbindd_domain *d) { - ADS_STRUCT *ads; - ADS_STATUS status; - BOOL local = False; + ADS_STRUCT *ads = (ADS_STRUCT *) d->private_data; -#ifdef ADS_AUTH_EXTERNAL_BIND - local = ((strncmp(ad_idmap_uri, "ldapi://", sizeof("ldapi://") - 1)) == 0); -#endif /* ADS_AUTH_EXTERNAL_BIND */ - - if (ad_idmap_ads != NULL) { - ads = ad_idmap_ads; + if (ads) { + DEBUG(7,("Found cached connection to realm %s for [%s]\n", + ads->server.realm, sid_string_static(&d->sid))); + /* check for a valid structure */ 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))) { return ads; - } else { - /* we own this ADS_STRUCT so make sure it goes away */ - ads->is_mine = True; - ads_destroy( &ads ); - ads_kdestroy(WINBIND_CCACHE_NAME); - ad_idmap_ads = NULL; } - } - if (!local) { - /* we don't want this to affect the users ccache */ - setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); - } + /* tickets have expired so we need a new connection */ + /* we own this ADS_STRUCT so make sure it goes away */ - ads = ads_init(NULL, NULL, NULL); - if (!ads) { - DEBUG(1,("ads_init failed\n")); - return NULL; + ads->is_mine = True; + ads_destroy( &ads ); + ads_kdestroy(WINBIND_CCACHE_NAME); + ads = NULL; + d->private_data = NULL; } - /* if ad_imap_uri is not empty we try to connect to - * the given URI in smb.conf. Else try to connect to - * one of the DCs - */ - if (*ad_idmap_uri != '\0') { - ads->server.ldap_uri = SMB_STRDUP(ad_idmap_uri); - if (ads->server.ldap_uri == NULL) { - return NULL; - } - } - else { - ads->server.ldap_uri = NULL; - ads->server.ldap_server = NULL; - } + return ad_idmap_new_cached_connection(d); +} -#ifdef ADS_AUTH_EXTERNAL_BIND - if (local) - ads->auth.flags |= ADS_AUTH_EXTERNAL_BIND; - else -#endif - { - /* the machine acct password might have change - fetch it every time */ - SAFE_FREE(ads->auth.password); - ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); +static ADS_STRUCT *ad_idmap_cached_connection(const DOM_SID *sid) +{ + struct winbindd_domain *d; + ADS_STRUCT *ads = NULL; - SAFE_FREE(ads->auth.realm); - ads->auth.realm = SMB_STRDUP(lp_realm()); - } + d = find_domain_from_sid(sid); - status = ads_connect(ads); - if (!ADS_ERR_OK(status)) { - DEBUG(1, ("ad_idmap_init: failed to connect to AD\n")); - ads_destroy(&ads); + if (d == NULL) { + DEBUG(1,("Tried to find connection to unknown domain [%s]\n", + sid_string_static(sid))); return NULL; } - ads->is_mine = False; - - if (!ad_idmap_check_attr_mapping(ads)) { - DEBUG(1, ("ad_idmap_init: failed to check attribute mapping\n")); + if (!d->active_directory) { + DEBUG(1,("ad_idmap_cached_connection found non-AD domain %s\n", + d->name)); return NULL; } - ad_idmap_ads = ads; - return ads; + return ad_idmap_live_connection(d); } + static NTSTATUS ad_idmap_init(char *uri) { - ad_idmap_uri = SMB_STRDUP(uri); - if (ad_idmap_uri == NULL) { - return NT_STATUS_NO_MEMORY; + if (*uri) { + DEBUG(0,("Warning: idmap_ad no longer supports a URI (%s)\n",uri)); } return NT_STATUS_OK; } -static NTSTATUS ad_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, int id_type) +static NTSTATUS ad_idmap_get_sid_from_id_in_domain(ADS_STRUCT *ads,DOM_SID *sid, unid_t unid, int id_type) { ADS_STATUS rc; NTSTATUS status = NT_STATUS_NONE_MAPPED; @@ -171,18 +198,11 @@ char *expr = NULL; fstring sid_string; int count; - ADS_STRUCT *ads; if (sid == NULL) { return NT_STATUS_INVALID_PARAMETER; } - ads = ad_idmap_cached_connection(); - if (ads == NULL) { - DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n")); - return NT_STATUS_NOT_SUPPORTED; - } - switch (id_type & ID_TYPEMASK) { case ID_USERID: if (asprintf(&expr, "(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d))(%s=%d))", @@ -243,14 +263,43 @@ return status; } +/* + * Scan all known domains to try to map an id into a sid + */ + +static NTSTATUS ad_idmap_get_sid_from_id(DOM_SID *sid, unid_t unid, int id_type) +{ + struct winbindd_domain *d; + ADS_STRUCT *ads; + NTSTATUS status; + + for (d = domain_list(); d; d = d->next) { + ads = ad_idmap_live_connection(d); + if (!ads) { + DEBUG(1,("ad_idmap_get_sid_from_id: could not check %s\n", + d->name)); + continue; + } + + status = ad_idmap_get_sid_from_id_in_domain(ads,sid,unid,id_type); + if (NT_STATUS_IS_OK(status)) + return status; + } + + return NT_STATUS_UNSUCCESSFUL; +} + + static NTSTATUS ad_idmap_get_id_from_sid(unid_t *unid, int *id_type, const DOM_SID *sid) { ADS_STATUS rc; NTSTATUS status = NT_STATUS_NONE_MAPPED; - const char *attrs[] = { "sAMAccountType", - NULL /* [1] ATTR_UIDNUMBER */, - NULL /* [2] ATTR_GIDNUMBER */, - NULL }; + const char *attrs[] = { + "sAMAccountType", + NULL, /* space for (e.g.) uidNumber */ + NULL, /* space for (e.g.) gidNumber */ + NULL + }; void *res = NULL; void *msg = NULL; char *expr = NULL; @@ -260,18 +309,26 @@ int count; ADS_STRUCT *ads; - if (unid == NULL) { + if ((unid == NULL) || (sid == NULL)) { return NT_STATUS_INVALID_PARAMETER; } - ads = ad_idmap_cached_connection(); + ads = ad_idmap_cached_connection(sid); if (ads == NULL) { - DEBUG(1, ("ad_idmap_get_id_from_sid ADS uninitialized\n")); + DEBUG(1, ("ad_idmap_get_id_from_sid [%s] could not get connection\n", + sid_string_static(sid))); + return NT_STATUS_NOT_SUPPORTED; + } + + if ((!ads->schema.sfu_uidnumber_attr) + && (!ads_check_sfu_mapping(ads))) { + DEBUG(7,("ad_idmap_get_id_from_sid [%s] could not get LDAP attribute mappings\n", + sid_string_static(sid))); return NT_STATUS_NOT_SUPPORTED; } - attrs[1] = attr_uidnumber; - attrs[2] = attr_gidnumber; + attrs[1] = ads->schema.sfu_uidnumber_attr; + attrs[2] = ads->schema.sfu_gidnumber_attr; sidstr = sid_binstring(sid); if (asprintf(&expr, "(objectSid=%s)", sidstr) == -1) { @@ -323,9 +380,9 @@ break; } - if (!ads_pull_uint32(ads, msg, (*id_type == ID_GROUPID) ? attr_gidnumber : attr_uidnumber, &uid)) { + if (!ads_pull_uint32(ads, msg, (*id_type == ID_GROUPID) ? ads->schema.sfu_gidnumber_attr : ads->schema.sfu_uidnumber_attr, &uid)) { DEBUG(1, ("ad_idmap_get_id_from_sid: ads_pull_uint32: could not read attribute '%s'\n", - (*id_type == ID_GROUPID) ? attr_gidnumber : attr_uidnumber)); + (*id_type == ID_GROUPID) ? ads->schema.sfu_gidnumber_attr : ads->schema.sfu_uidnumber_attr)); goto done; } @@ -355,18 +412,8 @@ static NTSTATUS ad_idmap_close(void) { - ADS_STRUCT *ads = ad_idmap_ads; - - if (ads != NULL) { - /* we own this ADS_STRUCT so make sure it goes away */ - ads->is_mine = True; - ads_destroy( &ads ); - ad_idmap_ads = NULL; - } + /* We might not own all those connections, so don't mess with them */ - SAFE_FREE(attr_uidnumber); - SAFE_FREE(attr_gidnumber); - return NT_STATUS_OK; } @@ -401,6 +448,7 @@ /* support for new authentication subsystem */ NTSTATUS init_module(void) { + DEBUG(1,("idmap_ad: This version has the multiple-connection patch\n")); return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ad", &ad_methods); }