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-Implement-adcli-testjoin.patch b/SOURCES/0001-Implement-adcli-testjoin.patch
new file mode 100644
index 0000000..d75cbf2
--- /dev/null
+++ b/SOURCES/0001-Implement-adcli-testjoin.patch
@@ -0,0 +1,181 @@
+From 6fd99ff6c5dd6ef0be8d942989b1c6dcee3102d9 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Mar 2019 12:37:39 +0100
+Subject: [PATCH] Implement 'adcli testjoin'
+
+By calling adcli testjoin it will be checked if the host credentials
+stored in the keytab are still valid.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1622583
+---
+ doc/adcli.xml    | 34 +++++++++++++++++++++++
+ tools/computer.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
+ tools/tools.c    |  1 +
+ tools/tools.h    |  4 +++
+ 4 files changed, 111 insertions(+)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index af73433..9605b4a 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -43,6 +43,9 @@
+ 	<cmdsynopsis>
+ 		<command>adcli update</command>
+ 	</cmdsynopsis>
++	<cmdsynopsis>
++		<command>adcli testjoin</command>
++	</cmdsynopsis>
+ 	<cmdsynopsis>
+ 		<command>adcli create-user</command>
+ 		<arg choice="opt">--domain=domain.example.com</arg>
+@@ -474,6 +477,37 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 
+ </refsect1>
+ 
++<refsect1 id='testjoin'>
++	<title>Testing if the machine account password is valid</title>
++
++	<para><command>adcli testjoin</command> uses the current credentials in
++	the keytab and tries to authenticate with the machine account to the AD
++	domain. If this works the machine account password and the join are
++	still valid. If it fails the machine account password or the whole
++	machine account have to be refreshed with
++	<command>adcli join</command> or <command>adcli update</command>.
++	</para>
++
++<programlisting>
++$ adcli testjoin
++</programlisting>
++
++	<para>Only the global options not related to authentication are
++	available, additionally you can specify the following options to
++	control how this operation is done.</para>
++
++	<variablelist>
++		<varlistentry>
++			<term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
++			<listitem><para>Specify the path to the host keytab where
++			current host credentials are stored and the new ones
++			will be written to.  If not specified, the default
++			location will be used, usually
++			<filename>/etc/krb5.keytab</filename>.</para></listitem>
++		</varlistentry>
++	</variablelist>
++</refsect1>
++
+ <refsect1 id='create_user'>
+ 	<title>Creating a User</title>
+ 
+diff --git a/tools/computer.c b/tools/computer.c
+index 112340e..610ed2b 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -566,6 +566,78 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 	return 0;
+ }
+ 
++int
++adcli_tool_computer_testjoin (adcli_conn *conn,
++                              int argc,
++                              char *argv[])
++{
++	adcli_enroll *enroll;
++	adcli_result res;
++	const char *ktname;
++	int opt;
++
++	struct option options[] = {
++		{ "domain", required_argument, NULL, opt_domain },
++		{ "domain-controller", required_argument, NULL, opt_domain_controller },
++		{ "host-keytab", required_argument, 0, opt_host_keytab },
++		{ "verbose", no_argument, NULL, opt_verbose },
++		{ "help", no_argument, NULL, 'h' },
++		{ 0 },
++	};
++
++	static adcli_tool_desc usages[] = {
++		{ 0, "usage: adcli testjoin" },
++		{ 0 },
++	};
++
++	enroll = adcli_enroll_new (conn);
++	if (enroll == NULL)
++		errx (-1, "unexpected memory problems");
++
++	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
++		switch (opt) {
++		case 'h':
++		case '?':
++		case ':':
++			adcli_tool_usage (options, usages);
++			adcli_tool_usage (options, common_usages);
++			adcli_enroll_unref (enroll);
++			return opt == 'h' ? 0 : 2;
++		default:
++			parse_option ((Option)opt, optarg, conn, enroll);
++			break;
++		}
++	}
++
++	/* Force use of a keytab to test the join/machine account password */
++	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT);
++	ktname = adcli_enroll_get_keytab_name (enroll);
++	adcli_conn_set_login_keytab_name (conn, ktname ? ktname : "");
++
++	res = adcli_enroll_load (enroll);
++	if (res != ADCLI_SUCCESS) {
++		adcli_enroll_unref (enroll);
++		adcli_conn_unref (conn);
++		errx (-res, "couldn't lookup domain info from keytab: %s",
++		      adcli_get_last_error ());
++	}
++
++	res = adcli_conn_connect (conn);
++	if (res != ADCLI_SUCCESS) {
++		adcli_enroll_unref (enroll);
++		adcli_conn_unref (conn);
++		errx (-res, "couldn't connect to %s domain: %s",
++		      adcli_conn_get_domain_name (conn),
++		      adcli_get_last_error ());
++	}
++
++	printf ("Sucessfully validated join to domain %s\n",
++	        adcli_conn_get_domain_name (conn));
++
++	adcli_enroll_unref (enroll);
++
++	return 0;
++}
+ 
+ int
+ adcli_tool_computer_preset (adcli_conn *conn,
+diff --git a/tools/tools.c b/tools/tools.c
+index 915130e..c4e2851 100644
+--- a/tools/tools.c
++++ b/tools/tools.c
+@@ -55,6 +55,7 @@ struct {
+ 	{ "info", adcli_tool_info, "Print information about a domain", CONNECTION_LESS },
+ 	{ "join", adcli_tool_computer_join, "Join this machine to a domain", },
+ 	{ "update", adcli_tool_computer_update, "Update machine membership in a domain", },
++	{ "testjoin", adcli_tool_computer_testjoin, "Test if machine account password is valid", },
+ 	{ "preset-computer", adcli_tool_computer_preset, "Pre setup computers accounts", },
+ 	{ "reset-computer", adcli_tool_computer_reset, "Reset a computer account", },
+ 	{ "delete-computer", adcli_tool_computer_delete, "Delete a computer account", },
+diff --git a/tools/tools.h b/tools/tools.h
+index 6c97ccf..8cebbf9 100644
+--- a/tools/tools.h
++++ b/tools/tools.h
+@@ -70,6 +70,10 @@ int       adcli_tool_computer_update   (adcli_conn *conn,
+                                         int argc,
+                                         char *argv[]);
+ 
++int       adcli_tool_computer_testjoin (adcli_conn *conn,
++                                        int argc,
++                                        char *argv[]);
++
+ int       adcli_tool_computer_delete   (adcli_conn *conn,
+                                         int argc,
+                                         char *argv[]);
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-Increment-kvno-after-password-change-with-user-creds.patch b/SOURCES/0001-Increment-kvno-after-password-change-with-user-creds.patch
new file mode 100644
index 0000000..aeef509
--- /dev/null
+++ b/SOURCES/0001-Increment-kvno-after-password-change-with-user-creds.patch
@@ -0,0 +1,32 @@
+From 5cf1723c308e21cdbe9b98ed2aaa42cb997456fb Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 15 Mar 2019 14:31:12 +0100
+Subject: [PATCH] Increment kvno after password change with user creds
+
+Originally only the host credential part was fixed in the context of
+https://bugs.freedesktop.org/show_bug.cgi?id=91185. This patch adds the
+fix to the case when user credentials are used.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1642546
+---
+ library/adenroll.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index e02f403..58362c2 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -1057,6 +1057,10 @@ set_password_with_user_creds (adcli_enroll *enroll)
+ #endif
+ 	} else {
+ 		_adcli_info ("Set computer password");
++		if (enroll->kvno > 0) {
++			enroll->kvno++;
++			_adcli_info ("kvno incremented to %d", enroll->kvno);
++		}
+ 		res = ADCLI_SUCCESS;
+ 	}
+ 
+-- 
+2.20.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-adutil-add-_adcli_strv_add_unique.patch b/SOURCES/0001-adutil-add-_adcli_strv_add_unique.patch
new file mode 100644
index 0000000..f49f5f8
--- /dev/null
+++ b/SOURCES/0001-adutil-add-_adcli_strv_add_unique.patch
@@ -0,0 +1,134 @@
+From 85d127fd52a8469f9f3ce0d1130fe17e756fdd75 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 16 Nov 2018 13:32:33 +0100
+Subject: [PATCH 1/2] adutil: add _adcli_strv_add_unique
+
+_adcli_strv_add_unique checks is the new value already exists in the
+strv before adding it. Check can be done case-sensitive or not.
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/16
+---
+ library/adprivate.h |  5 ++++
+ library/adutil.c    | 65 ++++++++++++++++++++++++++++++++++++++-------
+ 2 files changed, 61 insertions(+), 9 deletions(-)
+
+diff --git a/library/adprivate.h b/library/adprivate.h
+index bc9df6d..0806430 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -111,6 +111,11 @@ char **        _adcli_strv_add               (char **strv,
+                                               char *string,
+                                               int *length) GNUC_WARN_UNUSED;
+ 
++char **        _adcli_strv_add_unique        (char **strv,
++                                              char *string,
++                                              int *length,
++                                              bool case_sensitive) GNUC_WARN_UNUSED;
++
+ void           _adcli_strv_remove_unsorted   (char **strv,
+                                               const char *string,
+                                               int *length);
+diff --git a/library/adutil.c b/library/adutil.c
+index 17d2caa..76ea158 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -221,6 +221,34 @@ _adcli_strv_add (char **strv,
+ 	return seq_push (strv, length, string);
+ }
+ 
++static int
++_adcli_strv_has_ex (char **strv,
++                    const char *str,
++                    int (* compare) (const char *match, const char*value))
++{
++	int i;
++
++	for (i = 0; strv && strv[i] != NULL; i++) {
++		if (compare (strv[i], str) == 0)
++			return 1;
++	}
++
++	return 0;
++}
++
++char **
++_adcli_strv_add_unique (char **strv,
++                        char *string,
++                        int *length,
++                        bool case_sensitive)
++{
++	if (_adcli_strv_has_ex (strv, string, case_sensitive ? strcmp : strcasecmp) == 1) {
++		return strv;
++	}
++
++	return _adcli_strv_add (strv, string, length);
++}
++
+ #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+ 
+ void
+@@ -241,19 +269,11 @@ _adcli_strv_remove_unsorted (char **strv,
+ 	                            (seq_compar)strcasecmp, free);
+ }
+ 
+-
+ int
+ _adcli_strv_has (char **strv,
+                  const char *str)
+ {
+-	int i;
+-
+-	for (i = 0; strv && strv[i] != NULL; i++) {
+-		if (strcmp (strv[i], str) == 0)
+-			return 1;
+-	}
+-
+-	return 0;
++	return _adcli_strv_has_ex (strv, str, strcmp);
+ }
+ 
+ void
+@@ -704,6 +724,32 @@ test_strv_add_free (void)
+ 	_adcli_strv_free (strv);
+ }
+ 
++static void
++test_strv_add_unique_free (void)
++{
++	char **strv = NULL;
++
++	strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("tWo"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false);
++	strv = _adcli_strv_add_unique (strv, strdup ("TWO"), NULL, true);
++
++	assert_num_eq (_adcli_strv_len (strv), 4);
++
++	assert_str_eq (strv[0], "one");
++	assert_str_eq (strv[1], "two");
++	assert_str_eq (strv[2], "three");
++	assert_str_eq (strv[3], "TWO");
++	assert (strv[4] == NULL);
++
++	_adcli_strv_free (strv);
++}
++
++
+ static void
+ test_strv_dup (void)
+ {
+@@ -856,6 +902,7 @@ main (int argc,
+       char *argv[])
+ {
+ 	test_func (test_strv_add_free, "/util/strv_add_free");
++	test_func (test_strv_add_unique_free, "/util/strv_add_unique_free");
+ 	test_func (test_strv_dup, "/util/strv_dup");
+ 	test_func (test_strv_count, "/util/strv_count");
+ 	test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-create-user-add-nis-domain-option.patch b/SOURCES/0001-create-user-add-nis-domain-option.patch
new file mode 100644
index 0000000..32b0ca9
--- /dev/null
+++ b/SOURCES/0001-create-user-add-nis-domain-option.patch
@@ -0,0 +1,71 @@
+From 1457b4a7623a8ae58fb8d6a652d1cc44904b8863 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 18 Mar 2019 11:02:57 +0100
+Subject: [PATCH 1/2] create-user: add nis-domain option
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/2
+---
+ doc/adcli.xml | 8 ++++++++
+ tools/entry.c | 6 ++++++
+ 2 files changed, 14 insertions(+)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 4722c3a..18620c0 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -531,6 +531,14 @@ $ adcli create-user Fry --domain=domain.example.com \
+ 			the new created user account, which should be the user's
+ 			numeric primary user id.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--nis-domain=<parameter>nis_domain</parameter></option></term>
++			<listitem><para>Set the <code>msSFU30NisDomain</code> attribute of
++			the new created user account, which should be the user's
++			NIS domain is the NIS/YP service of Active Directory's Services for Unix (SFU)
++			are used. This is needed to let the 'UNIX attributes' tab of older Active
++			Directoy versions show the set UNIX specific attributes.</para></listitem>
++		</varlistentry>
+ 	</variablelist>
+ 
+ </refsect1>
+diff --git a/tools/entry.c b/tools/entry.c
+index 7b6a200..69ce62c 100644
+--- a/tools/entry.c
++++ b/tools/entry.c
+@@ -52,6 +52,7 @@ typedef enum {
+ 	opt_unix_uid,
+ 	opt_unix_gid,
+ 	opt_unix_shell,
++	opt_nis_domain,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+@@ -62,6 +63,7 @@ static adcli_tool_desc common_usages[] = {
+ 	{ opt_unix_uid, "unix uid number" },
+ 	{ opt_unix_gid, "unix gid number" },
+ 	{ opt_unix_shell, "unix shell" },
++	{ opt_nis_domain, "NIS domain" },
+ 	{ opt_domain, "active directory domain name" },
+ 	{ opt_domain_realm, "kerberos realm for the domain" },
+ 	{ opt_domain_controller, "domain directory server to connect to" },
+@@ -159,6 +161,7 @@ adcli_tool_user_create (adcli_conn *conn,
+ 		{ "unix-uid", required_argument, NULL, opt_unix_uid },
+ 		{ "unix-gid", required_argument, NULL, opt_unix_gid },
+ 		{ "unix-shell", required_argument, NULL, opt_unix_shell },
++		{ "nis-domain", required_argument, NULL, opt_nis_domain },
+ 		{ "domain-ou", required_argument, NULL, opt_domain_ou },
+ 		{ "domain", required_argument, NULL, opt_domain },
+ 		{ "domain-realm", required_argument, NULL, opt_domain_realm },
+@@ -200,6 +203,9 @@ adcli_tool_user_create (adcli_conn *conn,
+ 		case opt_unix_shell:
+ 			adcli_attrs_add (attrs, "loginShell", optarg, NULL);
+ 			break;
++		case opt_nis_domain:
++			adcli_attrs_add (attrs, "msSFU30NisDomain", optarg, NULL);
++			break;
+ 		case opt_domain_ou:
+ 			ou = optarg;
+ 			break;
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch b/SOURCES/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch
new file mode 100644
index 0000000..dfdf745
--- /dev/null
+++ b/SOURCES/0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch
@@ -0,0 +1,72 @@
+From 3a84c2469c31967bc22c0490456f07723ef5fc86 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 20 Mar 2019 11:01:50 +0100
+Subject: [PATCH 1/4] ensure_keytab_principals: do not leak memory when called
+ twice
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
+---
+ library/adenroll.c | 32 +++++++++++++++++++++-----------
+ 1 file changed, 21 insertions(+), 11 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index d1f746c..48cb4cf 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -413,6 +413,25 @@ ensure_service_principals (adcli_result res,
+ 	return res;
+ }
+ 
++static void enroll_clear_keytab_principals (adcli_enroll *enroll)
++{
++	krb5_context k5;
++	size_t c;
++
++	if (enroll->keytab_principals) {
++		k5 = adcli_conn_get_krb5_context (enroll->conn);
++		return_if_fail (k5 != NULL);
++
++		for (c = 0; enroll->keytab_principals[c] != NULL; c++)
++			krb5_free_principal (k5, enroll->keytab_principals[c]);
++
++		free (enroll->keytab_principals);
++		enroll->keytab_principals = NULL;
++	}
++
++	return;
++}
++
+ static adcli_result
+ ensure_keytab_principals (adcli_result res,
+                           adcli_enroll *enroll)
+@@ -430,6 +449,7 @@ ensure_keytab_principals (adcli_result res,
+ 	k5 = adcli_conn_get_krb5_context (enroll->conn);
+ 	return_unexpected_if_fail (k5 != NULL);
+ 
++	enroll_clear_keytab_principals (enroll);
+ 	enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
+ 	return_unexpected_if_fail (enroll->keytab_principals != NULL);
+ 	at = 0;
+@@ -1860,18 +1880,8 @@ static void
+ enroll_clear_state (adcli_enroll *enroll)
+ {
+ 	krb5_context k5;
+-	int i;
+-
+-	if (enroll->keytab_principals) {
+-		k5 = adcli_conn_get_krb5_context (enroll->conn);
+-		return_if_fail (k5 != NULL);
+-
+-		for (i = 0; enroll->keytab_principals[i] != NULL; i++)
+-			krb5_free_principal (k5, enroll->keytab_principals[i]);
+ 
+-		free (enroll->keytab_principals);
+-		enroll->keytab_principals = NULL;
+-	}
++	enroll_clear_keytab_principals (enroll);
+ 
+ 	if (enroll->keytab) {
+ 		k5 = adcli_conn_get_krb5_context (enroll->conn);
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-join-always-add-service-principals.patch b/SOURCES/0001-join-always-add-service-principals.patch
new file mode 100644
index 0000000..0281dc6
--- /dev/null
+++ b/SOURCES/0001-join-always-add-service-principals.patch
@@ -0,0 +1,86 @@
+From cd296bf24e7cc56fb8d00bad7e9a56c539894309 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 19 Mar 2019 20:44:36 +0100
+Subject: [PATCH 1/2] join: always add service principals
+
+If currently --service-name is given during the join only the service
+names given by this option are added as service principal names. As a
+result the default 'host' service principal name might be missing which
+might cause issues e.g. with SSSD and sshd.
+
+The patch makes sure the default service principals 'host' and
+'RestrictedKrbHost' are always added during join.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1644311
+---
+ library/adenroll.c | 36 ++++++++++++++++++++++++++++++------
+ 1 file changed, 30 insertions(+), 6 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 58362c2..d1f746c 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -288,16 +288,23 @@ ensure_computer_password (adcli_result res,
+ }
+ 
+ static adcli_result
+-ensure_service_names (adcli_result res,
+-                      adcli_enroll *enroll)
++ensure_default_service_names (adcli_enroll *enroll)
+ {
+ 	int length = 0;
+ 
+-	if (res != ADCLI_SUCCESS)
+-		return res;
++	if (enroll->service_names != NULL) {
++		length = seq_count (enroll->service_names);
+ 
+-	if (enroll->service_names || enroll->service_principals)
+-		return ADCLI_SUCCESS;
++		/* Make sure there is no entry with an unexpected case. AD
++		 * would not care but since the client side is case-sensitive
++		 * we should make sure we use the expected spelling. */
++		seq_remove_unsorted (enroll->service_names,
++		                     &length, "host",
++		                     (seq_compar)strcasecmp, free);
++		seq_remove_unsorted (enroll->service_names,
++		                     &length, "RestrictedKrbHost",
++		                     (seq_compar)strcasecmp, free);
++	}
+ 
+ 	/* The default ones specified by MS */
+ 	enroll->service_names = _adcli_strv_add (enroll->service_names,
+@@ -307,6 +314,19 @@ ensure_service_names (adcli_result res,
+ 	return ADCLI_SUCCESS;
+ }
+ 
++static adcli_result
++ensure_service_names (adcli_result res,
++                      adcli_enroll *enroll)
++{
++	if (res != ADCLI_SUCCESS)
++		return res;
++
++	if (enroll->service_names || enroll->service_principals)
++		return ADCLI_SUCCESS;
++
++	return ensure_default_service_names (enroll);
++}
++
+ static adcli_result
+ add_service_names_to_service_principals (adcli_enroll *enroll)
+ {
+@@ -2039,6 +2059,10 @@ adcli_enroll_join (adcli_enroll *enroll,
+ 	if (res != ADCLI_SUCCESS)
+ 		return res;
+ 
++	res = ensure_default_service_names (enroll);
++	if (res != ADCLI_SUCCESS)
++		return res;
++
+ 	res = adcli_enroll_prepare (enroll, flags);
+ 	if (res != ADCLI_SUCCESS)
+ 		return res;
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-library-add-missing-strdup.patch b/SOURCES/0001-library-add-missing-strdup.patch
new file mode 100644
index 0000000..378bb3c
--- /dev/null
+++ b/SOURCES/0001-library-add-missing-strdup.patch
@@ -0,0 +1,34 @@
+From a64cce9830c2e9c26e120f671b247ee71b45c888 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 12 Apr 2019 17:31:41 +0200
+Subject: [PATCH] library: add missing strdup
+
+In add_server_side_service_principals _adcli_strv_add_unique is called
+which only adds a string to a list without copying to. Since the
+original list will be freed later the value must be copied.
+
+This issue was introduce with 972f1a2f35829ed89f5353bd204683aa9ad6a2d2
+and hence
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
+---
+ library/adenroll.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 1cce86a..52aa8a8 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -1987,7 +1987,8 @@ add_server_side_service_principals (adcli_enroll *enroll)
+ 		_adcli_info ("Checking %s", spn_list[c]);
+ 		if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) {
+ 			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
+-		                                                             spn_list[c], &length, false);
++			                                                     strdup (spn_list[c]),
++			                                                     &length, false);
+ 			assert (enroll->service_principals != NULL);
+ 			_adcli_info ("   Added %s", spn_list[c]);
+ 		}
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch b/SOURCES/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch
new file mode 100644
index 0000000..c682c5a
--- /dev/null
+++ b/SOURCES/0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch
@@ -0,0 +1,92 @@
+From 85b835f8258a57e3b23de47a255dddd822d5bfb3 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 15 Mar 2019 17:33:44 +0100
+Subject: [PATCH] library: use getaddrinfo with AI_CANONNAME to find a FQDN
+
+Currently adcli creates service principals only with a short name if the
+hostname of the client is a short name. This would fail is
+Kerberos/GSSAPI clients will use the fully-qualified domain name (FQDN)
+to access the host.
+
+With this patch adcli tries to expand the short name by calling
+getaddrinfo with the AI_CANONNAME hint.
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/1
+---
+ doc/adcli.xml    |  6 +++++-
+ library/adconn.c | 30 +++++++++++++++++++++++++++++-
+ 2 files changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 97dec08..4722c3a 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -228,7 +228,11 @@ Password for Administrator:
+ 			<term><option>-H, --host-fqdn=<parameter>host</parameter></option></term>
+ 			<listitem><para>Override the local machine's fully qualified
+ 			domain name. If not specified, the local machine's hostname
+-			will be retrieved via <function>gethostname()</function>.</para></listitem>
++			will be retrieved via <function>gethostname()</function>.
++			If <function>gethostname()</function> only returns a short name
++			<function>getaddrinfo()</function> with the AI_CANONNAME hint
++			is called to expand the name to a fully qualified domain
++			name.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
+diff --git a/library/adconn.c b/library/adconn.c
+index e2250e3..f6c23d3 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -86,11 +86,36 @@ struct _adcli_conn_ctx {
+ 	krb5_keytab keytab;
+ };
+ 
++static char *try_to_get_fqdn (const char *host_name)
++{
++	int ret;
++	char *fqdn = NULL;
++	struct addrinfo *res;
++	struct addrinfo hints;
++
++	memset (&hints, 0, sizeof (struct addrinfo));
++	hints.ai_socktype = SOCK_DGRAM;
++	hints.ai_flags = AI_CANONNAME;
++
++	ret = getaddrinfo (host_name, NULL, &hints, &res);
++	if (ret != 0) {
++		_adcli_err ("Failed to find FQDN: %s", gai_strerror (ret));
++		return NULL;
++	}
++
++	fqdn = strdup (res->ai_canonname);
++
++	freeaddrinfo (res);
++
++	return fqdn;
++}
++
+ static adcli_result
+ ensure_host_fqdn (adcli_result res,
+                   adcli_conn *conn)
+ {
+ 	char hostname[HOST_NAME_MAX + 1];
++	char *fqdn = NULL;
+ 	int ret;
+ 
+ 	if (res != ADCLI_SUCCESS)
+@@ -107,7 +132,10 @@ ensure_host_fqdn (adcli_result res,
+ 		return ADCLI_ERR_UNEXPECTED;
+ 	}
+ 
+-	conn->host_fqdn = strdup (hostname);
++	if (strchr (hostname, '.') == NULL) {
++		fqdn = try_to_get_fqdn (hostname);
++	}
++	conn->host_fqdn = fqdn != NULL ? fqdn : strdup (hostname);
+ 	return_unexpected_if_fail (conn->host_fqdn != NULL);
+ 	return ADCLI_SUCCESS;
+ }
+-- 
+2.20.1
+
diff --git a/SOURCES/0001-tools-remove-errx-from-computer-commands.patch b/SOURCES/0001-tools-remove-errx-from-computer-commands.patch
new file mode 100644
index 0000000..71db611
--- /dev/null
+++ b/SOURCES/0001-tools-remove-errx-from-computer-commands.patch
@@ -0,0 +1,328 @@
+From fa7926c7a9d92bc7c42c610ba6f1706c635aa901 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 15 Apr 2019 17:54:27 +0200
+Subject: [PATCH 1/7] tools: remove errx from computer commands
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/computer.c | 166 ++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 107 insertions(+), 59 deletions(-)
+
+diff --git a/tools/computer.c b/tools/computer.c
+index bee695c..9cbbb28 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -379,8 +379,10 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 	};
+ 
+ 	enroll = adcli_enroll_new (conn);
+-	if (enroll == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (enroll == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+ 		switch (opt) {
+@@ -415,21 +417,28 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 
+ 	if (argc == 1)
+ 		adcli_conn_set_domain_name (conn, argv[0]);
+-	else if (argc > 1)
+-		errx (2, "extra arguments specified");
++	else if (argc > 1) {
++		warnx ("extra arguments specified");
++		adcli_enroll_unref (enroll);
++		return 2;
++	}
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	res = adcli_enroll_join (enroll, flags);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "joining domain %s failed: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("joining domain %s failed: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	if (details)
+@@ -486,8 +495,10 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 	};
+ 
+ 	enroll = adcli_enroll_new (conn);
+-	if (enroll == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (enroll == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+ 		switch (opt) {
+@@ -525,22 +536,28 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 
+ 	res = adcli_enroll_load (enroll);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't lookup domain info from keytab: %s",
+-		      adcli_get_last_error ());
++		warnx ("couldn't lookup domain info from keytab: %s",
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	res = adcli_enroll_update (enroll, flags);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "updating membership with domain %s failed: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("updating membership with domain %s failed: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	if (details)
+@@ -578,8 +595,10 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
+ 	};
+ 
+ 	enroll = adcli_enroll_new (conn);
+-	if (enroll == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (enroll == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+ 		switch (opt) {
+@@ -604,18 +623,18 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
+ 	res = adcli_enroll_load (enroll);
+ 	if (res != ADCLI_SUCCESS) {
+ 		adcli_enroll_unref (enroll);
+-		adcli_conn_unref (conn);
+-		errx (-res, "couldn't lookup domain info from keytab: %s",
+-		      adcli_get_last_error ());
++		warnx ("couldn't lookup domain info from keytab: %s",
++		       adcli_get_last_error ());
++		return -res;
+ 	}
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+ 		adcli_enroll_unref (enroll);
+-		adcli_conn_unref (conn);
+-		errx (-res, "couldn't connect to %s domain: %s",
++		warnx ("couldn't connect to %s domain: %s",
+ 		      adcli_conn_get_domain_name (conn),
+ 		      adcli_get_last_error ());
++		return -res;
+ 	}
+ 
+ 	printf ("Sucessfully validated join to domain %s\n",
+@@ -665,8 +684,10 @@ adcli_tool_computer_preset (adcli_conn *conn,
+ 	};
+ 
+ 	enroll = adcli_enroll_new (conn);
+-	if (enroll == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (enroll == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 	flags = ADCLI_ENROLL_NO_KEYTAB;
+ 
+ 	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+@@ -694,17 +715,22 @@ adcli_tool_computer_preset (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc < 1)
+-		errx (EUSAGE, "specify one or more host names of computer accounts to preset");
++	if (argc < 1) {
++		warnx ("specify one or more host names of computer accounts to preset");
++		adcli_enroll_unref (enroll);
++		return EUSAGE;
++	}
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 	reset_password = (adcli_enroll_get_computer_password (enroll) == NULL);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	for (i = 0; i < argc; i++) {
+@@ -715,9 +741,11 @@ adcli_tool_computer_preset (adcli_conn *conn,
+ 
+ 		res = adcli_enroll_join (enroll, flags);
+ 		if (res != ADCLI_SUCCESS) {
+-			errx (-res, "presetting %s in %s domain failed: %s", argv[i],
+-			      adcli_conn_get_domain_name (conn),
+-			      adcli_get_last_error ());
++			warnx ("presetting %s in %s domain failed: %s", argv[i],
++			       adcli_conn_get_domain_name (conn),
++			       adcli_get_last_error ());
++			adcli_enroll_unref (enroll);
++			return -res;
+ 		}
+ 
+ 		printf ("computer-name: %s\n", adcli_enroll_get_computer_name (enroll));
+@@ -758,8 +786,10 @@ adcli_tool_computer_reset (adcli_conn *conn,
+ 	};
+ 
+ 	enroll = adcli_enroll_new (conn);
+-	if (enroll == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (enroll == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+ 		switch (opt) {
+@@ -779,14 +809,19 @@ adcli_tool_computer_reset (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc != 1)
+-		errx (EUSAGE, "specify one host name of computer account to reset");
++	if (argc != 1) {
++		warnx ("specify one host name of computer account to reset");
++		adcli_enroll_unref (enroll);
++		return EUSAGE;
++	}
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	parse_fqdn_or_name (enroll, argv[0]);
+@@ -794,9 +829,11 @@ adcli_tool_computer_reset (adcli_conn *conn,
+ 
+ 	res = adcli_enroll_password (enroll, 0);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "resetting %s in %s domain failed: %s", argv[0],
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("resetting %s in %s domain failed: %s", argv[0],
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	adcli_enroll_unref (enroll);
+@@ -832,8 +869,10 @@ adcli_tool_computer_delete (adcli_conn *conn,
+ 	};
+ 
+ 	enroll = adcli_enroll_new (conn);
+-	if (enroll == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (enroll == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	while ((opt = adcli_tool_getopt (argc, argv, options)) != -1) {
+ 		switch (opt) {
+@@ -853,22 +892,29 @@ adcli_tool_computer_delete (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc > 1)
+-		errx (EUSAGE, "specify one host name of computer account to delete");
++	if (argc > 1) {
++		warnx ("specify one host name of computer account to delete");
++		adcli_enroll_unref (enroll);
++		return EUSAGE;
++	}
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_enroll_load (enroll);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't lookup domain info from keytab: %s",
+-		      adcli_get_last_error ());
++		warnx ("couldn't lookup domain info from keytab: %s",
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	if (argc == 1)
+@@ -876,9 +922,11 @@ adcli_tool_computer_delete (adcli_conn *conn,
+ 
+ 	res = adcli_enroll_delete (enroll, 0);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "deleting %s in %s domain failed: %s", argv[0],
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("deleting %s in %s domain failed: %s", argv[0],
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_enroll_unref (enroll);
++		return -res;
+ 	}
+ 
+ 	adcli_enroll_unref (enroll);
+-- 
+2.20.1
+
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-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch b/SOURCES/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch
new file mode 100644
index 0000000..e4a6bc5
--- /dev/null
+++ b/SOURCES/0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch
@@ -0,0 +1,83 @@
+From 0c027538f398b3823bedbfbf5f388ad97784a0ec Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 16 Nov 2018 13:32:59 +0100
+Subject: [PATCH 2/2] adenroll: use _adcli_strv_add_unique for service
+ principals
+
+Check if service principals is already in the list before adding it.
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/16
+---
+ library/adenroll.c | 31 ++++++++-----------------------
+ 1 file changed, 8 insertions(+), 23 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index de2242a..e02f403 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -313,7 +313,6 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
+ 	char *name;
+ 	int length = 0;
+ 	int i;
+-	size_t c;
+ 
+ 	if (enroll->service_principals != NULL) {
+ 		length = seq_count (enroll->service_principals);
+@@ -322,28 +321,14 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
+ 	for (i = 0; enroll->service_names[i] != NULL; i++) {
+ 		if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
+ 			return_unexpected_if_reached ();
+-		for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
+-			if (strcmp (name, enroll->service_principals[c]) == 0) {
+-				break;
+-			}
+-		}
+-		if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
+-			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-				                                      name, &length);
+-		}
++		enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
++		                                                     name, &length, false);
+ 
+ 		if (enroll->host_fqdn) {
+ 			if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
+ 				return_unexpected_if_reached ();
+-			for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
+-				if (strcmp (name, enroll->service_principals[c]) == 0) {
+-					break;
+-				}
+-			}
+-			if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
+-				enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-					                                      name, &length);
+-			}
++			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
++			                                                     name, &length, false);
+ 		}
+ 	}
+ 
+@@ -364,9 +349,9 @@ add_and_remove_service_principals (adcli_enroll *enroll)
+ 	list = adcli_enroll_get_service_principals_to_add (enroll);
+ 	if (list != NULL) {
+ 		for (c = 0; list[c] != NULL; c++) {
+-			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-			                                              strdup (list[c]),
+-			                                              &length);
++			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
++			                                                     strdup (list[c]),
++			                                                     &length, false);
+ 			if (enroll->service_principals == NULL) {
+ 				return ADCLI_ERR_UNEXPECTED;
+ 			}
+@@ -1525,7 +1510,7 @@ load_keytab_entry (krb5_context k5,
+ 			value = strdup (name);
+ 			return_val_if_fail (value != NULL, FALSE);
+ 			_adcli_info ("Found service principal in keytab: %s", value);
+-			enroll->service_principals = _adcli_strv_add (enroll->service_principals, value, NULL);
++			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals, value, NULL, false);
+ 		}
+ 	}
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-create-user-try-to-find-NIS-domain-if-needed.patch b/SOURCES/0002-create-user-try-to-find-NIS-domain-if-needed.patch
new file mode 100644
index 0000000..0ecdc90
--- /dev/null
+++ b/SOURCES/0002-create-user-try-to-find-NIS-domain-if-needed.patch
@@ -0,0 +1,147 @@
+From 408880a11879b1a57a450e25c77ef2e310bdffd5 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 18 Mar 2019 16:45:54 +0100
+Subject: [PATCH 2/2] create-user: try to find NIS domain if needed
+
+Related to https://gitlab.freedesktop.org/realmd/adcli/issues/2
+---
+ doc/adcli.xml     |  4 +++-
+ library/adentry.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
+ library/adentry.h |  2 ++
+ tools/entry.c     | 16 ++++++++++++++++
+ 4 files changed, 65 insertions(+), 1 deletion(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 18620c0..af73433 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -537,7 +537,9 @@ $ adcli create-user Fry --domain=domain.example.com \
+ 			the new created user account, which should be the user's
+ 			NIS domain is the NIS/YP service of Active Directory's Services for Unix (SFU)
+ 			are used. This is needed to let the 'UNIX attributes' tab of older Active
+-			Directoy versions show the set UNIX specific attributes.</para></listitem>
++			Directoy versions show the set UNIX specific attributes. If not specified
++			adcli will try to determine the NIS domain automatically if needed.
++			</para></listitem>
+ 		</varlistentry>
+ 	</variablelist>
+ 
+diff --git a/library/adentry.c b/library/adentry.c
+index 9b9e1c6..1cc0518 100644
+--- a/library/adentry.c
++++ b/library/adentry.c
+@@ -484,3 +484,47 @@ adcli_entry_new_group (adcli_conn *conn,
+ 	return_val_if_fail (sam_name != NULL, NULL);
+ 	return entry_new (conn, "group", group_entry_builder, sam_name);
+ }
++
++adcli_result
++adcli_get_nis_domain (adcli_entry *entry,
++                      adcli_attrs *attrs)
++{
++	LDAP *ldap;
++	const char *ldap_attrs[] = { "cn", NULL };
++	LDAPMessage *results;
++	LDAPMessage *ldap_entry;
++	char *base;
++	const char *filter = "objectClass=msSFU30DomainInfo";
++	char *cn;
++	int ret;
++
++	ldap = adcli_conn_get_ldap_connection (entry->conn);
++	return_unexpected_if_fail (ldap != NULL);
++
++	if (asprintf (&base, "CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,%s",
++	              adcli_conn_get_default_naming_context (entry->conn)) < 0) {
++		return_unexpected_if_reached ();
++	}
++
++	ret = ldap_search_ext_s (ldap, base, LDAP_SCOPE_SUB, filter, (char **)ldap_attrs,
++	                         0, NULL, NULL, NULL, -1, &results);
++
++	free (base);
++
++	if (ret != LDAP_SUCCESS) {
++		/* No NIS domain available */
++		ldap_msgfree (results);
++		return ADCLI_SUCCESS;
++	}
++
++	ldap_entry = ldap_first_entry (ldap, results);
++	if (ldap_entry != NULL) {
++		cn = _adcli_ldap_parse_value (ldap, ldap_entry, "cn");
++		return_unexpected_if_fail (cn != NULL);
++
++		adcli_attrs_add (attrs, "msSFU30NisDomain", cn, NULL);
++	}
++	ldap_msgfree (results);
++
++	return ADCLI_SUCCESS;
++}
+diff --git a/library/adentry.h b/library/adentry.h
+index eb8bc00..ae90689 100644
+--- a/library/adentry.h
++++ b/library/adentry.h
+@@ -58,4 +58,6 @@ const char *       adcli_entry_get_sam_name             (adcli_entry *entry);
+ 
+ const char *       adcli_entry_get_dn                   (adcli_entry *entry);
+ 
++adcli_result       adcli_get_nis_domain                 (adcli_entry *entry,
++                                                         adcli_attrs *attrs);
+ #endif /* ADENTRY_H_ */
+diff --git a/tools/entry.c b/tools/entry.c
+index 69ce62c..de56586 100644
+--- a/tools/entry.c
++++ b/tools/entry.c
+@@ -153,6 +153,8 @@ adcli_tool_user_create (adcli_conn *conn,
+ 	adcli_attrs *attrs;
+ 	const char *ou = NULL;
+ 	int opt;
++	bool has_unix_attr = false;
++	bool has_nis_domain = false;
+ 
+ 	struct option options[] = {
+ 		{ "display-name", required_argument, NULL, opt_display_name },
+@@ -193,18 +195,23 @@ adcli_tool_user_create (adcli_conn *conn,
+ 			break;
+ 		case opt_unix_home:
+ 			adcli_attrs_add (attrs, "unixHomeDirectory", optarg, NULL);
++			has_unix_attr = true;
+ 			break;
+ 		case opt_unix_uid:
+ 			adcli_attrs_add (attrs, "uidNumber", optarg, NULL);
++			has_unix_attr = true;
+ 			break;
+ 		case opt_unix_gid:
+ 			adcli_attrs_add (attrs, "gidNumber", optarg, NULL);
++			has_unix_attr = true;
+ 			break;
+ 		case opt_unix_shell:
+ 			adcli_attrs_add (attrs, "loginShell", optarg, NULL);
++			has_unix_attr = true;
+ 			break;
+ 		case opt_nis_domain:
+ 			adcli_attrs_add (attrs, "msSFU30NisDomain", optarg, NULL);
++			has_nis_domain = true;
+ 			break;
+ 		case opt_domain_ou:
+ 			ou = optarg;
+@@ -242,6 +249,15 @@ adcli_tool_user_create (adcli_conn *conn,
+ 		      adcli_get_last_error ());
+ 	}
+ 
++	if (has_unix_attr && !has_nis_domain) {
++		res = adcli_get_nis_domain (entry, attrs);
++		if (res != ADCLI_SUCCESS) {
++			adcli_entry_unref (entry);
++			adcli_attrs_free (attrs);
++			errx (-res, "couldn't get NIS domain");
++		}
++	}
++
+ 	res = adcli_entry_create (entry, attrs);
+ 	if (res != ADCLI_SUCCESS) {
+ 		errx (-res, "creating user %s in domain %s failed: %s",
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-library-make-_adcli_strv_has_ex-public.patch b/SOURCES/0002-library-make-_adcli_strv_has_ex-public.patch
new file mode 100644
index 0000000..db18951
--- /dev/null
+++ b/SOURCES/0002-library-make-_adcli_strv_has_ex-public.patch
@@ -0,0 +1,42 @@
+From e1b45e66bc185f5db4c252e1f3fb1b4400b4538e Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Mar 2019 10:36:38 +0100
+Subject: [PATCH 2/4] library: make _adcli_strv_has_ex public
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
+---
+ library/adprivate.h | 4 ++++
+ library/adutil.c    | 2 +-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/library/adprivate.h b/library/adprivate.h
+index 0806430..55e6234 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -125,6 +125,10 @@ void           _adcli_strv_free              (char **strv);
+ int            _adcli_strv_has               (char **strv,
+                                               const char *str);
+ 
++int            _adcli_strv_has_ex            (char **strv,
++                                              const char *str,
++                                              int (* compare) (const char *match, const char*value));
++
+ char **        _adcli_strv_dup               (char **strv) GNUC_WARN_UNUSED;
+ 
+ char *         _adcli_strv_join              (char **strv,
+diff --git a/library/adutil.c b/library/adutil.c
+index 76ea158..9b0c47f 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -221,7 +221,7 @@ _adcli_strv_add (char **strv,
+ 	return seq_push (strv, length, string);
+ }
+ 
+-static int
++int
+ _adcli_strv_has_ex (char **strv,
+                     const char *str,
+                     int (* compare) (const char *match, const char*value))
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-library-return-error-if-no-matching-key-was-found.patch b/SOURCES/0002-library-return-error-if-no-matching-key-was-found.patch
new file mode 100644
index 0000000..f9c68d6
--- /dev/null
+++ b/SOURCES/0002-library-return-error-if-no-matching-key-was-found.patch
@@ -0,0 +1,35 @@
+From 4987a21f4839ab7ea50e932c72df05075efb89b3 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 21 Mar 2019 15:05:33 +0100
+Subject: [PATCH 2/2] library: return error if no matching key was found
+
+To avoid a misleading debug message indicating success a proper erro
+code should be returned the no matching key was found when trying to
+copy an keytab entry for a new principal.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1644311
+---
+ library/adkrb5.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/library/adkrb5.c b/library/adkrb5.c
+index 033c181..7f77373 100644
+--- a/library/adkrb5.c
++++ b/library/adkrb5.c
+@@ -298,11 +298,10 @@ _adcli_krb5_keytab_copy_entries (krb5_context k5,
+ 
+ 		code = _adcli_krb5_get_keyblock (k5, keytab, &entry.key,
+ 		                                 match_enctype_and_kvno, &closure);
+-		if (code != 0) {
+-			return code;
++		if (code != 0 || closure.matched == 0) {
++			return code != 0 ? code : ENOKEY;
+ 		}
+ 
+-
+ 		entry.principal = principal;
+ 		entry.vno = kvno;
+ 
+-- 
+2.20.1
+
diff --git a/SOURCES/0002-tools-remove-errx-from-user-and-group-commands.patch b/SOURCES/0002-tools-remove-errx-from-user-and-group-commands.patch
new file mode 100644
index 0000000..36e5567
--- /dev/null
+++ b/SOURCES/0002-tools-remove-errx-from-user-and-group-commands.patch
@@ -0,0 +1,398 @@
+From cac0fa9df8888245399f2db187e05e31f93d1471 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 15 Apr 2019 17:56:37 +0200
+Subject: [PATCH 2/7] tools: remove errx from user and group commands
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/entry.c | 232 +++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 154 insertions(+), 78 deletions(-)
+
+diff --git a/tools/entry.c b/tools/entry.c
+index de56586..97ec6e7 100644
+--- a/tools/entry.c
++++ b/tools/entry.c
+@@ -232,21 +232,30 @@ adcli_tool_user_create (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc != 1)
+-		errx (2, "specify one user name to create");
++	if (argc != 1) {
++		warnx ("specify one user name to create");
++		adcli_attrs_free (attrs);
++		return 2;
++	}
+ 
+ 	entry = adcli_entry_new_user (conn, argv[0]);
+-	if (entry == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (entry == NULL) {
++		warnx ("unexpected memory problems");
++		adcli_attrs_free (attrs);
++		return -1;
++	}
+ 	adcli_entry_set_domain_ou (entry, ou);
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		adcli_attrs_free (attrs);
++		return -res;
+ 	}
+ 
+ 	if (has_unix_attr && !has_nis_domain) {
+@@ -254,16 +263,20 @@ adcli_tool_user_create (adcli_conn *conn,
+ 		if (res != ADCLI_SUCCESS) {
+ 			adcli_entry_unref (entry);
+ 			adcli_attrs_free (attrs);
+-			errx (-res, "couldn't get NIS domain");
++			warnx ("couldn't get NIS domain");
++			return -res;
+ 		}
+ 	}
+ 
+ 	res = adcli_entry_create (entry, attrs);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "creating user %s in domain %s failed: %s",
+-		      adcli_entry_get_sam_name (entry),
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("creating user %s in domain %s failed: %s",
++		       adcli_entry_get_sam_name (entry),
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		adcli_attrs_free (attrs);
++		return -res;
+ 	}
+ 
+ 	adcli_entry_unref (entry);
+@@ -317,28 +330,36 @@ adcli_tool_user_delete (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc != 1)
+-		errx (2, "specify one user name to delete");
++	if (argc != 1) {
++		warnx ("specify one user name to delete");
++		return 2;
++	}
+ 
+ 	entry = adcli_entry_new_user (conn, argv[0]);
+-	if (entry == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (entry == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	res = adcli_entry_delete (entry);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "deleting user %s in domain %s failed: %s",
+-		      adcli_entry_get_sam_name (entry),
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("deleting user %s in domain %s failed: %s",
++		       adcli_entry_get_sam_name (entry),
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	adcli_entry_unref (entry);
+@@ -404,29 +425,41 @@ adcli_tool_group_create (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc != 1)
+-		errx (2, "specify one group to create");
++	if (argc != 1) {
++		warnx ("specify one group to create");
++		adcli_attrs_free (attrs);
++		return 2;
++	}
+ 
+ 	entry = adcli_entry_new_group (conn, argv[0]);
+-	if (entry == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (entry == NULL) {
++		warnx ("unexpected memory problems");
++		adcli_attrs_free (attrs);
++		return -1;
++	}
+ 	adcli_entry_set_domain_ou (entry, ou);
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to domain %s: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to domain %s: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		adcli_attrs_free (attrs);
++		return -res;
+ 	}
+ 
+ 	res = adcli_entry_create (entry, attrs);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "creating group %s in domain %s failed: %s",
+-		      adcli_entry_get_sam_name (entry),
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("creating group %s in domain %s failed: %s",
++		       adcli_entry_get_sam_name (entry),
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		adcli_attrs_free (attrs);
++		return -res;
+ 	}
+ 
+ 	adcli_entry_unref (entry);
+@@ -480,28 +513,36 @@ adcli_tool_group_delete (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc != 1)
+-		errx (2, "specify one group name to delete");
++	if (argc != 1) {
++		warnx ("specify one group name to delete");
++		return 2;
++	}
+ 
+ 	entry = adcli_entry_new_group (conn, argv[0]);
+-	if (entry == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (entry == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	res = adcli_entry_delete (entry);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "deleting group %s in domain %s failed: %s",
+-		      adcli_entry_get_sam_name (entry),
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("deleting group %s in domain %s failed: %s",
++		       adcli_entry_get_sam_name (entry),
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	adcli_entry_unref (entry);
+@@ -509,7 +550,7 @@ adcli_tool_group_delete (adcli_conn *conn,
+ 	return 0;
+ }
+ 
+-static void
++static int
+ expand_user_dn_as_member (adcli_conn *conn,
+                           adcli_attrs *attrs,
+                           const char *user,
+@@ -523,16 +564,19 @@ expand_user_dn_as_member (adcli_conn *conn,
+ 
+ 	res = adcli_entry_load (entry);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't lookup user %s in domain %s: %s",
+-		      user, adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't lookup user %s in domain %s: %s",
++		       user, adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	dn = adcli_entry_get_dn (entry);
+ 	if (dn == NULL) {
+-		errx (-ADCLI_ERR_CONFIG,
+-		      "couldn't found user %s in domain %s",
+-		      user, adcli_conn_get_domain_name (conn));
++		warnx ("couldn't found user %s in domain %s",
++		       user, adcli_conn_get_domain_name (conn));
++		adcli_entry_unref (entry);
++		return -ADCLI_ERR_CONFIG;
+ 	}
+ 
+ 	if (adding)
+@@ -541,6 +585,8 @@ expand_user_dn_as_member (adcli_conn *conn,
+ 		adcli_attrs_delete1 (attrs, "member", dn);
+ 
+ 	adcli_entry_unref (entry);
++
++	return ADCLI_SUCCESS;
+ }
+ 
+ int
+@@ -590,33 +636,48 @@ adcli_tool_member_add (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc < 2)
+-		errx (2, "specify a group name and a user to add");
++	if (argc < 2) {
++		warnx ("specify a group name and a user to add");
++		return 2;
++	}
+ 
+ 	entry = adcli_entry_new_group (conn, argv[0]);
+-	if (entry == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (entry == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	attrs = adcli_attrs_new ();
+ 
+-	for (i = 1; i < argc; i++)
+-		expand_user_dn_as_member (conn, attrs, argv[i], 1);
++	for (i = 1; i < argc; i++) {
++		res = expand_user_dn_as_member (conn, attrs, argv[i], 1);
++		if (res != ADCLI_SUCCESS) {
++			adcli_attrs_free (attrs);
++			adcli_entry_unref (entry);
++			return res;
++		}
++	}
+ 
+ 	res = adcli_entry_modify (entry, attrs);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "adding member(s) to group %s in domain %s failed: %s",
+-		      adcli_entry_get_sam_name (entry),
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("adding member(s) to group %s in domain %s failed: %s",
++		       adcli_entry_get_sam_name (entry),
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_attrs_free (attrs);
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	adcli_attrs_free (attrs);
+@@ -672,33 +733,48 @@ adcli_tool_member_remove (adcli_conn *conn,
+ 	argc -= optind;
+ 	argv += optind;
+ 
+-	if (argc < 2)
+-		errx (2, "specify a group name and a user to remove");
++	if (argc < 2) {
++		warnx ("specify a group name and a user to remove");
++		return 2;
++	}
+ 
+ 	entry = adcli_entry_new_group (conn, argv[0]);
+-	if (entry == NULL)
+-		errx (-1, "unexpected memory problems");
++	if (entry == NULL) {
++		warnx ("unexpected memory problems");
++		return -1;
++	}
+ 
+ 	adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 	res = adcli_conn_connect (conn);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "couldn't connect to %s domain: %s",
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("couldn't connect to %s domain: %s",
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	attrs = adcli_attrs_new ();
+ 
+-	for (i = 1; i < argc; i++)
+-		expand_user_dn_as_member (conn, attrs, argv[i], 0);
++	for (i = 1; i < argc; i++) {
++		res = expand_user_dn_as_member (conn, attrs, argv[i], 0);
++		if (res != ADCLI_SUCCESS) {
++			adcli_attrs_free (attrs);
++			adcli_entry_unref (entry);
++			return res;
++		}
++	}
+ 
+ 	res = adcli_entry_modify (entry, attrs);
+ 	if (res != ADCLI_SUCCESS) {
+-		errx (-res, "adding member(s) to group %s in domain %s failed: %s",
+-		      adcli_entry_get_sam_name (entry),
+-		      adcli_conn_get_domain_name (conn),
+-		      adcli_get_last_error ());
++		warnx ("adding member(s) to group %s in domain %s failed: %s",
++		       adcli_entry_get_sam_name (entry),
++		       adcli_conn_get_domain_name (conn),
++		       adcli_get_last_error ());
++		adcli_attrs_free (attrs);
++		adcli_entry_unref (entry);
++		return -res;
+ 	}
+ 
+ 	adcli_attrs_free (attrs);
+-- 
+2.20.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/0003-library-_adcli_krb5_build_principal-allow-principals.patch b/SOURCES/0003-library-_adcli_krb5_build_principal-allow-principals.patch
new file mode 100644
index 0000000..217636c
--- /dev/null
+++ b/SOURCES/0003-library-_adcli_krb5_build_principal-allow-principals.patch
@@ -0,0 +1,42 @@
+From 10a4dbb5978b6f05cf75f820d97da908e735ace8 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Mar 2019 10:37:11 +0100
+Subject: [PATCH 3/4] library: _adcli_krb5_build_principal allow principals as
+ names
+
+Make _adcli_krb5_build_principal a bit more robust by checking if the
+given name already contains a realm suffix.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
+---
+ library/adkrb5.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/library/adkrb5.c b/library/adkrb5.c
+index 7f77373..da835d7 100644
+--- a/library/adkrb5.c
++++ b/library/adkrb5.c
+@@ -41,12 +41,16 @@ _adcli_krb5_build_principal (krb5_context k5,
+                              krb5_principal *principal)
+ {
+ 	krb5_error_code code;
+-	char *name;
++	char *name = NULL;
+ 
+-	if (asprintf (&name, "%s@%s", user, realm) < 0)
+-		return_val_if_reached (ENOMEM);
++	/* Use user if user contains a @-character and add @realm otherwise */
++	if (strchr (user, '@') == NULL) {
++		if (asprintf (&name, "%s@%s", user, realm) < 0) {
++			return_val_if_reached (ENOMEM);
++		}
++	}
+ 
+-	code = krb5_parse_name (k5, name, principal);
++	code = krb5_parse_name (k5, name != NULL ? name : user, principal);
+ 	return_val_if_fail (code == 0, code);
+ 
+ 	free (name);
+-- 
+2.20.1
+
diff --git a/SOURCES/0003-tools-remove-errx-from-info-commands.patch b/SOURCES/0003-tools-remove-errx-from-info-commands.patch
new file mode 100644
index 0000000..c53cf50
--- /dev/null
+++ b/SOURCES/0003-tools-remove-errx-from-info-commands.patch
@@ -0,0 +1,53 @@
+From 4794812cc98c8783921f534d20dae8b44f3826d2 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 15 Apr 2019 17:57:37 +0200
+Subject: [PATCH 3/7] tools: remove errx from info commands
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/info.c | 21 ++++++++++++++-------
+ 1 file changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/tools/info.c b/tools/info.c
+index e7e20ad..c63e0ff 100644
+--- a/tools/info.c
++++ b/tools/info.c
+@@ -162,21 +162,28 @@ adcli_tool_info (adcli_conn *unused,
+ 
+ 	if (argc == 1)
+ 		domain = argv[0];
+-	else if (argc != 0)
+-		errx (2, "specify one user name to create");
++	else if (argc != 0) {
++		warnx ("specify one user name to create");
++		return 2;
++	}
+ 
+ 	if (server) {
+ 		adcli_disco_host (server, &disco);
+-		if (disco == NULL)
+-			errx (1, "couldn't discover domain controller: %s", server);
++		if (disco == NULL) {
++			warnx ("couldn't discover domain controller: %s", server);
++			return 1;
++		}
+ 		for_host = 1;
+ 	} else if (domain) {
+ 		adcli_disco_domain (domain, &disco);
+-		if (disco == NULL)
+-			errx (1, "couldn't discover domain: %s", domain);
++		if (disco == NULL) {
++			warnx ("couldn't discover domain: %s", domain);
++			return 1;
++		}
+ 		for_host = 0;
+ 	} else {
+-		errx (2, "specify a domain to discover");
++		warnx ("specify a domain to discover");
++		return 2;
+ 	}
+ 
+ 	print_info (disco, for_host);
+-- 
+2.20.1
+
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/SOURCES/0004-library-make-sure-server-side-SPNs-are-preserved.patch b/SOURCES/0004-library-make-sure-server-side-SPNs-are-preserved.patch
new file mode 100644
index 0000000..07cc8fb
--- /dev/null
+++ b/SOURCES/0004-library-make-sure-server-side-SPNs-are-preserved.patch
@@ -0,0 +1,82 @@
+From 972f1a2f35829ed89f5353bd204683aa9ad6a2d2 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 22 Mar 2019 10:37:57 +0100
+Subject: [PATCH 4/4] library: make sure server side SPNs are preserved
+
+adcli should not delete service principal names (SPNs) unexpectedly. If
+a SPN was added on the server while presetting a host or updating an
+existing entry and upcoming adcli join or update should preserver this
+change.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1630187
+---
+ library/adenroll.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 46 insertions(+)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 48cb4cf..1cce86a 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -1961,6 +1961,47 @@ adcli_enroll_prepare (adcli_enroll *enroll,
+ 	return res;
+ }
+ 
++static adcli_result
++add_server_side_service_principals (adcli_enroll *enroll)
++{
++	char **spn_list;
++	LDAP *ldap;
++	size_t c;
++	int length = 0;
++	adcli_result res;
++
++	ldap = adcli_conn_get_ldap_connection (enroll->conn);
++	assert (ldap != NULL);
++
++	spn_list = _adcli_ldap_parse_values (ldap, enroll->computer_attributes,
++	                                     "servicePrincipalName");
++	if (spn_list == NULL) {
++		return ADCLI_SUCCESS;
++	}
++
++	if (enroll->service_principals != NULL) {
++		length = seq_count (enroll->service_principals);
++	}
++
++	for (c = 0; spn_list[c] != NULL; c++) {
++		_adcli_info ("Checking %s", spn_list[c]);
++		if (!_adcli_strv_has_ex (enroll->service_principals_to_remove, spn_list[c], strcasecmp)) {
++			enroll->service_principals = _adcli_strv_add_unique (enroll->service_principals,
++		                                                             spn_list[c], &length, false);
++			assert (enroll->service_principals != NULL);
++			_adcli_info ("   Added %s", spn_list[c]);
++		}
++	}
++	_adcli_strv_free (spn_list);
++
++	res = ensure_keytab_principals (ADCLI_SUCCESS, enroll);
++	if (res != ADCLI_SUCCESS) {
++		return res;
++	}
++
++	return ADCLI_SUCCESS;
++}
++
+ static adcli_result
+ enroll_join_or_update_tasks (adcli_enroll *enroll,
+ 		             adcli_enroll_flags flags)
+@@ -2019,6 +2060,11 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
+ 	update_and_calculate_enctypes (enroll);
+ 	update_computer_account (enroll);
+ 
++	res = add_server_side_service_principals (enroll);
++	if (res != ADCLI_SUCCESS) {
++		return res;
++	}
++
+ 	/* service_names is only set from input on the command line, so no
+ 	 * additional check for explicit is needed here */
+ 	if (enroll->service_names != NULL) {
+-- 
+2.20.1
+
diff --git a/SOURCES/0004-tools-remove-errx-from-adcli_read_password_func.patch b/SOURCES/0004-tools-remove-errx-from-adcli_read_password_func.patch
new file mode 100644
index 0000000..1b53d7d
--- /dev/null
+++ b/SOURCES/0004-tools-remove-errx-from-adcli_read_password_func.patch
@@ -0,0 +1,42 @@
+From 251d7d0c71226afb8e51f7bc5794a7a3164f5a20 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 15 Apr 2019 17:59:17 +0200
+Subject: [PATCH 4/7] tools: remove errx from adcli_read_password_func
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/tools.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/tools/tools.c b/tools/tools.c
+index c4e2851..bdf6d38 100644
+--- a/tools/tools.c
++++ b/tools/tools.c
+@@ -247,7 +247,9 @@ adcli_read_password_func (adcli_login_type login_type,
+ 		if (res < 0) {
+ 			if (errno == EAGAIN || errno == EINTR)
+ 				continue;
+-			err (EFAIL, "couldn't read password from stdin");
++			warn ("couldn't read password from stdin");
++			free (buffer);
++			return NULL;
+ 
+ 		} else if (res == 0) {
+ 			buffer[offset] = '\0';
+@@ -261,8 +263,11 @@ adcli_read_password_func (adcli_login_type login_type,
+ 			return buffer;
+ 
+ 		} else {
+-			if (memchr (buffer + offset, 0, res))
+-				errx (EUSAGE, "unsupported null character present in password");
++			if (memchr (buffer + offset, 0, res)) {
++				warnx ("unsupported null character present in password");
++				free (buffer);
++				return NULL;
++			}
+ 			offset += res;
+ 		}
+ 	}
+-- 
+2.20.1
+
diff --git a/SOURCES/0005-tools-remove-errx-from-setup_krb5_conf_directory.patch b/SOURCES/0005-tools-remove-errx-from-setup_krb5_conf_directory.patch
new file mode 100644
index 0000000..8fd9197
--- /dev/null
+++ b/SOURCES/0005-tools-remove-errx-from-setup_krb5_conf_directory.patch
@@ -0,0 +1,63 @@
+From b8f5d995d30c17eb8bec3ac5e0777ea94f5b76c3 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 15 Apr 2019 18:00:52 +0200
+Subject: [PATCH 5/7] tools: remove errx from setup_krb5_conf_directory
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/tools.c | 38 ++++++++++++++++++++++++--------------
+ 1 file changed, 24 insertions(+), 14 deletions(-)
+
+diff --git a/tools/tools.c b/tools/tools.c
+index bdf6d38..fc9fa9a 100644
+--- a/tools/tools.c
++++ b/tools/tools.c
+@@ -327,21 +327,31 @@ setup_krb5_conf_directory (adcli_conn *conn)
+ 	}
+ 
+ 	if (asprintf (&directory, "%s%sadcli-krb5-XXXXXX", parent,
+-	              (parent[0] && parent[strlen(parent) - 1] == '/') ? "" : "/") < 0)
+-		errx (1, "unexpected: out of memory");
+-
+-	if (mkdtemp (directory) == NULL) {
+-		errn = errno;
++	              (parent[0] && parent[strlen(parent) - 1] == '/') ? "" : "/") < 0) {
++		warnx ("unexpected: out of memory");
++		directory = NULL; /* content is undefined */
+ 		failed = 1;
+-		warnx ("couldn't create temporary directory in: %s: %s",
+-		       parent, strerror (errn));
+-	} else {
+-		if (asprintf (&filename, "%s/krb5.conf", directory) < 0 ||
+-		    asprintf (&snippets, "%s/krb5.d", directory) < 0 ||
+-		    asprintf (&contents, "includedir %s\n%s%s\n", snippets,
+-		              krb5_conf ? "include " : "",
+-		              krb5_conf ? krb5_conf : "") < 0)
+-			errx (1, "unexpected: out of memory");
++	}
++
++	if (!failed) {
++		if (mkdtemp (directory) == NULL) {
++			errn = errno;
++			failed = 1;
++			warnx ("couldn't create temporary directory in: %s: %s",
++			       parent, strerror (errn));
++		} else {
++			if (asprintf (&filename, "%s/krb5.conf", directory) < 0 ||
++			    asprintf (&snippets, "%s/krb5.d", directory) < 0 ||
++			    asprintf (&contents, "includedir %s\n%s%s\n", snippets,
++			              krb5_conf ? "include " : "",
++			              krb5_conf ? krb5_conf : "") < 0) {
++				warnx ("unexpected: out of memory");
++				filename = NULL; /* content is undefined */
++				snippets = NULL; /* content is undefined */
++				contents = NULL; /* content is undefined */
++				failed = 1;
++			}
++		}
+ 	}
+ 
+ 	if (!failed) {
+-- 
+2.20.1
+
diff --git a/SOURCES/0006-tools-entry-remove-errx-from-parse_option.patch b/SOURCES/0006-tools-entry-remove-errx-from-parse_option.patch
new file mode 100644
index 0000000..17bb9c4
--- /dev/null
+++ b/SOURCES/0006-tools-entry-remove-errx-from-parse_option.patch
@@ -0,0 +1,175 @@
+From d9912e19e48ec482351b9c384140ad71922ec5c0 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 8 Apr 2019 17:22:00 +0200
+Subject: [PATCH 6/7] tools: entry - remove errx from parse_option
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/entry.c | 70 ++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 47 insertions(+), 23 deletions(-)
+
+diff --git a/tools/entry.c b/tools/entry.c
+index 97ec6e7..f361845 100644
+--- a/tools/entry.c
++++ b/tools/entry.c
+@@ -81,7 +81,7 @@ static adcli_tool_desc common_usages[] = {
+ 	{ 0 },
+ };
+ 
+-static void
++static int
+ parse_option (Option opt,
+               const char *optarg,
+               adcli_conn *conn)
+@@ -93,54 +93,58 @@ parse_option (Option opt,
+ 	switch (opt) {
+ 	case opt_login_ccache:
+ 		adcli_conn_set_login_ccache_name (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_login_user:
+ 		adcli_conn_set_login_user (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain:
+ 		adcli_conn_set_domain_name (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain_realm:
+ 		adcli_conn_set_domain_realm (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain_controller:
+ 		adcli_conn_set_domain_controller (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_no_password:
+ 		if (stdin_password || prompt_password) {
+-			errx (EUSAGE, "cannot use --no-password argument with %s",
+-			      stdin_password ? "--stdin-password" : "--prompt-password");
++			warnx ("cannot use --no-password argument with %s",
++			       stdin_password ? "--stdin-password" : "--prompt-password");
++			return EUSAGE;
+ 		} else {
+ 			adcli_conn_set_password_func (conn, NULL, NULL, NULL);
+ 			no_password = 1;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_prompt_password:
+ 		if (stdin_password || no_password) {
+-			errx (EUSAGE, "cannot use --prompt-password argument with %s",
+-			      stdin_password ? "--stdin-password" : "--no-password");
++			warnx ("cannot use --prompt-password argument with %s",
++			       stdin_password ? "--stdin-password" : "--no-password");
++			return EUSAGE;
+ 		} else {
+ 			adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL);
+ 			prompt_password = 1;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_stdin_password:
+ 		if (prompt_password || no_password) {
+-			errx (EUSAGE, "cannot use --stdin-password argument with %s",
+-			      prompt_password ? "--prompt-password" : "--no-password");
++			warnx ("cannot use --stdin-password argument with %s",
++			       prompt_password ? "--prompt-password" : "--no-password");
++			return EUSAGE;
+ 		} else {
+ 			adcli_conn_set_password_func (conn, adcli_read_password_func, NULL, NULL);
+ 			stdin_password = 1;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_verbose:
+-		return;
++		return ADCLI_SUCCESS;
+ 	default:
+ 		assert (0 && "not reached");
+ 		break;
+ 	}
+ 
+-	errx (EUSAGE, "failure to parse option '%c'", opt);
++	warnx ("failure to parse option '%c'", opt);
++	return EUSAGE;
+ }
+ 
+ int
+@@ -224,7 +228,11 @@ adcli_tool_user_create (adcli_conn *conn,
+ 			adcli_attrs_free (attrs);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn);
++			res = parse_option ((Option)opt, optarg, conn);
++			if (res != ADCLI_SUCCESS) {
++				adcli_attrs_free (attrs);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -322,7 +330,10 @@ adcli_tool_user_delete (adcli_conn *conn,
+ 			adcli_tool_usage (options, common_usages);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn);
++			res = parse_option ((Option)opt, optarg, conn);
++			if (res != ADCLI_SUCCESS) {
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -417,7 +428,11 @@ adcli_tool_group_create (adcli_conn *conn,
+ 			adcli_attrs_free (attrs);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn);
++			res = parse_option ((Option)opt, optarg, conn);
++			if (res != ADCLI_SUCCESS) {
++				adcli_attrs_free (attrs);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -505,7 +520,10 @@ adcli_tool_group_delete (adcli_conn *conn,
+ 			adcli_tool_usage (options, common_usages);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn);
++			res = parse_option ((Option)opt, optarg, conn);
++			if (res != ADCLI_SUCCESS) {
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -628,7 +646,10 @@ adcli_tool_member_add (adcli_conn *conn,
+ 			adcli_tool_usage (options, common_usages);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn);
++			res = parse_option ((Option)opt, optarg, conn);
++			if (res != ADCLI_SUCCESS) {
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -725,7 +746,10 @@ adcli_tool_member_remove (adcli_conn *conn,
+ 			adcli_tool_usage (options, common_usages);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn);
++			res = parse_option ((Option)opt, optarg, conn);
++			if (res != ADCLI_SUCCESS) {
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+-- 
+2.20.1
+
diff --git a/SOURCES/0007-tools-computer-remove-errx-from-parse_option.patch b/SOURCES/0007-tools-computer-remove-errx-from-parse_option.patch
new file mode 100644
index 0000000..065fc9f
--- /dev/null
+++ b/SOURCES/0007-tools-computer-remove-errx-from-parse_option.patch
@@ -0,0 +1,294 @@
+From f127ddef23a532cd9763190527bf79b4e47fa2ab Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 8 Apr 2019 17:33:17 +0200
+Subject: [PATCH 7/7] tools: computer - remove errx from parse_option
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1588596
+---
+ tools/computer.c | 128 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 80 insertions(+), 48 deletions(-)
+
+diff --git a/tools/computer.c b/tools/computer.c
+index 9cbbb28..ac8a203 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -159,7 +159,7 @@ static adcli_tool_desc common_usages[] = {
+ 	{ 0 },
+ };
+ 
+-static void
++static int
+ parse_option (Option opt,
+               const char *optarg,
+               adcli_conn *conn,
+@@ -175,132 +175,139 @@ parse_option (Option opt,
+ 	switch (opt) {
+ 	case opt_login_ccache:
+ 		adcli_conn_set_login_ccache_name (conn, optarg ? optarg : "");
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_login_user:
+ 		if (adcli_conn_get_allowed_login_types (conn) & ADCLI_LOGIN_USER_ACCOUNT) {
+ 			adcli_conn_set_login_user (conn, optarg);
+ 			adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 		} else {
+-			errx (EUSAGE, "cannot set --user if --login-type not set to 'user'");
++			warnx ("cannot set --user if --login-type not set to 'user'");
++			return EUSAGE;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_login_type:
+ 		if (optarg && strcmp (optarg, "computer") == 0) {
+-			if (adcli_conn_get_login_user (conn) != NULL)
+-				errx (EUSAGE, "cannot set --login-type to 'computer' if --user is set");
+-			else
++			if (adcli_conn_get_login_user (conn) != NULL) {
++				warnx ("cannot set --login-type to 'computer' if --user is set");
++				return EUSAGE;
++			} else
+ 				adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_COMPUTER_ACCOUNT);
+ 		} else if (optarg && strcmp (optarg, "user") == 0) {
+ 			adcli_conn_set_allowed_login_types (conn, ADCLI_LOGIN_USER_ACCOUNT);
+ 
+ 		} else {
+-			errx (EUSAGE, "unknown login type '%s'", optarg);
++			warnx ("unknown login type '%s'", optarg);
++			return EUSAGE;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_host_fqdn:
+ 		adcli_conn_set_host_fqdn (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_host_keytab:
+ 		adcli_enroll_set_keytab_name (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_computer_name:
+ 		adcli_conn_set_computer_name (conn, optarg);
+ 		adcli_enroll_set_computer_name (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain:
+ 		adcli_conn_set_domain_name (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain_realm:
+ 		adcli_conn_set_domain_realm (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain_controller:
+ 		adcli_conn_set_domain_controller (conn, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_domain_ou:
+ 		adcli_enroll_set_domain_ou (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_service_name:
+ 		adcli_enroll_add_service_name (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_no_password:
+ 		if (stdin_password || prompt_password) {
+-			errx (EUSAGE, "cannot use --no-password argument with %s",
+-			      stdin_password ? "--stdin-password" : "--prompt-password");
++			warnx ("cannot use --no-password argument with %s",
++			       stdin_password ? "--stdin-password" : "--prompt-password");
++			return EUSAGE;
+ 		} else {
+ 			adcli_conn_set_password_func (conn, NULL, NULL, NULL);
+ 			no_password = 1;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_prompt_password:
+ 		if (stdin_password || no_password) {
+-			errx (EUSAGE, "cannot use --prompt-password argument with %s",
+-			      stdin_password ? "--stdin-password" : "--no-password");
++			warnx ("cannot use --prompt-password argument with %s",
++			       stdin_password ? "--stdin-password" : "--no-password");
++			return EUSAGE;
+ 		} else {
+ 			adcli_conn_set_password_func (conn, adcli_prompt_password_func, NULL, NULL);
+ 			prompt_password = 1;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_stdin_password:
+ 		if (prompt_password || no_password) {
+-			errx (EUSAGE, "cannot use --stdin-password argument with %s",
+-			      prompt_password ? "--prompt-password" : "--no-password");
++			warnx ("cannot use --stdin-password argument with %s",
++			       prompt_password ? "--prompt-password" : "--no-password");
++			return EUSAGE;
+ 		} else {
+ 			adcli_conn_set_password_func (conn, adcli_read_password_func, NULL, NULL);
+ 			stdin_password = 1;
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_os_name:
+ 		adcli_enroll_set_os_name (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_os_version:
+ 		adcli_enroll_set_os_version (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_os_service_pack:
+ 		adcli_enroll_set_os_service_pack (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_user_principal:
+ 		if (optarg && optarg[0])
+ 			adcli_enroll_set_user_principal (enroll, optarg);
+ 		else
+ 			adcli_enroll_auto_user_principal (enroll);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_computer_password_lifetime:
+ 		errno = 0;
+ 		lifetime = strtoul (optarg, &endptr, 10);
+ 		if (errno != 0 || *endptr != '\0' || endptr == optarg) {
+-			errx (EUSAGE,
+-			      "failure to parse value '%s' of option 'computer-password-lifetime'; "
+-			      "expecting non-negative integer indicating the lifetime in days",
+-			      optarg);
++			warnx ("failure to parse value '%s' of option 'computer-password-lifetime'; "
++			       "expecting non-negative integer indicating the lifetime in days",
++			       optarg);
++			return EUSAGE;
+ 		}
+ 
+ 		adcli_enroll_set_computer_password_lifetime (enroll, lifetime);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_samba_data_tool:
+ 		errno = 0;
+ 		ret = access (optarg, X_OK);
+ 		if (ret != 0) {
+ 			ret = errno;
+-			errx (EUSAGE, "Failed to access tool to add Samba data: %s", strerror (ret));
++			warnx ("Failed to access tool to add Samba data: %s", strerror (ret));
++			return EUSAGE;
+ 		} else {
+ 			adcli_enroll_set_samba_data_tool (enroll, optarg);
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_trusted_for_delegation:
+ 		if (strcasecmp (optarg, "true") == 0 || strcasecmp (optarg, "yes") == 0) {
+ 			adcli_enroll_set_trusted_for_delegation (enroll, true);
+ 		} else {
+ 			adcli_enroll_set_trusted_for_delegation (enroll, false);
+ 		}
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_add_service_principal:
+ 		adcli_enroll_add_service_principal_to_add (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_remove_service_principal:
+ 		adcli_enroll_add_service_principal_to_remove (enroll, optarg);
+-		return;
++		return ADCLI_SUCCESS;
+ 	case opt_verbose:
+-		return;
++		return ADCLI_SUCCESS;
+ 
+ 	/* Should be handled by caller */
+ 	case opt_show_details:
+@@ -311,7 +318,8 @@ parse_option (Option opt,
+ 		break;
+ 	}
+ 
+-	errx (EUSAGE, "failure to parse option '%c'", opt);
++	warnx ("failure to parse option '%c'", opt);
++	return EUSAGE;
+ }
+ 
+ static void
+@@ -407,7 +415,11 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 			adcli_enroll_unref (enroll);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn, enroll);
++			res = parse_option ((Option)opt, optarg, conn, enroll);
++			if (res != ADCLI_SUCCESS) {
++				adcli_enroll_unref (enroll);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -519,7 +531,11 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 			adcli_enroll_unref (enroll);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn, enroll);
++			res = parse_option ((Option)opt, optarg, conn, enroll);
++			if (res != ADCLI_SUCCESS) {
++				adcli_enroll_unref (enroll);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -610,7 +626,11 @@ adcli_tool_computer_testjoin (adcli_conn *conn,
+ 			adcli_enroll_unref (enroll);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn, enroll);
++			res = parse_option ((Option)opt, optarg, conn, enroll);
++			if (res != ADCLI_SUCCESS) {
++				adcli_enroll_unref (enroll);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -707,7 +727,11 @@ adcli_tool_computer_preset (adcli_conn *conn,
+ 			adcli_enroll_unref (enroll);
+ 			return 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn, enroll);
++			res = parse_option ((Option)opt, optarg, conn, enroll);
++			if (res != ADCLI_SUCCESS) {
++				adcli_enroll_unref (enroll);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -801,7 +825,11 @@ adcli_tool_computer_reset (adcli_conn *conn,
+ 			adcli_enroll_unref (enroll);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn, enroll);
++			res = parse_option ((Option)opt, optarg, conn, enroll);
++			if (res != ADCLI_SUCCESS) {
++				adcli_enroll_unref (enroll);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+@@ -884,7 +912,11 @@ adcli_tool_computer_delete (adcli_conn *conn,
+ 			adcli_enroll_unref (enroll);
+ 			return opt == 'h' ? 0 : 2;
+ 		default:
+-			parse_option ((Option)opt, optarg, conn, enroll);
++			res = parse_option ((Option)opt, optarg, conn, enroll);
++			if (res != ADCLI_SUCCESS) {
++				adcli_enroll_unref (enroll);
++				return res;
++			}
+ 			break;
+ 		}
+ 	}
+-- 
+2.20.1
+
diff --git a/SPECS/adcli.spec b/SPECS/adcli.spec
index c60909d..371dfe4 100644
--- a/SPECS/adcli.spec
+++ b/SPECS/adcli.spec
@@ -1,6 +1,6 @@
 Name:		adcli
 Version:	0.8.2
-Release:	2%{?dist}
+Release:	3%{?dist}
 Summary:	Active Directory enrollment
 License:	LGPLv2+
 URL:		http://cgit.freedesktop.org/realmd/adcli
@@ -36,6 +36,60 @@ Patch26:	0002-_adcli_call_external_program-silence-noisy-debug-mes.patch
 Patch27:	0003-Do-not-add-service-principals-twice.patch
 Patch28:	0004-Do-not-depend-on-default_realm-in-krb5.conf.patch
 
+# rhbz#1677194 -  Realm cannot join domain when hostname is not FQDN
+Patch29:	0001-adutil-add-_adcli_strv_add_unique.patch
+Patch30:	0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1642546 - adcli exports kerberos ticket
+# with old kvno
+Patch31:	0001-Increment-kvno-after-password-change-with-user-creds.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1595911 - [RFE] Have `adcli join` work
+# without FQDN in `hostname` output
+Patch32:	0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1644311 - Improve handling of service
+# principals
+Patch33:	0001-join-always-add-service-principals.patch
+Patch34:	0002-library-return-error-if-no-matching-key-was-found.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1337489 - [RFE] adcli command with
+# --unix-* options doesn't update values in UnixAttributes Tab for user
+Patch35:	0001-create-user-add-nis-domain-option.patch
+Patch36:	0002-create-user-try-to-find-NIS-domain-if-needed.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1630187 - [RFE] adcli join should
+# preserve SPN added by adcli preset-computer
+Patch37:	0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch
+Patch38:	0002-library-make-_adcli_strv_has_ex-public.patch
+Patch39:	0003-library-_adcli_krb5_build_principal-allow-principals.patch
+Patch40:	0004-library-make-sure-server-side-SPNs-are-preserved.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1622583 - [RFE] Need an option for adcli
+# command which will show domain join status.
+Patch41:	0001-Implement-adcli-testjoin.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1630187 - [RFE] adcli join should
+# preserve SPN added by adcli preset-computer - additional patch
+Patch42:	0001-library-add-missing-strdup.patch
+
+# Forward port of RHEL-7.7 ticket rhbz#1588596 - many adcli-krb5-?????
+# directories are created /tmp
+Patch43:	0001-tools-remove-errx-from-computer-commands.patch
+Patch44:	0002-tools-remove-errx-from-user-and-group-commands.patch
+Patch45:	0003-tools-remove-errx-from-info-commands.patch
+Patch46:	0004-tools-remove-errx-from-adcli_read_password_func.patch
+Patch47:	0005-tools-remove-errx-from-setup_krb5_conf_directory.patch
+Patch48:	0006-tools-entry-remove-errx-from-parse_option.patch
+Patch49:	0007-tools-computer-remove-errx-from-parse_option.patch
+
+# rhbz#1717355 - `adcli join` fails in FIPS enabled environment
+Patch50:	0001-Fix-for-issues-found-by-Coverity.patch
+Patch51:	0001-adenroll-make-sure-only-allowed-enctypes-are-used-in.patch
+Patch52:	0002-adconn-add-adcli_conn_set_krb5_context.patch
+Patch53:	0003-adenroll-add-adcli_enroll_get_permitted_keytab_encty.patch
+Patch54:	0004-adenroll-use-only-enctypes-permitted-by-Kerberos-con.patch
+
 BuildRequires:	gcc
 BuildRequires:	intltool pkgconfig
 BuildRequires:	libtool
@@ -58,35 +112,7 @@ standard LDAP and Kerberos calls.
 %define _hardened_build 1
 
 %prep
-%setup -q
-%patch1 -p1
-%patch2 -p1
-%patch3 -p1
-%patch4 -p1
-%patch5 -p1
-%patch6 -p1
-%patch7 -p1
-%patch8 -p1
-%patch9 -p1
-%patch10 -p1
-%patch11 -p1
-%patch12 -p1
-%patch13 -p1
-%patch14 -p1
-%patch15 -p1
-%patch16 -p1
-%patch17 -p1
-%patch18 -p1
-%patch19 -p1
-%patch20 -p1
-%patch21 -p1
-%patch22 -p1
-%patch23 -p1
-%patch24 -p1
-%patch25 -p1
-%patch26 -p1
-%patch27 -p1
-%patch28 -p1
+%autosetup -p1
 
 %build
 autoreconf --force --install --verbose
@@ -124,6 +150,13 @@ documentation.
 %doc %{_datadir}/doc/adcli/*
 
 %changelog
+* Fri Jun 14 2019 Sumit Bose <sbose@redhat.com> - 0.8.2-3
+- use autosetup macro to simplify patch handling
+- fixed rpmlint warnings in the spec file
+- join failed if hostname is not FQDN [#1677194]
+- adcli join fails in FIPS enabled environment [#1717355]
+- forward port of RHEL-7.7 fixes and enhancements
+
 * Tue Oct 09 2018 Sumit Bose <sbose@redhat.com> - 0.8.2-2
 - Do not add service principals twice and related fixes
 - Resolves: rhbz#1631734