Blame SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch

bfd5b6
From 0a0d0f66409eb83e06b7dc50543c2f6c15a36bc4 Mon Sep 17 00:00:00 2001
bfd5b6
From: Alexey A Nikitin <nikitin@amazon.com>
bfd5b6
Date: Mon, 29 Oct 2018 20:40:36 -0700
bfd5b6
Subject: [PATCH] Make 'adcli info' DC location mechanism more compliant with
bfd5b6
 [MS-ADTS] and [MS-NRPC]
bfd5b6
bfd5b6
AD specifications say that DC locator must attempt to find a suitable DC for the client. That means going through all of the DCs in SRV RRs one by one until one of them answers.
bfd5b6
bfd5b6
The problem with adcli's original behavior is that it queries only five DCs from SRV, ever. This becomes a problem if for any reason there is a large number of DCs in the domain from which the client cannot get a CLDAP response.
bfd5b6
---
bfd5b6
 library/addisco.c | 146 +++++++++++++++++++++++++++++-----------------
bfd5b6
 1 file changed, 94 insertions(+), 52 deletions(-)
bfd5b6
bfd5b6
diff --git a/library/addisco.c b/library/addisco.c
bfd5b6
index 8cc5bf0..6e73ead 100644
bfd5b6
--- a/library/addisco.c
bfd5b6
+++ b/library/addisco.c
bfd5b6
@@ -41,8 +41,10 @@
bfd5b6
 #include <string.h>
bfd5b6
 #include <time.h>
bfd5b6
 
bfd5b6
-/* Number of servers to do discovery against */
bfd5b6
-#define DISCO_COUNT 5
bfd5b6
+/* Number of servers to do discovery against.
bfd5b6
+ * For AD DS maximum number of DCs is 1200.
bfd5b6
+ */
bfd5b6
+#define DISCO_COUNT 1200
bfd5b6
 
bfd5b6
 /* The time period in which to do rapid requests */
bfd5b6
 #define DISCO_FEVER  1
bfd5b6
@@ -453,6 +455,51 @@ parse_disco (LDAP *ldap,
bfd5b6
 	return usability;
bfd5b6
 }
bfd5b6
 
