summaryrefslogtreecommitdiff
path: root/source3/libads
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libads')
-rw-r--r--source3/libads/dns.c10
-rw-r--r--source3/libads/kerberos.c65
-rw-r--r--source3/libads/ldap.c19
3 files changed, 72 insertions, 22 deletions
diff --git a/source3/libads/dns.c b/source3/libads/dns.c
index c8b3f29507..b67d802bdc 100644
--- a/source3/libads/dns.c
+++ b/source3/libads/dns.c
@@ -673,16 +673,16 @@ NTSTATUS ads_dns_query_internal(TALLOC_CTX *ctx,
}
/********************************************************************
- Query for AD DC's. Transparently use sitename.
+ Query for AD DC's.
********************************************************************/
NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
const char *realm,
+ const char *sitename,
struct dns_rr_srv **dclist,
int *numdcs )
{
NTSTATUS status;
- char *sitename = sitename_fetch();
status = ads_dns_query_internal(ctx, "_ldap", realm, sitename,
dclist, numdcs);
@@ -691,23 +691,22 @@ NTSTATUS ads_dns_query_dcs(TALLOC_CTX *ctx,
status = ads_dns_query_internal(ctx, "_ldap", realm, NULL,
dclist, numdcs);
}
- SAFE_FREE(sitename);
return status;
}
/********************************************************************
- Query for AD KDC's. Transparently use sitename.
+ Query for AD KDC's.
Even if our underlying kerberos libraries are UDP only, this
is pretty safe as it's unlikely that a KDC supports TCP and not UDP.
********************************************************************/
NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
const char *realm,
+ const char *sitename,
struct dns_rr_srv **dclist,
int *numdcs )
{
NTSTATUS status;
- char *sitename = sitename_fetch();
status = ads_dns_query_internal(ctx, "_kerberos", realm, sitename,
dclist, numdcs);
@@ -716,6 +715,5 @@ NTSTATUS ads_dns_query_kdcs(TALLOC_CTX *ctx,
status = ads_dns_query_internal(ctx, "_kerberos", realm, NULL,
dclist, numdcs);
}
- SAFE_FREE(sitename);
return status;
}
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 76866a8093..95eed6fe27 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -470,10 +470,11 @@ int kerberos_kinit_password(const char *principal,
Does DNS queries.
************************************************************************/
-static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr primary_ip)
+static char *get_kdc_ip_string(char *mem_ctx, const char *realm, const char *sitename, struct in_addr primary_ip)
{
- struct ip_service *ip_srv;
- int count, i;
+ struct ip_service *ip_srv_site;
+ struct ip_service *ip_srv_nonsite;
+ int count_site, count_nonsite, i;
char *kdc_str = talloc_asprintf(mem_ctx, "\tkdc = %s\n",
inet_ntoa(primary_ip));
@@ -481,26 +482,61 @@ static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr
return NULL;
}
- if (!NT_STATUS_IS_OK(get_kdc_list(realm, &ip_srv, &count))) {
- DEBUG(10,("get_kdc_ip_string: get_kdc_list failed. Returning %s\n",
- kdc_str ));
- return kdc_str;
+ /* Get the KDC's only in this site. */
+
+ get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
+
+ for (i = 0; i < count_site; i++) {
+ if (ip_equal(ip_srv_site[i].ip, primary_ip)) {
+ continue;
+ }
+ /* Append to the string - inefficient but not done often. */
+ kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
+ kdc_str, inet_ntoa(ip_srv_site[i].ip));
+ if (!kdc_str) {
+ SAFE_FREE(ip_srv_site);
+ return NULL;
+ }
}
- for (i = 0; i < count; i++) {
- if (ip_equal(ip_srv[i].ip, primary_ip)) {
+ /* Get all KDC's. */
+
+ get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
+
+ for (i = 0; i < count_nonsite; i++) {
+ int j;
+
+ if (ip_equal(ip_srv_nonsite[i].ip, primary_ip)) {
+ continue;
+ }
+
+ /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
+ for (j = 0; j < count_site; j++) {
+ if (ip_equal(ip_srv_nonsite[i].ip, ip_srv_site[j].ip)) {
+ break;
+ }
+ /* As the lists are sorted we can break early if nonsite > site. */
+ if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
+ break;
+ }
+ }
+ if (j != i) {
continue;
}
+
/* Append to the string - inefficient but not done often. */
kdc_str = talloc_asprintf(mem_ctx, "%s\tkdc = %s\n",
- kdc_str, inet_ntoa(ip_srv[i].ip));
+ kdc_str, inet_ntoa(ip_srv_nonsite[i].ip));
if (!kdc_str) {
- SAFE_FREE(ip_srv);
+ SAFE_FREE(ip_srv_site);
+ SAFE_FREE(ip_srv_nonsite);
return NULL;
}
}
- SAFE_FREE(ip_srv);
+
+ SAFE_FREE(ip_srv_site);
+ SAFE_FREE(ip_srv_nonsite);
DEBUG(10,("get_kdc_ip_string: Returning %s\n",
kdc_str ));
@@ -515,7 +551,8 @@ static char *get_kdc_ip_string(char *mem_ctx, const char *realm, struct in_addr
run as root or will fail (which is a good thing :-).
************************************************************************/
-BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain, struct in_addr ip)
+BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *domain,
+ const char *sitename, struct in_addr ip)
{
char *dname = talloc_asprintf(NULL, "%s/smb_krb5", lp_lockdir());
char *tmpname = NULL;
@@ -556,7 +593,7 @@ BOOL create_local_private_krb5_conf_for_domain(const char *realm, const char *do
realm_upper = talloc_strdup(fname, realm);
strupper_m(realm_upper);
- kdc_ip_string = get_kdc_ip_string(dname, realm, ip);
+ kdc_ip_string = get_kdc_ip_string(dname, realm, sitename, ip);
if (!kdc_ip_string) {
TALLOC_FREE(dname);
return False;
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index c263e8e133..2ceae4d957 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -249,6 +249,7 @@ static NTSTATUS ads_find_dc(ADS_STRUCT *ads)
pstring realm;
BOOL got_realm = False;
BOOL use_own_domain = False;
+ char *sitename = sitename_fetch();
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
/* if the realm and workgroup are both empty, assume they are ours */
@@ -279,6 +280,7 @@ again:
}
if ( !c_realm || !*c_realm ) {
+ SAFE_FREE(sitename);
DEBUG(0,("ads_find_dc: no realm or workgroup! Don't know what to do\n"));
return NT_STATUS_INVALID_PARAMETER; /* rather need MISSING_PARAMETER ... */
}
@@ -289,7 +291,7 @@ again:
DEBUG(6,("ads_find_dc: looking for %s '%s'\n",
(got_realm ? "realm" : "domain"), realm));
- status = get_sorted_dc_list(realm, &ip_list, &count, got_realm);
+ status = get_sorted_dc_list(realm, sitename, &ip_list, &count, got_realm);
if (!NT_STATUS_IS_OK(status)) {
/* fall back to netbios if we can */
if ( got_realm && !lp_disable_netbios() ) {
@@ -331,6 +333,7 @@ again:
if ( ads_try_connect(ads, server) ) {
SAFE_FREE(ip_list);
+ SAFE_FREE(sitename);
return NT_STATUS_OK;
}
@@ -339,7 +342,19 @@ again:
}
SAFE_FREE(ip_list);
-
+
+ /* In case we failed to contact one of our closest DC on our site we
+ * need to try to find another DC, retry with a site-less SRV DNS query
+ * - Guenther */
+
+ if (sitename) {
+ DEBUG(1,("ads_find_dc: failed to find a valid DC on our site (%s), "
+ "trying to find another DC\n", sitename));
+ SAFE_FREE(sitename);
+ namecache_delete(realm, 0x1C);
+ goto again;
+ }
+
return NT_STATUS_NO_LOGON_SERVERS;
}