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

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