bfd5b6
+static int
bfd5b6
+ldap_disco_poller (LDAP **ldap,
bfd5b6
+                   LDAPMessage **message,
bfd5b6
+                   adcli_disco **results,
bfd5b6
+                   const char **addrs)
bfd5b6
+{
bfd5b6
+	int found = ADCLI_DISCO_UNUSABLE;
bfd5b6
+	int close_ldap;
bfd5b6
+	int parsed;
bfd5b6
+	int ret = 0;
bfd5b6
+	struct timeval tvpoll = { 0, 0 };
bfd5b6
+
bfd5b6
+	switch (ldap_result (*ldap, LDAP_RES_ANY, 1, &tvpoll, message)) {
bfd5b6
+		case LDAP_RES_SEARCH_ENTRY:
bfd5b6
+		case LDAP_RES_SEARCH_RESULT:
bfd5b6
+			parsed = parse_disco (*ldap, *addrs, *message, results);
bfd5b6
+			if (parsed > found)
bfd5b6
+				found = parsed;
bfd5b6
+			ldap_msgfree (*message);
bfd5b6
+			close_ldap = 1;
bfd5b6
+			break;
bfd5b6
+		case -1:
bfd5b6
+			ldap_get_option (*ldap, LDAP_OPT_RESULT_CODE, &ret;;
bfd5b6
+			close_ldap = 1;
bfd5b6
+			break;
bfd5b6
+		default:
bfd5b6
+			ldap_msgfree (*message);
bfd5b6
+			close_ldap = 0;
bfd5b6
+			break;
bfd5b6
+	}
bfd5b6
+
bfd5b6
+	if (ret != LDAP_SUCCESS) {
bfd5b6
+		_adcli_ldap_handle_failure (*ldap, ADCLI_ERR_CONFIG,
bfd5b6
+		                            "Couldn't perform discovery search");
bfd5b6
+	}
bfd5b6
+
bfd5b6
+	/* Done with this connection */
bfd5b6
+	if (close_ldap) {
bfd5b6
+		ldap_unbind_ext_s (*ldap, NULL, NULL);
bfd5b6
+		*ldap = NULL;
bfd5b6
+	}
bfd5b6
+
bfd5b6
+	return found;
bfd5b6
+}
bfd5b6
+
bfd5b6
 static int
bfd5b6
 ldap_disco (const char *domain,
bfd5b6
             srvinfo *srv,
bfd5b6
@@ -477,6 +524,7 @@ ldap_disco (const char *domain,
bfd5b6
 	int num, i;
bfd5b6
 	int ret;
bfd5b6
 	int have_any = 0;
bfd5b6
+	struct timeval interval;
bfd5b6
 
bfd5b6
 	if (domain) {
bfd5b6
 		value = _adcli_ldap_escape_filter (domain);
bfd5b6
@@ -540,7 +588,6 @@ ldap_disco (const char *domain,
bfd5b6
 				version = LDAP_VERSION3;
bfd5b6
 				ldap_set_option (ldap[num], LDAP_OPT_PROTOCOL_VERSION, &version);
bfd5b6
 				ldap_set_option (ldap[num], LDAP_OPT_REFERRALS , 0);
bfd5b6
-				_adcli_info ("Sending netlogon pings to domain controller: %s", url);
bfd5b6
 				addrs[num] = srv->hostname;
bfd5b6
 				have_any = 1;
bfd5b6
 				num++;
bfd5b6
@@ -555,70 +602,65 @@ ldap_disco (const char *domain,
bfd5b6
 		freeaddrinfo (res);
bfd5b6
 	}
bfd5b6
 
bfd5b6
-	/* Wait for the first response. Poor mans fd watch */
bfd5b6
-	for (started = now = time (NULL);
bfd5b6
-	     have_any && found != ADCLI_DISCO_USABLE && now < started + DISCO_TIME;
bfd5b6
-	     now = time (NULL)) {
bfd5b6
+	/* Initial send and short time wait */
bfd5b6
+	interval.tv_sec = 0;
bfd5b6
+	for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
bfd5b6
+		int parsed;
bfd5b6
+
bfd5b6
+		if (NULL == ldap[i])
bfd5b6
+			continue;
bfd5b6
 
bfd5b6
-		struct timeval tvpoll = { 0, 0 };
bfd5b6
-		struct timeval interval;
bfd5b6
+		have_any = 1;
bfd5b6
+		_adcli_info ("Sending NetLogon ping to domain controller: %s", addrs[i]);
bfd5b6
 
bfd5b6
-		/* If in the initial period, send feverishly */
bfd5b6
-		if (now < started + DISCO_FEVER) {
bfd5b6
-			interval.tv_sec = 0;
bfd5b6
-			interval.tv_usec = 100 * 1000;
bfd5b6
+		ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
bfd5b6
+		                       filter, attrs, 0, NULL, NULL, NULL,
bfd5b6
+		                       -1, &msgidp);
bfd5b6
+
bfd5b6
+		if (ret != LDAP_SUCCESS) {
bfd5b6
+			_adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
bfd5b6
+			                            "Couldn't perform discovery search");
bfd5b6
+			ldap_unbind_ext_s (ldap[i], NULL, NULL);
bfd5b6
+			ldap[i] = NULL;
bfd5b6
+		}
bfd5b6
+
bfd5b6
+		/* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first
bfd5b6
+		 * five DCs are given 0.4 seconds timeout, next five are given 0.2
bfd5b6
+		 * seconds, and the rest are given 0.1 seconds
bfd5b6
+		 */
bfd5b6
+		if (i < 5) {
bfd5b6
+			interval.tv_usec = 400000;
bfd5b6
+		} else if (i < 10) {
bfd5b6
+			interval.tv_usec = 200000;
bfd5b6
 		} else {
bfd5b6
-			interval.tv_sec = 1;
bfd5b6
-			interval.tv_usec = 0;
bfd5b6
+			interval.tv_usec = 100000;
bfd5b6
 		}
bfd5b6
+		select (0, NULL, NULL, NULL, &interval);
bfd5b6
+
bfd5b6
+		parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
bfd5b6
+		if (parsed > found)
bfd5b6
+			found = parsed;
bfd5b6
+	}
bfd5b6
+
bfd5b6
+	/* Wait some more until LDAP timeout (DISCO_TIME) */
bfd5b6
+	for (started = now = time (NULL);
bfd5b6
+	     have_any && ADCLI_DISCO_UNUSABLE == found && now < started + DISCO_TIME;
bfd5b6
+	     now = time (NULL)) {
bfd5b6
 
bfd5b6
 		select (0, NULL, NULL, NULL, &interval);
bfd5b6
 
bfd5b6
 		have_any = 0;
bfd5b6
-		for (i = 0; found != ADCLI_DISCO_USABLE && i < num; i++) {
bfd5b6
-			int close_ldap;
bfd5b6
+		for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
bfd5b6
 			int parsed;
bfd5b6
 
bfd5b6
 			if (ldap[i] == NULL)
bfd5b6
 				continue;
bfd5b6
 
bfd5b6
-			ret = 0;
bfd5b6
 			have_any = 1;
bfd5b6
-			switch (ldap_result (ldap[i], LDAP_RES_ANY, 1, &tvpoll, &message)) {
bfd5b6
-			case LDAP_RES_SEARCH_ENTRY:
bfd5b6
-			case LDAP_RES_SEARCH_RESULT:
bfd5b6
-				parsed = parse_disco (ldap[i], addrs[i], message, results);
bfd5b6
-				if (parsed > found)
bfd5b6
-					found = parsed;
bfd5b6
-				ldap_msgfree (message);
bfd5b6
-				close_ldap = 1;
bfd5b6
-				break;
bfd5b6
-			case 0:
bfd5b6
-				ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
bfd5b6
-				                       filter, attrs, 0, NULL, NULL, NULL,
bfd5b6
-				                       -1, &msgidp);
bfd5b6
-				close_ldap = (ret != 0);
bfd5b6
-				break;
bfd5b6
-			case -1:
bfd5b6
-				ldap_get_option (ldap[i], LDAP_OPT_RESULT_CODE, &ret;;
bfd5b6
-				close_ldap = 1;
bfd5b6
-				break;
bfd5b6
-			default:
bfd5b6
-				ldap_msgfree (message);
bfd5b6
-				close_ldap = 0;
bfd5b6
-				break;
bfd5b6
-			}
bfd5b6
-
bfd5b6
-			if (ret != LDAP_SUCCESS) {
bfd5b6
-				_adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
bfd5b6
-				                            "Couldn't perform discovery search");
bfd5b6
-			}
bfd5b6
 
bfd5b6
-			/* Done with this connection */
bfd5b6
-			if (close_ldap) {
bfd5b6
-				ldap_unbind_ext_s (ldap[i], NULL, NULL);
bfd5b6
-				ldap[i] = NULL;
bfd5b6
-			}
bfd5b6
+			parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
bfd5b6
+			if (parsed > found)
bfd5b6
+				found = parsed;
bfd5b6
 		}
bfd5b6
 	}
bfd5b6
 
bfd5b6
-- 
bfd5b6
2.21.0
bfd5b6