diff options
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/net_ads.c | 111 |
1 files changed, 74 insertions, 37 deletions
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 53d9f65d6b..7902248f94 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -153,20 +153,12 @@ static int net_ads_cldap_netlogon(ADS_STRUCT *ads) static int net_ads_lookup(int argc, const char **argv) { ADS_STRUCT *ads; - ADS_STATUS status; - const char *realm = assume_own_realm(); - - ads = ads_init(realm, opt_target_workgroup, opt_host); - if (ads) { - ads->auth.flags |= ADS_AUTH_NO_BIND; - } - status = ads_connect(ads); - if (!ADS_ERR_OK(status) || !ads) { + if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) { d_fprintf(stderr, "Didn't find the cldap server!\n"); return -1; } - + if (!ads->config.realm) { ads->config.realm = CONST_DISCARD(char *, opt_target_workgroup); ads->ldap_port = 389; @@ -180,14 +172,12 @@ static int net_ads_lookup(int argc, const char **argv) static int net_ads_info(int argc, const char **argv) { ADS_STRUCT *ads; - const char *realm = assume_own_realm(); - if ( (ads = ads_init(realm, opt_target_workgroup, opt_host)) != NULL ) { - ads->auth.flags |= ADS_AUTH_NO_BIND; + if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) { + d_fprintf(stderr, "Didn't find the ldap server!\n"); + return -1; } - ads_connect(ads); - if (!ads || !ads->config.realm) { d_fprintf(stderr, "Didn't find the ldap server!\n"); return -1; @@ -219,24 +209,33 @@ static void use_in_memory_ccache(void) { setenv(KRB5_ENV_CCNAME, "MEMORY:net_ads", 1); } -ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads) +static ADS_STATUS ads_startup_int(BOOL only_own_domain, uint32 auth_flags, ADS_STRUCT **ads_ret) { + ADS_STRUCT *ads = NULL; ADS_STATUS status; BOOL need_password = False; BOOL second_time = False; char *cp; const char *realm = NULL; - + BOOL tried_closest_dc = False; + BOOL closest_dc = False; + BOOL site_matches = False; + /* lp_realm() should be handled by a command line param, However, the join requires that realm be set in smb.conf and compares our realm with the remote server's so this is ok until someone needs more flexibility */ + *ads_ret = NULL; + +retry_connect: if (only_own_domain) { realm = lp_realm(); + } else { + realm = assume_own_realm(); } - - *ads = ads_init(realm, opt_target_workgroup, opt_host); + + ads = ads_init(realm, opt_target_workgroup, opt_host); if (!opt_user_name) { opt_user_name = "administrator"; @@ -248,31 +247,39 @@ ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads) retry: if (!opt_password && need_password && !opt_machine_pass) { - char *prompt; + char *prompt = NULL; asprintf(&prompt,"%s's password: ", opt_user_name); + if (!prompt) { + ads_destroy(&ads); + return ADS_ERROR(LDAP_NO_MEMORY); + } opt_password = getpass(prompt); free(prompt); } if (opt_password) { use_in_memory_ccache(); - (*ads)->auth.password = smb_xstrdup(opt_password); + SAFE_FREE(ads->auth.password); + ads->auth.password = smb_xstrdup(opt_password); } - (*ads)->auth.user_name = smb_xstrdup(opt_user_name); + ads->auth.flags |= auth_flags; + SAFE_FREE(ads->auth.user_name); + ads->auth.user_name = smb_xstrdup(opt_user_name); /* * If the username is of the form "name@realm", * extract the realm and convert to upper case. * This is only used to establish the connection. */ - if ((cp = strchr_m((*ads)->auth.user_name, '@'))!=0) { - *cp++ = '\0'; - (*ads)->auth.realm = smb_xstrdup(cp); - strupper_m((*ads)->auth.realm); + if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) { + *cp++ = '\0'; + SAFE_FREE(ads->auth.realm); + ads->auth.realm = smb_xstrdup(cp); + strupper_m(ads->auth.realm); } - status = ads_connect(*ads); + status = ads_connect(ads); if (!ADS_ERR_OK(status)) { if (!need_password && !second_time) { @@ -280,12 +287,50 @@ retry: second_time = True; goto retry; } else { - ads_destroy(ads); + ads_destroy(&ads); + return status; } } + + /* when contacting our own domain, make sure we use the closest DC. + * This is done by reconnecting to ADS because only the first call to + * ads_connect will give us our own sitename */ + + closest_dc = (ads->config.flags & ADS_CLOSEST); + site_matches = ads_sitename_match(ads); + + DEBUG(10,("ads_startup_int: DC %s closest DC\n", closest_dc ? "is":"is *NOT*")); + DEBUG(10,("ads_startup_int: sitenames %s match\n", site_matches ? "do":"do *NOT*")); + + if ((only_own_domain || !opt_host) && !tried_closest_dc) { + + tried_closest_dc = True; /* avoid loop */ + + if (!closest_dc || !site_matches) { + + namecache_delete(ads->server.realm, 0x1C); + namecache_delete(ads->server.workgroup, 0x1C); + + ads_destroy(&ads); + ads = NULL; + + goto retry_connect; + } + } + + *ads_ret = ads; return status; } +ADS_STATUS ads_startup(BOOL only_own_domain, ADS_STRUCT **ads) +{ + return ads_startup_int(only_own_domain, 0, ads); +} + +ADS_STATUS ads_startup_nobind(BOOL only_own_domain, ADS_STRUCT **ads) +{ + return ads_startup_int(only_own_domain, ADS_AUTH_NO_BIND, ads); +} /* Check to see if connection can be made via ads. @@ -327,17 +372,9 @@ int net_ads_check(void) static int net_ads_workgroup(int argc, const char **argv) { ADS_STRUCT *ads; - ADS_STATUS status; - const char *realm = assume_own_realm(); struct cldap_netlogon_reply reply; - ads = ads_init(realm, opt_target_workgroup, opt_host); - if (ads) { - ads->auth.flags |= ADS_AUTH_NO_BIND; - } - - status = ads_connect(ads); - if (!ADS_ERR_OK(status) || !ads) { + if (!ADS_ERR_OK(ads_startup_nobind(False, &ads))) { d_fprintf(stderr, "Didn't find the cldap server!\n"); return -1; } |