diff --git a/SOURCES/0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch b/SOURCES/0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch
new file mode 100644
index 0000000..81d6e2c
--- /dev/null
+++ b/SOURCES/0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch
@@ -0,0 +1,60 @@
+From 158468507bb723aa62196846749c23c121d4b298 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 8 Apr 2019 10:55:39 +0200
+Subject: [PATCH] Do not use arcfour-hmac-md5 when discovering the salt
+
+Since the arcfour-hmac-md5 encryption types does not use salts it cannot
+be used to discover the right salt.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1683745
+
+diff --git a/library/adkrb5.c b/library/adkrb5.c
+index da835d7..be3ede5 100644
+--- a/library/adkrb5.c
++++ b/library/adkrb5.c
+@@ -395,15 +395,33 @@ _adcli_krb5_keytab_discover_salt (krb5_context k5,
+ 	krb5_keytab scratch;
+ 	krb5_error_code code;
+ 	int i;
++	krb5_enctype *salt_enctypes = NULL;
++	size_t c;
++	size_t s;
+ 
+ 	/* TODO: This should be a unique name */
+ 
+ 	code = krb5_kt_resolve (k5, "MEMORY:adcli-discover-salt", &scratch);
+ 	return_val_if_fail (code == 0, code);
+ 
++	for (c = 0; enctypes[c] != 0; c++); /* count enctypes */
++	salt_enctypes = calloc (c + 1, sizeof (krb5_enctype));
++	return_val_if_fail (salt_enctypes != NULL, ENOMEM);
++
++	/* ENCTYPE_ARCFOUR_HMAC does not use salts, so it cannot be used to
++	 * discover the right salt. */
++	s = 0;
++	for (c = 0; enctypes[c] != 0; c++) {
++		if (enctypes[c] == ENCTYPE_ARCFOUR_HMAC) {
++			continue;
++		}
++
++		salt_enctypes[s++] = enctypes[c];
++	}
++
+ 	for (i = 0; salts[i].data != NULL; i++) {
+ 		code = _adcli_krb5_keytab_test_salt (k5, scratch, principal, kvno,
+-		                                     password, enctypes, &salts[i]);
++		                                     password, salt_enctypes, &salts[i]);
+ 		if (code == 0) {
+ 			*discovered = i;
+ 			break;
+@@ -412,6 +430,7 @@ _adcli_krb5_keytab_discover_salt (krb5_context k5,
+ 		}
+ 	}
+ 
++	free (salt_enctypes);
+ 	krb5_kt_close (k5, scratch);
+ 	return code;
+ }
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-Fix-for-issue-found-by-Coverity.patch b/SOURCES/0001-Fix-for-issue-found-by-Coverity.patch
new file mode 100644
index 0000000..6706ba5
--- /dev/null
+++ b/SOURCES/0001-Fix-for-issue-found-by-Coverity.patch
@@ -0,0 +1,26 @@
+From 5da6d34e2659f915e830932fd366c635801ecd91 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 12 Aug 2019 17:28:20 +0200
+Subject: [PATCH] Fix for issue found by Coverity
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 53cd812..524663a 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -2681,7 +2681,10 @@ adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll)
+ 	for (c = 0; cur_enctypes[c] != 0; c++);
+ 
+ 	new_enctypes = calloc (c + 1, sizeof (krb5_enctype));
+-	return_val_if_fail (new_enctypes != NULL, NULL);
++	if (new_enctypes == NULL) {
++		krb5_free_enctypes (k5, permitted_enctypes);
++		return NULL;
++	}
+ 
+ 	n = 0;
+ 	for (c = 0; cur_enctypes[c] != 0; c++) {
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch b/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch
new file mode 100644
index 0000000..c7e698e
--- /dev/null
+++ b/SOURCES/0001-Fix-for-issues-found-by-Coverity.patch
@@ -0,0 +1,43 @@
+From 3c93c96eb6ea2abd3869921ee4c89e1a4d9e4c44 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 14 Aug 2018 13:08:52 +0200
+Subject: [PATCH] Fix for issues found by Coverity
+
+---
+ library/adenroll.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 02bd9e3..de2242a 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -1575,7 +1575,7 @@ load_host_keytab (adcli_enroll *enroll)
+ 	}
+ 
+ 	krb5_free_context (k5);
+-	return ADCLI_SUCCESS;
++	return res;
+ }
+ 
+ typedef struct {
+@@ -1756,12 +1756,12 @@ add_principal_to_keytab (adcli_enroll *enroll,
+ 		                                       enroll->kvno, &password, enctypes, &salts[*which_salt]);
+ 
+ 		free_principal_salts (k5, salts);
++	}
+ 
+-		if (code != 0) {
+-			_adcli_err ("Couldn't add keytab entries: %s: %s",
+-			            enroll->keytab_name, krb5_get_error_message (k5, code));
+-			return ADCLI_ERR_FAIL;
+-		}
++	if (code != 0) {
++		_adcli_err ("Couldn't add keytab entries: %s: %s",
++		            enroll->keytab_name, krb5_get_error_message (k5, code));
++		return ADCLI_ERR_FAIL;
+ 	}
+ 
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch b/SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch
new file mode 100644
index 0000000..770f49c
--- /dev/null
+++ b/SOURCES/0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch
@@ -0,0 +1,216 @@
+From 0a0d0f66409eb83e06b7dc50543c2f6c15a36bc4 Mon Sep 17 00:00:00 2001
+From: Alexey A Nikitin <nikitin@amazon.com>
+Date: Mon, 29 Oct 2018 20:40:36 -0700
+Subject: [PATCH] Make 'adcli info' DC location mechanism more compliant with
+ [MS-ADTS] and [MS-NRPC]
+
+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.
+
+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.
+---
+ library/addisco.c | 146 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 94 insertions(+), 52 deletions(-)
+
+diff --git a/library/addisco.c b/library/addisco.c
+index 8cc5bf0..6e73ead 100644
+--- a/library/addisco.c
++++ b/library/addisco.c
+@@ -41,8 +41,10 @@
+ #include <string.h>
+ #include <time.h>
+ 
+-/* Number of servers to do discovery against */
+-#define DISCO_COUNT 5
++/* Number of servers to do discovery against.
++ * For AD DS maximum number of DCs is 1200.
++ */
++#define DISCO_COUNT 1200
+ 
+ /* The time period in which to do rapid requests */
+ #define DISCO_FEVER  1
+@@ -453,6 +455,51 @@ parse_disco (LDAP *ldap,
+ 	return usability;
+ }
+ 
++static int
++ldap_disco_poller (LDAP **ldap,
++                   LDAPMessage **message,
++                   adcli_disco **results,
++                   const char **addrs)
++{
++	int found = ADCLI_DISCO_UNUSABLE;
++	int close_ldap;
++	int parsed;
++	int ret = 0;
++	struct timeval tvpoll = { 0, 0 };
++
++	switch (ldap_result (*ldap, LDAP_RES_ANY, 1, &tvpoll, message)) {
++		case LDAP_RES_SEARCH_ENTRY:
++		case LDAP_RES_SEARCH_RESULT:
++			parsed = parse_disco (*ldap, *addrs, *message, results);
++			if (parsed > found)
++				found = parsed;
++			ldap_msgfree (*message);
++			close_ldap = 1;
++			break;
++		case -1:
++			ldap_get_option (*ldap, LDAP_OPT_RESULT_CODE, &ret);
++			close_ldap = 1;
++			break;
++		default:
++			ldap_msgfree (*message);
++			close_ldap = 0;
++			break;
++	}
++
++	if (ret != LDAP_SUCCESS) {
++		_adcli_ldap_handle_failure (*ldap, ADCLI_ERR_CONFIG,
++		                            "Couldn't perform discovery search");
++	}
++
++	/* Done with this connection */
++	if (close_ldap) {
++		ldap_unbind_ext_s (*ldap, NULL, NULL);
++		*ldap = NULL;
++	}
++
++	return found;
++}
++
+ static int
+ ldap_disco (const char *domain,
+             srvinfo *srv,
+@@ -477,6 +524,7 @@ ldap_disco (const char *domain,
+ 	int num, i;
+ 	int ret;
+ 	int have_any = 0;
++	struct timeval interval;
+ 
+ 	if (domain) {
+ 		value = _adcli_ldap_escape_filter (domain);
+@@ -540,7 +588,6 @@ ldap_disco (const char *domain,
+ 				version = LDAP_VERSION3;
+ 				ldap_set_option (ldap[num], LDAP_OPT_PROTOCOL_VERSION, &version);
+ 				ldap_set_option (ldap[num], LDAP_OPT_REFERRALS , 0);
+-				_adcli_info ("Sending netlogon pings to domain controller: %s", url);
+ 				addrs[num] = srv->hostname;
+ 				have_any = 1;
+ 				num++;
+@@ -555,70 +602,65 @@ ldap_disco (const char *domain,
+ 		freeaddrinfo (res);
+ 	}
+ 
+-	/* Wait for the first response. Poor mans fd watch */
+-	for (started = now = time (NULL);
+-	     have_any && found != ADCLI_DISCO_USABLE && now < started + DISCO_TIME;
+-	     now = time (NULL)) {
++	/* Initial send and short time wait */
++	interval.tv_sec = 0;
++	for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
++		int parsed;
++
++		if (NULL == ldap[i])
++			continue;
+ 
+-		struct timeval tvpoll = { 0, 0 };
+-		struct timeval interval;
++		have_any = 1;
++		_adcli_info ("Sending NetLogon ping to domain controller: %s", addrs[i]);
+ 
+-		/* If in the initial period, send feverishly */
+-		if (now < started + DISCO_FEVER) {
+-			interval.tv_sec = 0;
+-			interval.tv_usec = 100 * 1000;
++		ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
++		                       filter, attrs, 0, NULL, NULL, NULL,
++		                       -1, &msgidp);
++
++		if (ret != LDAP_SUCCESS) {
++			_adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
++			                            "Couldn't perform discovery search");
++			ldap_unbind_ext_s (ldap[i], NULL, NULL);
++			ldap[i] = NULL;
++		}
++
++		/* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first
++		 * five DCs are given 0.4 seconds timeout, next five are given 0.2
++		 * seconds, and the rest are given 0.1 seconds
++		 */
++		if (i < 5) {
++			interval.tv_usec = 400000;
++		} else if (i < 10) {
++			interval.tv_usec = 200000;
+ 		} else {
+-			interval.tv_sec = 1;
+-			interval.tv_usec = 0;
++			interval.tv_usec = 100000;
+ 		}
++		select (0, NULL, NULL, NULL, &interval);
++
++		parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
++		if (parsed > found)
++			found = parsed;
++	}
++
++	/* Wait some more until LDAP timeout (DISCO_TIME) */
++	for (started = now = time (NULL);
++	     have_any && ADCLI_DISCO_UNUSABLE == found && now < started + DISCO_TIME;
++	     now = time (NULL)) {
+ 
+ 		select (0, NULL, NULL, NULL, &interval);
+ 
+ 		have_any = 0;
+-		for (i = 0; found != ADCLI_DISCO_USABLE && i < num; i++) {
+-			int close_ldap;
++		for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
+ 			int parsed;
+ 
+ 			if (ldap[i] == NULL)
+ 				continue;
+ 
+-			ret = 0;
+ 			have_any = 1;
+-			switch (ldap_result (ldap[i], LDAP_RES_ANY, 1, &tvpoll, &message)) {
+-			case LDAP_RES_SEARCH_ENTRY:
+-			case LDAP_RES_SEARCH_RESULT:
+-				parsed = parse_disco (ldap[i], addrs[i], message, results);
+-				if (parsed > found)
+-					found = parsed;
+-				ldap_msgfree (message);
+-				close_ldap = 1;
+-				break;
+-			case 0:
+-				ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
+-				                       filter, attrs, 0, NULL, NULL, NULL,
+-				                       -1, &msgidp);
+-				close_ldap = (ret != 0);
+-				break;
+-			case -1:
+-				ldap_get_option (ldap[i], LDAP_OPT_RESULT_CODE, &ret);
+-				close_ldap = 1;
+-				break;
+-			default:
+-				ldap_msgfree (message);
+-				close_ldap = 0;
+-				break;
+-			}
+-
+-			if (ret != LDAP_SUCCESS) {
+-				_adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
+-				                            "Couldn't perform discovery search");
+-			}
+ 
+-			/* Done with this connection */
+-			if (close_ldap) {
+-				ldap_unbind_ext_s (ldap[i], NULL, NULL);
+-				ldap[i] = NULL;
+-			}
++			parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
++			if (parsed > found)
++				found = parsed;
+ 		}
+ 	}
+ 
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch b/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch
new file mode 100644
index 0000000..a1f63cc
--- /dev/null
+++ b/SOURCES/0001-Use-GSS-SPNEGO-if-available.patch
@@ -0,0 +1,124 @@
+From a4c35124b5c83603333ee7518d0783ff708e86df Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 11 Oct 2019 16:39:25 +0200
+Subject: [PATCH 1/2] Use GSS-SPNEGO if available
+
+Currently adcli uses the GSSAPI SASL mechanism for LDAP authentication
+and to establish encryption. While this works in general it does not
+handle some of the more advanced features which can be required by AD
+DCs.
+
+The GSS-SPNEGO mechanism can handle them and is used with this patch by
+adcli if the AD DC indicates that it supports it.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1762420
+---
+ library/adconn.c | 35 ++++++++++++++++++++++++++++++++++-
+ library/adconn.h |  3 +++
+ 2 files changed, 37 insertions(+), 1 deletion(-)
+
+diff --git a/library/adconn.c b/library/adconn.c
+index f6c23d3..a3f4548 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -77,6 +77,7 @@ struct _adcli_conn_ctx {
+ 	char *default_naming_context;
+ 	char *configuration_naming_context;
+ 	char **supported_capabilities;
++	char **supported_sasl_mechs;
+ 
+ 	/* Connect state */
+ 	LDAP *ldap;
+@@ -845,6 +846,7 @@ connect_and_lookup_naming (adcli_conn *conn,
+ 		"defaultNamingContext",
+ 		"configurationNamingContext",
+ 		"supportedCapabilities",
++		"supportedSASLMechanisms",
+ 		NULL
+ 	};
+ 
+@@ -897,6 +899,11 @@ connect_and_lookup_naming (adcli_conn *conn,
+ 		                                                         "supportedCapabilities");
+ 	}
+ 
++	if (conn->supported_sasl_mechs == NULL) {
++		conn->supported_sasl_mechs = _adcli_ldap_parse_values (ldap, results,
++		                                                       "supportedSASLMechanisms");
++	}
++
+ 	ldap_msgfree (results);
+ 
+ 	if (conn->default_naming_context == NULL) {
+@@ -1022,6 +1029,7 @@ authenticate_to_directory (adcli_conn *conn)
+ 	OM_uint32 minor;
+ 	ber_len_t ssf;
+ 	int ret;
++	const char *mech = "GSSAPI";
+ 
+ 	if (conn->ldap_authenticated)
+ 		return ADCLI_SUCCESS;
+@@ -1038,7 +1046,11 @@ authenticate_to_directory (adcli_conn *conn)
+ 	ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf);
+ 	return_unexpected_if_fail (ret == 0);
+ 
+-	ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, "GSSAPI", NULL, NULL,
++	if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")) {
++		mech =  "GSS-SPNEGO";
++	}
++
++	ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, mech, NULL, NULL,
+ 	                                    LDAP_SASL_QUIET, sasl_interact, NULL);
+ 
+ 	/* Clear the credential cache GSSAPI to use (for this thread) */
+@@ -1231,6 +1243,7 @@ conn_free (adcli_conn *conn)
+ 	free (conn->default_naming_context);
+ 	free (conn->configuration_naming_context);
+ 	_adcli_strv_free (conn->supported_capabilities);
++	_adcli_strv_free (conn->supported_sasl_mechs);
+ 
+ 	free (conn->computer_name);
+ 	free (conn->host_fqdn);
+@@ -1593,6 +1606,26 @@ adcli_conn_server_has_capability (adcli_conn *conn,
+ 	return 0;
+ }
+ 
++bool
++adcli_conn_server_has_sasl_mech (adcli_conn *conn,
++                                 const char *mech)
++{
++	int i;
++
++	return_val_if_fail (conn != NULL, false);
++	return_val_if_fail (mech != NULL, false);
++
++	if (!conn->supported_sasl_mechs)
++		return false;
++
++	for (i = 0; conn->supported_sasl_mechs[i] != NULL; i++) {
++		if (strcasecmp (mech, conn->supported_sasl_mechs[i]) == 0)
++			return true;
++	}
++
++	return false;
++}
++
+ bool adcli_conn_is_writeable (adcli_conn *conn)
+ {
+ 	disco_dance_if_necessary (conn);
+diff --git a/library/adconn.h b/library/adconn.h
+index 13cfd32..8e88045 100644
+--- a/library/adconn.h
++++ b/library/adconn.h
+@@ -146,6 +146,9 @@ void                adcli_conn_set_krb5_conf_dir     (adcli_conn *conn,
+ int                 adcli_conn_server_has_capability (adcli_conn *conn,
+                                                       const char *capability);
+ 
++bool                adcli_conn_server_has_sasl_mech  (adcli_conn *conn,
++                                                      const char *mech);
++
+ bool                adcli_conn_is_writeable          (adcli_conn *conn);
+ 
+ #endif /* ADCONN_H_ */
+-- 
+2.21.1
+
diff --git a/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch b/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch
new file mode 100644
index 0000000..ad69b70
--- /dev/null
+++ b/SOURCES/0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch
@@ -0,0 +1,80 @@
+From 341974aae7d0755fc32a0b7e2b34d8e1ef60d195 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 20 Dec 2018 21:05:35 +0100
+Subject: [PATCH 1/4] adenroll: make sure only allowed enctypes are used in
+ FIPS mode
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1717355
+---
+ library/adenroll.c | 36 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 35 insertions(+), 1 deletion(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 52aa8a8..f617f28 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -41,11 +41,19 @@
+ #include <netdb.h>
+ #include <stdio.h>
+ #include <unistd.h>
++#include <sys/stat.h>
++#include <fcntl.h>
+ 
+ #ifndef SAMBA_DATA_TOOL
+ #define SAMBA_DATA_TOOL "/usr/bin/net"
+ #endif
+ 
++static krb5_enctype v60_later_enctypes_fips[] = {
++	ENCTYPE_AES256_CTS_HMAC_SHA1_96,
++	ENCTYPE_AES128_CTS_HMAC_SHA1_96,
++	0
++};
++
+ static krb5_enctype v60_later_enctypes[] = {
+ 	ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ 	ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+@@ -2594,6 +2602,28 @@ adcli_enroll_set_keytab_name (adcli_enroll *enroll,
+ 	enroll->keytab_name_is_krb5 = 0;
+ }
+ 
++#define PROC_SYS_FIPS "/proc/sys/crypto/fips_enabled"
++
++static bool adcli_fips_enabled (void)
++{
++	int fd;
++	ssize_t len;
++	char buf[8];
++
++	fd = open (PROC_SYS_FIPS, O_RDONLY);
++	if (fd != -1) {
++		len = read (fd, buf, sizeof (buf));
++		close (fd);
++		/* Assume FIPS in enabled if PROC_SYS_FIPS contains a
++		 * non-0 value. */
++		if ( ! (len == 2 && buf[0] == '0' && buf[1] == '\n')) {
++			return true;
++		}
++	}
++
++	return false;
++}
++
+ krb5_enctype *
+ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
+ {
+@@ -2602,7 +2632,11 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
+ 		return enroll->keytab_enctypes;
+ 
+ 	if (adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID))
+-		return v60_later_enctypes;
++		if (adcli_fips_enabled ()) {
++			return v60_later_enctypes_fips;
++		} else {
++			return v60_later_enctypes;
++		}
+ 	else
+ 		return v51_earlier_enctypes;
+ }
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-doc-explain-how-to-force-password-reset.patch b/SOURCES/0001-doc-explain-how-to-force-password-reset.patch
new file mode 100644
index 0000000..01e694d
--- /dev/null
+++ b/SOURCES/0001-doc-explain-how-to-force-password-reset.patch
@@ -0,0 +1,27 @@
+From 9b187095edb8c914238419ed51fef6041864f4fc Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 26 Aug 2019 13:33:24 +0200
+Subject: [PATCH] doc: explain how to force password reset
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1738573
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 094f577..4f201e0 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -330,7 +330,11 @@ Password for Administrator:
+ 			important here is currently the
+ 			<option>workgroup</option> option, see
+ 			<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+-			for details.</para></listitem>
++			for details.</para>
++			<para>Note that if the machine account password is not
++			older than 30 days, you have to pass
++			<option>--computer-password-lifetime=0</option> to
++			force the update.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch b/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch
new file mode 100644
index 0000000..769a022
--- /dev/null
+++ b/SOURCES/0002-adconn-add-adcli_conn_set_krb5_context.patch
@@ -0,0 +1,52 @@
+From 2fc259a88be618871cea8ff8b8a13bd3e040aea4 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 13 Jun 2019 17:23:47 +0200
+Subject: [PATCH 2/4] adconn: add adcli_conn_set_krb5_context
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3
+---
+ library/adconn.c | 13 +++++++++++++
+ library/adconn.h |  3 +++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/library/adconn.c b/library/adconn.c
+index f6c23d3..bcaced8 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -1406,6 +1406,19 @@ adcli_conn_get_krb5_context (adcli_conn *conn)
+ 	return conn->k5;
+ }
+ 
++void
++adcli_conn_set_krb5_context (adcli_conn *conn,
++                             krb5_context k5)
++{
++	return_if_fail (conn != NULL);
++
++	if (conn->k5 != NULL) {
++		krb5_free_context (conn->k5);
++	}
++
++	conn->k5 = k5;
++}
++
+ const char *
+ adcli_conn_get_login_user (adcli_conn *conn)
+ {
+diff --git a/library/adconn.h b/library/adconn.h
+index 13cfd32..1ad5715 100644
+--- a/library/adconn.h
++++ b/library/adconn.h
+@@ -97,6 +97,9 @@ LDAP *              adcli_conn_get_ldap_connection   (adcli_conn *conn);
+ 
+ krb5_context        adcli_conn_get_krb5_context      (adcli_conn *conn);
+ 
++void                adcli_conn_set_krb5_context      (adcli_conn *conn,
++                                                      krb5_context k5);
++
+ const char *        adcli_conn_get_computer_name     (adcli_conn *conn);
+ 
+ void                adcli_conn_set_computer_name     (adcli_conn *conn,
+-- 
+2.21.0
+
diff --git a/SOURCES/0002-add-option-use-ldaps.patch b/SOURCES/0002-add-option-use-ldaps.patch
new file mode 100644
index 0000000..8e97803
--- /dev/null
+++ b/SOURCES/0002-add-option-use-ldaps.patch
@@ -0,0 +1,370 @@
+From 196163b419f3a22c78bd14095b91822fe08aa595 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 19 Dec 2019 07:22:33 +0100
+Subject: [PATCH 2/2] add option use-ldaps
+
+In general using the LDAP port with GSS-SPNEGO should satifiy all
+requirements an AD DC should have for authentication on an encrypted
+LDAP connection.
+
+But if e.g. the LDAP port is blocked by a firewall using the LDAPS port
+with TLS encryption might be an alternative. For this use case the
+--use-ldaps option is added.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1762420
+---
+ doc/adcli.xml    | 24 +++++++++++++++
+ library/adconn.c | 79 ++++++++++++++++++++++++++++++++++++++++++------
+ library/adconn.h |  4 +++
+ tools/computer.c |  9 ++++++
+ tools/entry.c    | 11 +++++++
+ 5 files changed, 118 insertions(+), 9 deletions(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 9605b4a..3cefe48 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -123,6 +123,30 @@
+ 			If not specified, then an appropriate domain controller
+ 			is automatically discovered.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--use-ldaps</option></term>
++			<listitem><para>Connect to the domain controller
++			with LDAPS. By default the LDAP port is used and SASL
++			GSS-SPNEGO or GSSAPI is used for authentication and to
++			establish encryption. This should satisfy all
++			requirements set on the server side and LDAPS should
++			only be used if the LDAP port is not accessible due to
++			firewalls or other reasons.</para>
++			<para> Please note that the place where CA certificates
++			can be found to validate the AD DC certificates
++			must be configured in the OpenLDAP configuration
++			file, e.g. <filename>/etc/openldap/ldap.conf</filename>.
++			As an alternative it can be specified with the help of
++			an environment variable, e.g.
++<programlisting>
++$ LDAPTLS_CACERT=/path/to/ad_dc_ca_cert.pem adcli join --use-ldaps -D domain.example.com
++...
++</programlisting>
++			Please see
++			<citerefentry><refentrytitle>ldap.conf</refentrytitle>
++			<manvolnum>5</manvolnum></citerefentry> for details.
++			</para></listitem>
++		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-C, --login-ccache=<parameter>ccache_name</parameter></option></term>
+ 			<listitem><para>Use the specified kerberos credential
+diff --git a/library/adconn.c b/library/adconn.c
+index a3f4548..8a55776 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -70,6 +70,7 @@ struct _adcli_conn_ctx {
+ 	char *domain_name;
+ 	char *domain_realm;
+ 	char *domain_controller;
++	bool use_ldaps;
+ 	char *canonical_host;
+ 	char *domain_short;
+ 	char *domain_sid;
+@@ -773,7 +774,8 @@ int ldap_init_fd (ber_socket_t fd, int proto, LDAP_CONST char *url, struct ldap
+ 
+ static LDAP *
+ connect_to_address (const char *host,
+-                    const char *canonical_host)
++                    const char *canonical_host,
++                    bool use_ldaps)
+ {
+ 	struct addrinfo *res = NULL;
+ 	struct addrinfo *ai;
+@@ -783,6 +785,16 @@ connect_to_address (const char *host,
+ 	char *url;
+ 	int sock;
+ 	int rc;
++	int opt_rc;
++	const char *port = "389";
++	const char *proto = "ldap";
++	const char *errmsg = NULL;
++
++	if (use_ldaps) {
++		port = "636";
++		proto = "ldaps";
++		_adcli_info ("Using LDAPS to connect to %s", host);
++	}
+ 
+ 	memset (&hints, '\0', sizeof(hints));
+ #ifdef AI_ADDRCONFIG
+@@ -794,7 +806,7 @@ connect_to_address (const char *host,
+ 	if (!canonical_host)
+ 		canonical_host = host;
+ 
+-	rc = getaddrinfo (host, "389", &hints, &res);
++	rc = getaddrinfo (host, port, &hints, &res);
+ 	if (rc != 0) {
+ 		_adcli_err ("Couldn't resolve host name: %s: %s", host, gai_strerror (rc));
+ 		return NULL;
+@@ -810,7 +822,7 @@ connect_to_address (const char *host,
+ 			close (sock);
+ 		} else {
+ 			error = 0;
+-			if (asprintf (&url, "ldap://%s", canonical_host) < 0)
++			if (asprintf (&url, "%s://%s", proto, canonical_host) < 0)
+ 				return_val_if_reached (NULL);
+ 			rc = ldap_init_fd (sock, 1, url, &ldap);
+ 			free (url);
+@@ -820,6 +832,25 @@ connect_to_address (const char *host,
+ 				            ldap_err2string (rc));
+ 				break;
+ 			}
++
++			if (use_ldaps) {
++				rc = ldap_install_tls (ldap);
++				if (rc != LDAP_SUCCESS) {
++					opt_rc = ldap_get_option (ldap,
++					                          LDAP_OPT_DIAGNOSTIC_MESSAGE,
++					                          (void *) &errmsg);
++					if (opt_rc != LDAP_SUCCESS) {
++						errmsg = NULL;
++					}
++					_adcli_err ("Couldn't initialize TLS [%s]: %s",
++					            ldap_err2string (rc),
++					            errmsg == NULL ? "- no details -"
++					                           : errmsg);
++					ldap_unbind_ext_s (ldap, NULL, NULL);
++					ldap = NULL;
++					break;
++				}
++			}
+ 		}
+ 	}
+ 
+@@ -856,7 +887,8 @@ connect_and_lookup_naming (adcli_conn *conn,
+ 	if (!canonical_host)
+ 		canonical_host = disco->host_addr;
+ 
+-	ldap = connect_to_address (disco->host_addr, canonical_host);
++	ldap = connect_to_address (disco->host_addr, canonical_host,
++	                           adcli_conn_get_use_ldaps (conn));
+ 	if (ldap == NULL)
+ 		return ADCLI_ERR_DIRECTORY;
+ 
+@@ -1041,14 +1073,28 @@ authenticate_to_directory (adcli_conn *conn)
+ 	status = gss_krb5_ccache_name (&minor, conn->login_ccache_name, NULL);
+ 	return_unexpected_if_fail (status == 0);
+ 
+-	/* Clumsily tell ldap + cyrus-sasl that we want encryption */
+-	ssf = 1;
+-	ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf);
+-	return_unexpected_if_fail (ret == 0);
++	if (adcli_conn_get_use_ldaps (conn)) {
++		/* do not use SASL encryption on LDAPS connection */
++		ssf = 0;
++		ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf);
++		return_unexpected_if_fail (ret == 0);
++		ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MAX, &ssf);
++		return_unexpected_if_fail (ret == 0);
++	} else {
++		/* Clumsily tell ldap + cyrus-sasl that we want encryption */
++		ssf = 1;
++		ret = ldap_set_option (conn->ldap, LDAP_OPT_X_SASL_SSF_MIN, &ssf);
++		return_unexpected_if_fail (ret == 0);
++	}
+ 
+-	if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")) {
++	/* There are issues with cryrus-sasl and GSS-SPNEGO with TLS even if
++	 * ssf_max is set to 0. To be on the safe side GSS-SPNEGO is only used
++	 * without LDAPS. */
++	if (adcli_conn_server_has_sasl_mech (conn, "GSS-SPNEGO")
++	                     && !adcli_conn_get_use_ldaps (conn)) {
+ 		mech =  "GSS-SPNEGO";
+ 	}
++	_adcli_info ("Using %s for SASL bind", mech);
+ 
+ 	ret = ldap_sasl_interactive_bind_s (conn->ldap, NULL, mech, NULL, NULL,
+ 	                                    LDAP_SASL_QUIET, sasl_interact, NULL);
+@@ -1230,6 +1276,7 @@ adcli_conn_new (const char *domain_name)
+ 	conn->refs = 1;
+ 	conn->logins_allowed = ADCLI_LOGIN_COMPUTER_ACCOUNT | ADCLI_LOGIN_USER_ACCOUNT;
+ 	adcli_conn_set_domain_name (conn, domain_name);
++	adcli_conn_set_use_ldaps (conn, false);
+ 	return conn;
+ }
+ 
+@@ -1389,6 +1436,20 @@ adcli_conn_set_domain_controller (adcli_conn *conn,
+ 	no_more_disco (conn);
+ }
+ 
++bool
++adcli_conn_get_use_ldaps (adcli_conn *conn)
++{
++	return_val_if_fail (conn != NULL, NULL);
++	return conn->use_ldaps;
++}
++
++void
++adcli_conn_set_use_ldaps (adcli_conn *conn, bool value)
++{
++	return_if_fail (conn != NULL);
++	conn->use_ldaps = value;
++}
++
+ const char *
+ adcli_conn_get_domain_short (adcli_conn *conn)
+ {
+diff --git a/library/adconn.h b/library/adconn.h
+index 8e88045..3e287b1 100644
+--- a/library/adconn.h
++++ b/library/adconn.h
+@@ -89,6 +89,10 @@ const char *        adcli_conn_get_domain_controller (adcli_conn *conn);
+ void                adcli_conn_set_domain_controller (adcli_conn *conn,
+                                                       const char *value);
+ 
++bool                adcli_conn_get_use_ldaps         (adcli_conn *conn);
++void                adcli_conn_set_use_ldaps         (adcli_conn *conn,
++                                                      bool value);
++
+ const char *        adcli_conn_get_domain_short      (adcli_conn *conn);
+ 
+ const char *        adcli_conn_get_domain_sid        (adcli_conn *conn);
+diff --git a/tools/computer.c b/tools/computer.c
+index ac8a203..7bf8f9b 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -112,12 +112,14 @@ typedef enum {
+ 	opt_trusted_for_delegation,
+ 	opt_add_service_principal,
+ 	opt_remove_service_principal,
++	opt_use_ldaps,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+ 	{ opt_domain, "active directory domain name" },
+ 	{ opt_domain_realm, "kerberos realm for the domain" },
+ 	{ opt_domain_controller, "domain controller to connect to" },
++	{ opt_use_ldaps, "use LDAPS port for communication" },
+ 	{ opt_host_fqdn, "override the fully qualified domain name of the\n"
+ 	                 "local machine" },
+ 	{ opt_host_keytab, "filename for the host kerberos keytab" },
+@@ -306,6 +308,9 @@ parse_option (Option opt,
+ 	case opt_remove_service_principal:
+ 		adcli_enroll_add_service_principal_to_remove (enroll, optarg);
+ 		return ADCLI_SUCCESS;
++	case opt_use_ldaps:
++		adcli_conn_set_use_ldaps (conn, true);
++		return ADCLI_SUCCESS;
+ 	case opt_verbose:
+ 		return ADCLI_SUCCESS;
+ 
+@@ -352,6 +357,7 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
+ 		{ "domain-server", required_argument, NULL, opt_domain_controller }, /* compat */
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "user", required_argument, NULL, opt_login_user }, /* compat */
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+@@ -681,6 +687,7 @@ adcli_tool_computer_preset (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "domain-ou", required_argument, NULL, opt_domain_ou },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+@@ -793,6 +800,7 @@ adcli_tool_computer_reset (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "login-type", required_argument, NULL, opt_login_type },
+@@ -881,6 +889,7 @@ adcli_tool_computer_delete (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "no-password", no_argument, 0, opt_no_password },
+diff --git a/tools/entry.c b/tools/entry.c
+index f361845..05e4313 100644
+--- a/tools/entry.c
++++ b/tools/entry.c
+@@ -53,6 +53,7 @@ typedef enum {
+ 	opt_unix_gid,
+ 	opt_unix_shell,
+ 	opt_nis_domain,
++	opt_use_ldaps,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+@@ -67,6 +68,7 @@ static adcli_tool_desc common_usages[] = {
+ 	{ opt_domain, "active directory domain name" },
+ 	{ opt_domain_realm, "kerberos realm for the domain" },
+ 	{ opt_domain_controller, "domain directory server to connect to" },
++	{ opt_use_ldaps, "use LDAPS port for communication" },
+ 	{ opt_login_ccache, "kerberos credential cache file which contains\n"
+ 	                    "ticket to used to connect to the domain" },
+ 	{ opt_login_user, "user (usually administrative) login name of\n"
+@@ -136,6 +138,9 @@ parse_option (Option opt,
+ 			stdin_password = 1;
+ 		}
+ 		return ADCLI_SUCCESS;
++	case opt_use_ldaps:
++		adcli_conn_set_use_ldaps (conn, true);
++		return ADCLI_SUCCESS;
+ 	case opt_verbose:
+ 		return ADCLI_SUCCESS;
+ 	default:
+@@ -172,6 +177,7 @@ adcli_tool_user_create (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "no-password", no_argument, 0, opt_no_password },
+@@ -306,6 +312,7 @@ adcli_tool_user_delete (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "no-password", no_argument, 0, opt_no_password },
+@@ -394,6 +401,7 @@ adcli_tool_group_create (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "domain-ou", required_argument, NULL, opt_domain_ou },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+@@ -496,6 +504,7 @@ adcli_tool_group_delete (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "no-password", no_argument, 0, opt_no_password },
+@@ -622,6 +631,7 @@ adcli_tool_member_add (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "no-password", no_argument, 0, opt_no_password },
+@@ -722,6 +732,7 @@ adcli_tool_member_remove (adcli_conn *conn,
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+ 		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "use-ldaps", no_argument, 0, opt_use_ldaps },
+ 		{ "login-user", required_argument, NULL, opt_login_user },
+ 		{ "login-ccache", optional_argument, NULL, opt_login_ccache },
+ 		{ "no-password", no_argument, 0, opt_no_password },
+-- 
+2.21.1
+
diff --git a/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch b/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch
new file mode 100644
index 0000000..f810c13
--- /dev/null
+++ b/SOURCES/0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch
@@ -0,0 +1,196 @@
+From 0c09070e8beec734e3f0c70e14b0a04788077b73 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 13 Jun 2019 17:25:52 +0200
+Subject: [PATCH 3/4] adenroll: add adcli_enroll_get_permitted_keytab_enctypes
+ with tests
+
+The new call does not only return the current encryption types set in AD
+or a default list but filters them with the list of permitted encryption
+types on the client. This makes sure the client can create and use the
+keys.
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/3
+---
+ library/Makefile.am |   5 ++
+ library/adenroll.c  | 124 ++++++++++++++++++++++++++++++++++++++++++++
+ library/adenroll.h  |   2 +
+ 3 files changed, 131 insertions(+)
+
+diff --git a/library/Makefile.am b/library/Makefile.am
+index 39e8fd1..4829555 100644
+--- a/library/Makefile.am
++++ b/library/Makefile.am
+@@ -40,6 +40,7 @@ check_PROGRAMS = \
+ 	test-util \
+ 	test-ldap \
+ 	test-attrs \
++	test-adenroll \
+ 	$(NULL)
+ 
+ test_seq_SOURCES = seq.c test.c test.h
+@@ -56,6 +57,10 @@ test_attrs_SOURCES = adattrs.c $(test_ldap_SOURCES)
+ test_attrs_CFLAGS = -DATTRS_TESTS
+ test_attrs_LDADD = $(test_ldap_LDADD)
+ 
++test_adenroll_SOURCES = adenroll.c $(test_ldap_SOURCES)
++test_adenroll_CFLAGS = -DADENROLL_TESTS
++test_adenroll_LDADD = $(KRB5_LIBS)
++
+ TESTS = $(check_PROGRAMS)
+ 
+ MEMCHECK_ENV = $(TEST_RUNNER) valgrind --error-exitcode=80 --quiet --trace-children=yes
+diff --git a/library/adenroll.c b/library/adenroll.c
+index f617f28..95c07cd 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -2641,6 +2641,50 @@ adcli_enroll_get_keytab_enctypes (adcli_enroll *enroll)
+ 		return v51_earlier_enctypes;
+ }
+ 
++krb5_enctype *
++adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll)
++{
++	krb5_enctype *cur_enctypes;
++	krb5_enctype *permitted_enctypes;
++	krb5_enctype *new_enctypes;
++	krb5_error_code code;
++	krb5_context k5;
++	size_t c;
++	size_t p;
++	size_t n;
++
++	return_val_if_fail (enroll != NULL, NULL);
++	cur_enctypes = adcli_enroll_get_keytab_enctypes (enroll);
++
++	k5 = adcli_conn_get_krb5_context (enroll->conn);
++	return_val_if_fail (k5 != NULL, NULL);
++
++	code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
++	return_val_if_fail (code == 0, NULL);
++
++	for (c = 0; cur_enctypes[c] != 0; c++);
++
++	new_enctypes = calloc (c + 1, sizeof (krb5_enctype));
++	return_val_if_fail (new_enctypes != NULL, NULL);
++
++	n = 0;
++	for (c = 0; cur_enctypes[c] != 0; c++) {
++		for (p = 0; permitted_enctypes[p] != 0; p++) {
++			if (cur_enctypes[c] == permitted_enctypes[p]) {
++				new_enctypes[n++] = cur_enctypes[c];
++				break;
++			}
++		}
++		if (permitted_enctypes[p] == 0) {
++			_adcli_info ("Encryption type [%d] not permitted.", cur_enctypes[c]);
++		}
++	}
++
++	krb5_free_enctypes (k5, permitted_enctypes);
++
++	return new_enctypes;
++}
++
+ void
+ adcli_enroll_set_keytab_enctypes (adcli_enroll *enroll,
+                                   krb5_enctype *value)
+@@ -2833,3 +2877,83 @@ adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
+ 							    strdup (value), NULL);
+ 	return_if_fail (enroll->service_principals_to_remove != NULL);
+ }
++
++#ifdef ADENROLL_TESTS
++
++#include "test.h"
++
++static void
++test_adcli_enroll_get_permitted_keytab_enctypes (void)
++{
++	krb5_enctype *enctypes;
++	krb5_error_code code;
++	krb5_enctype *permitted_enctypes;
++	krb5_enctype check_enctypes[3] = { 0 };
++	adcli_conn *conn;
++	adcli_enroll *enroll;
++	adcli_result res;
++	krb5_context k5;
++	size_t c;
++
++	conn = adcli_conn_new ("test.dom");
++	assert_ptr_not_null (conn);
++
++	enroll = adcli_enroll_new (conn);
++	assert_ptr_not_null (enroll);
++
++	enctypes = adcli_enroll_get_permitted_keytab_enctypes (NULL);
++	assert_ptr_eq (enctypes, NULL);
++
++	/* krb5 context missing */
++	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
++	assert_ptr_eq (enctypes, NULL);
++
++	/* check that all permitted enctypes can pass */
++	res = _adcli_krb5_init_context (&k5);
++	assert_num_eq (res, ADCLI_SUCCESS);
++
++	adcli_conn_set_krb5_context (conn, k5);
++
++	code = krb5_get_permitted_enctypes (k5, &permitted_enctypes);
++	assert_num_eq (code, 0);
++	assert_ptr_not_null (permitted_enctypes);
++	assert_num_cmp (permitted_enctypes[0], !=, 0);
++
++	adcli_enroll_set_keytab_enctypes (enroll, permitted_enctypes);
++
++	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
++	assert_ptr_not_null (enctypes);
++	for (c = 0; permitted_enctypes[c] != 0; c++) {
++		assert_num_eq (enctypes[c], permitted_enctypes[c]);
++	}
++	assert_num_eq (enctypes[c], 0);
++	krb5_free_enctypes (k5, enctypes);
++
++	/* check that ENCTYPE_UNKNOWN is filtered out */
++	check_enctypes[0] = permitted_enctypes[0];
++	check_enctypes[1] = ENCTYPE_UNKNOWN;
++	check_enctypes[2] = 0;
++	adcli_enroll_set_keytab_enctypes (enroll, check_enctypes);
++
++	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
++	assert_ptr_not_null (enctypes);
++	assert_num_eq (enctypes[0], permitted_enctypes[0]);
++	assert_num_eq (enctypes[1], 0);
++	krb5_free_enctypes (k5, enctypes);
++
++	krb5_free_enctypes (k5, permitted_enctypes);
++
++	adcli_enroll_unref (enroll);
++	adcli_conn_unref (conn);
++}
++
++int
++main (int argc,
++      char *argv[])
++{
++	test_func (test_adcli_enroll_get_permitted_keytab_enctypes,
++	           "/attrs/adcli_enroll_get_permitted_keytab_enctypes");
++	return test_run (argc, argv);
++}
++
++#endif /* ADENROLL_TESTS */
+diff --git a/library/adenroll.h b/library/adenroll.h
+index abbbfd4..1d5d00d 100644
+--- a/library/adenroll.h
++++ b/library/adenroll.h
+@@ -138,6 +138,8 @@ krb5_enctype *     adcli_enroll_get_keytab_enctypes     (adcli_enroll *enroll);
+ void               adcli_enroll_set_keytab_enctypes     (adcli_enroll *enroll,
+                                                          krb5_enctype *enctypes);
+ 
++krb5_enctype *     adcli_enroll_get_permitted_keytab_enctypes (adcli_enroll *enroll);
++
+ const char *       adcli_enroll_get_os_name             (adcli_enroll *enroll);
+ 
+ void               adcli_enroll_set_os_name             (adcli_enroll *enroll,
+-- 
+2.21.0
+
diff --git a/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch b/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch
new file mode 100644
index 0000000..a496e32
--- /dev/null
+++ b/SOURCES/0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch
@@ -0,0 +1,103 @@
+From cc3ef52884a48863a81acbfc741735fe09cd85f7 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 13 Jun 2019 18:27:49 +0200
+Subject: [PATCH 4/4] adenroll: use only enctypes permitted by Kerberos config
+
+Realted to https://gitlab.freedesktop.org/realmd/adcli/issues/3
+---
+ doc/adcli.xml      | 10 ++++++++++
+ library/adenroll.c | 22 +++++++++++++++++++---
+ 2 files changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 9605b4a..094f577 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -342,6 +342,11 @@ Password for Administrator:
+ 		</varlistentry>
+ 	</variablelist>
+ 
++	<para>If supported on the AD side the
++	<option>msDS-supportedEncryptionTypes</option> attribute will be set as
++	well. Either the current value or the default list of AD's supported
++	encryption types filtered by the permitted encryption types of the
++	client's Kerberos configuration are written.</para>
+ </refsect1>
+ 
+ <refsect1 id='updating'>
+@@ -475,6 +480,11 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 		</varlistentry>
+ 	</variablelist>
+ 
++	<para>If supported on the AD side the
++	<option>msDS-supportedEncryptionTypes</option> attribute will be set as
++	well. Either the current value or the default list of AD's supported
++	encryption types filtered by the permitted encryption types of the
++	client's Kerberos configuration are written.</para>
+ </refsect1>
+ 
+ <refsect1 id='testjoin'>
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 95c07cd..53cd812 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -639,6 +639,7 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
+ {
+ 	char *value = NULL;
+ 	krb5_enctype *read_enctypes;
++	krb5_enctype *new_enctypes;
+ 	char *new_value = NULL;
+ 	int is_2008_or_later;
+ 	LDAP *ldap;
+@@ -685,7 +686,14 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
+ 		value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
+ 	}
+ 
+-	new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll));
++	new_enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
++	if (new_enctypes == NULL) {
++		_adcli_warn ("No permitted encryption type found.");
++		return ADCLI_ERR_UNEXPECTED;
++	}
++
++	new_value = _adcli_krb5_format_enctypes (new_enctypes);
++	krb5_free_enctypes (adcli_conn_get_krb5_context (enroll->conn), new_enctypes);
+ 	if (new_value == NULL) {
+ 		free (value);
+ 		_adcli_warn ("The encryption types desired are not available in active directory");
+@@ -1758,7 +1766,11 @@ add_principal_to_keytab (adcli_enroll *enroll,
+ 		             enroll->keytab_name);
+ 	}
+ 
+-	enctypes = adcli_enroll_get_keytab_enctypes (enroll);
++	enctypes = adcli_enroll_get_permitted_keytab_enctypes (enroll);
++	if (enctypes == NULL) {
++		_adcli_warn ("No permitted encryption type found.");
++		return ADCLI_ERR_UNEXPECTED;
++	}
+ 
+ 	if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
+ 		code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
+@@ -1774,7 +1786,10 @@ add_principal_to_keytab (adcli_enroll *enroll,
+ 		 */
+ 
+ 		salts = build_principal_salts (enroll, k5, principal);
+-		return_unexpected_if_fail (salts != NULL);
++		if (salts == NULL) {
++			krb5_free_enctypes (k5, enctypes);
++			return ADCLI_ERR_UNEXPECTED;
++		}
+ 
+ 		if (*which_salt < 0) {
+ 			code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
+@@ -1794,6 +1809,7 @@ add_principal_to_keytab (adcli_enroll *enroll,
+ 
+ 		free_principal_salts (k5, salts);
+ 	}
++	krb5_free_enctypes (k5, enctypes);
+ 
+ 	if (code != 0) {
+ 		_adcli_err ("Couldn't add keytab entries: %s: %s",
+-- 
+2.21.0
+
diff --git a/SPECS/adcli.spec b/SPECS/adcli.spec
index 4fc9299..0ebe6b9 100644
--- a/SPECS/adcli.spec
+++ b/SPECS/adcli.spec
@@ -1,6 +1,6 @@
 Name:           adcli
 Version:        0.8.1
-Release:        9%{?dist}
+Release:        13%{?dist}
 Summary:        Active Directory enrollment
 License:        LGPLv2+
 URL:            http://cgit.freedesktop.org/realmd/adcli
@@ -90,6 +90,29 @@ Patch53:        0005-tools-remove-errx-from-setup_krb5_conf_directory.patch
 Patch54:        0006-tools-entry-remove-errx-from-parse_option.patch
 Patch55:        0007-tools-computer-remove-errx-from-parse_option.patch
 
+# rhbz#1665162 - adcli is failing with "Couldn't add keytab entries: FILE:/etc/krb5.keytab: Cannot allocate memory" (edit)
+Patch56:        0001-Fix-for-issues-found-by-Coverity.patch
+Patch57:        0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch
+Patch58:        0002-adconn-add-adcli_conn_set_krb5_context.patch
+Patch59:        0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch
+Patch60:        0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch
+
+# Coverity fix related to fixes for rhbz#1665162
+Patch61:        0001-Fix-for-issue-found-by-Coverity.patch
+
+# rhbz#1683745 - Issue is that with arcfour-hmac as first encryption type
+Patch62:        0001-Do-not-use-arcfour-hmac-md5-when-discovering-the-sal.patch
+
+# rhbz#1738573 - adcli update --add-samba-data does not work as expected
+Patch63:        0001-doc-explain-how-to-force-password-reset.patch
+
+# rhbz#1685138 - adcli info should send netlogin pings to all domain controllers, not only a subset
+Patch64:        0001-Make-adcli-info-DC-location-mechanism-more-compliant.patch
+
+# rhbz#1786776 - adcli should be able to Force LDAPS over 636 with AD Access Provider w.r.t sssd (RHEL7)
+Patch65:         0001-Use-GSS-SPNEGO-if-available.patch
+Patch66:         0002-add-option-use-ldaps.patch
+
 BuildRequires:  intltool pkgconfig
 BuildRequires:  libtool
 BuildRequires:  gettext-devel
@@ -138,6 +161,21 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
 %doc %{_mandir}/*/*
 
 %changelog
+* Tue Jan 14 2020 Sumit Bose <sbose@redhat.com> - 0.8.1-13
+- adcli should be able to Force LDAPS over 636 with AD Access Provider w.r.t sssd [#1786776]
+
+* Wed Sep 04 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-12
+- adcli info should send netlogin pings to all domain controllers, not only a subset [#1685138]
+
+* Tue Aug 27 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-11
+- Fixes and improvements for RHEL-7.8
+- Issue is that with arcfour-hmac as first encryption type in the config ... [#1683745]
+- adcli update --add-samba-data does not work as expected [#1738573]
+
+* Mon Aug 12 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-10
+- adcli is failing with "Couldn't add keytab entries: FILE:/etc/krb5.keytab:
+  Cannot allocate memory" [1665162]
+
 * Thu May 02 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-9
 - Fixes for RHEL-7.7 updates
 - additional patch for [RFE] adcli join should preserve SPN added by adcli