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-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-doc-fix-typos-in-the-adcli-man-page.patch b/SOURCES/0001-doc-fix-typos-in-the-adcli-man-page.patch
new file mode 100644
index 0000000..41bd97a
--- /dev/null
+++ b/SOURCES/0001-doc-fix-typos-in-the-adcli-man-page.patch
@@ -0,0 +1,203 @@
+From 1143163c367b8473dc3d0ea696eed3c30ccd634b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 5 Jul 2018 13:06:26 +0200
+Subject: [PATCH] doc: fix typos in the adcli man page
+
+Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1440533
+---
+ doc/adcli.xml | 44 ++++++++++++++++++++++----------------------
+ 1 file changed, 22 insertions(+), 22 deletions(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index 83b6981..97dec08 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -105,19 +105,19 @@
+ 		<varlistentry>
+ 			<term><option>-D, --domain=<parameter>domain</parameter></option></term>
+ 			<listitem><para>The domain to connect to. If a domain is
+-			not specified then the domain part of the local computer's
++			not specified, then the domain part of the local computer's
+ 			host name is used.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-R, --domain-realm=<parameter>REALM</parameter></option></term>
+ 			<listitem><para>Kerberos realm for the domain. If not
+-			specified then the upper cased domain name is
++			specified, then the upper cased domain name is
+ 			used.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-S, --domain-controller=<parameter>server</parameter></option></term>
+ 			<listitem><para>Connect to a specific domain controller.
+-			If not specified then an appropriate domain controller
++			If not specified, then an appropriate domain controller
+ 			is automatically discovered.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+@@ -134,7 +134,7 @@
+ 		<varlistentry>
+ 			<term><option>-U, --login-user=<parameter>User</parameter></option></term>
+ 			<listitem><para>Use the specified user account to
+-			authenticate with the domain. If not specified then
++			authenticate with the domain. If not specified, then
+ 			the name 'Administrator' will be used.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+@@ -181,7 +181,7 @@ $ adcli info --domain-controller=dc.domain.example.com
+ 	<para><command>adcli info</command> will output as much information as
+ 	it can about the domain. The information is designed to be both machine
+ 	and human readable. The command will exit with a non-zero exit code
+-	if the domain does note exist or cannot be reached.</para>
++	if the domain does not exist or cannot be reached.</para>
+ 
+ 	<para>To show domain info for a specific domain controller use the
+ 	<option>--domain-controller</option> option to specify which domain
+@@ -213,35 +213,35 @@ Password for Administrator:
+ 		<varlistentry>
+ 			<term><option>-N, --computer-name=<parameter>computer</parameter></option></term>
+ 			<listitem><para>The short non-dotted name of the computer
+-			account that will be created in the domain. If not specified
++			account that will be created in the domain. If not specified,
+ 			then the first portion of the <option>--host-fqdn</option>
+ 			is used.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-O, --domain-ou=<parameter>OU=xxx</parameter></option></term>
+ 			<listitem><para>The full distinguished name of the OU in
+-			which to create the computer account. If not specified
++			which to create the computer account. If not specified,
+ 			then the computer account will be created in a default
+ 			location.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<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
++			domain name. If not specified, the local machine's hostname
+ 			will be retrieved via <function>gethostname()</function>.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-K, --host-keytab=<parameter>/path/to/keytab</parameter></option></term>
+ 			<listitem><para>Specify the path to the host keytab where
+ 			host credentials will be written after a successful join
+-			operation. If not specified the default location will be
++			operation. If not specified, the default location will be
+ 			used, usually <filename>/etc/krb5.keytab</filename>.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--login-type=<parameter>{computer|user}</parameter></option></term>
+ 			<listitem><para>Specify the type of authentication that
+ 			will be performed before creating the machine account in
+-			the domain. If set to 'computer' then the computer must
++			the domain. If set to 'computer', then the computer must
+ 			already have a preset account in the domain. If not
+ 			specified and none of the other <option>--login-xxx</option>
+ 			arguments have been specified, then will try both
+@@ -329,7 +329,7 @@ Password for Administrator:
+ 			<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+ 			<listitem><para>If Samba's <command>net</command>
+ 			cannot be found at
+-			<filename>&samba_data_tool;</filename> this option can
++			<filename>&samba_data_tool;</filename>, this option can
+ 			be used to specific an alternative location with the
+ 			help of an absolute path.</para></listitem>
+ 		</varlistentry>
+@@ -351,7 +351,7 @@ Password for Administrator:
+ $ adcli update
+ </programlisting>
+ 
+-	<para>If used with a credential cache other attributes of the computer
++	<para>If used with a credential cache, other attributes of the computer
+ 	account can be changed as well if the principal has sufficient
+ 	privileges.</para>
+ 
+@@ -367,20 +367,20 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 		<varlistentry>
+ 			<term><option>-N, --computer-name=<parameter>computer</parameter></option></term>
+ 			<listitem><para>The short non-dotted name of the computer
+-			account that will be created in the domain. If not specified
++			account that will be created in the domain. If not specified,
+ 			it will be retrieved from the keytab entries.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>-H, --host-fqdn=<parameter>host</parameter></option></term>
+ 			<listitem><para>The local machine's fully qualified
+-			domain name. If not specified the local machine's hostname
++			domain name. If not specified, the local machine's hostname
+ 			will be retrieved from the keytab entries.</para></listitem>
+ 		</varlistentry>
+ 		<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
++			will be written to.  If not specified, the default
+ 			location will be used, usually
+ 			<filename>/etc/krb5.keytab</filename>.</para></listitem>
+ 		</varlistentry>
+@@ -462,7 +462,7 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 			<term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+ 			<listitem><para>If Samba's <command>net</command>
+ 			cannot be found at
+-			<filename>&samba_data_tool;</filename> this option can
++			<filename>&samba_data_tool;</filename>, this option can
+ 			be used to specific an alternative location with the
+ 			help of an absolute path.</para></listitem>
+ 		</varlistentry>
+@@ -493,7 +493,7 @@ $ adcli create-user Fry --domain=domain.example.com \
+ 		<varlistentry>
+ 			<term><option>-O, --domain-ou=<parameter>OU=xxx</parameter></option></term>
+ 			<listitem><para>The full distinguished name of the OU in
+-			which to create the user account. If not specified
++			which to create the user account. If not specified,
+ 			then the computer account will be created in a default
+ 			location.</para></listitem>
+ 		</varlistentry>
+@@ -569,7 +569,7 @@ $ adcli create-group Pilots --domain=domain.example.com \
+ 		<varlistentry>
+ 			<term><option>-O, --domain-ou=<parameter>OU=xxx</parameter></option></term>
+ 			<listitem><para>The full distinguished name of the OU in
+-			which to create the group. If not specified
++			which to create the group. If not specified,
+ 			then the group will be created in a default
+ 			location.</para></listitem>
+ 		</varlistentry>
+@@ -649,14 +649,14 @@ Password for Administrator:
+ 		<varlistentry>
+ 			<term><option>-O, --domain-ou=<parameter>OU=xxx</parameter></option></term>
+ 			<listitem><para>The full distinguished name of the OU in
+-			which to create the computer accounts. If not specified
++			which to create the computer accounts. If not specified,
+ 			then the computer account will be created in a default
+ 			location.</para></listitem>
+ 		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--one-time-password</option></term>
+ 			<listitem><para>Specify a one time password to use when
+-			presetting the computer accounts. If not specified then
++			presetting the computer accounts. If not specified, then
+ 			a default password will be used, which allows for later
+ 			automatic joins.</para></listitem>
+ 		</varlistentry>
+@@ -696,7 +696,7 @@ Password for Administrator:
+ 	<title>Reset Computer Account</title>
+ 
+ 	<para><command>adcli reset-computer</command> resets a computer account
+-	in the domain. If a the appropriate machine is currently joined to the
++	in the domain. If the appropriate machine is currently joined to the
+ 	domain, then its membership will be broken. The account must already
+ 	exist.</para>
+ 
+@@ -716,7 +716,7 @@ $ adcli reset-computer --domain=domain.example.com host2
+ 			<term><option>--login-type=<parameter>{computer|user}</parameter></option></term>
+ 			<listitem><para>Specify the type of authentication that
+ 			will be performed before creating the machine account in
+-			the domain. If set to 'computer' then the computer must
++			the domain. If set to 'computer', then the computer must
+ 			already have a preset account in the domain. If not
+ 			specified and none of the other <option>--login-xxx</option>
+ 			arguments have been specified, then will try both
+-- 
+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-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-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-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 7d864df..4fc9299 100644
--- a/SPECS/adcli.spec
+++ b/SPECS/adcli.spec
@@ -1,14 +1,14 @@
-Name:		adcli
-Version:	0.8.1
-Release:	6%{?dist}.1
-Summary:	Active Directory enrollment
-License:	LGPLv2+
-URL:		http://cgit.freedesktop.org/realmd/adcli
-Source0:	http://www.freedesktop.org/software/realmd/releases/adcli-%{version}.tar.gz
-Patch1:		0001-library-Fix-check-for-EAGAIN-or-EINTR.patch
-Patch2:		0002-Patch-to-adcli.xml-to-fix-documentation-error.patch
-Patch3:		0003-Remove-n-or-r-n-from-stdin-password.patch
-Patch4:		0001-delete-use-keytab-data-to-determine-realm-and-NetBIO.patch
+Name:           adcli
+Version:        0.8.1
+Release:        9%{?dist}
+Summary:        Active Directory enrollment
+License:        LGPLv2+
+URL:            http://cgit.freedesktop.org/realmd/adcli
+Source0:        http://www.freedesktop.org/software/realmd/releases/adcli-%{version}.tar.gz
+Patch1:         0001-library-Fix-check-for-EAGAIN-or-EINTR.patch
+Patch2:         0002-Patch-to-adcli.xml-to-fix-documentation-error.patch
+Patch3:         0003-Remove-n-or-r-n-from-stdin-password.patch
+Patch4:         0001-delete-use-keytab-data-to-determine-realm-and-NetBIO.patch
 Patch5:         0001-Remove-upper-case-only-check-when-looking-for-the-Ne.patch
 Patch6:         0002-Use-strdup-if-offset-are-used.patch
 Patch7:         0001-correct-spelling-of-adcli_tool_computer_delete-descr.patch
@@ -46,23 +46,63 @@ Patch31:        0003-Do-not-add-service-principals-twice.patch
 # Additional fixed for rhbz#1547014
 Patch32:        0004-Do-not-depend-on-default_realm-in-krb5.conf.patch
 
-# rhbz#1666775
+# rhbz#1649868
 Patch33:        0001-adutil-add-_adcli_strv_add_unique.patch
 Patch34:        0002-adenroll-use-_adcli_strv_add_unique-for-service-prin.patch
 
-BuildRequires:	intltool pkgconfig
-BuildRequires:	libtool
-BuildRequires:	gettext-devel
-BuildRequires:	krb5-devel
-BuildRequires:	openldap-devel
-BuildRequires:	libxslt
-BuildRequires:	xmlto
+# Patch35 is replaced by Patch49 - Patch55
 
-Requires:	cyrus-sasl-gssapi
+# rhbz#1642546 - adcli exports kerberos ticket with old kvno
+Patch36:        0001-Increment-kvno-after-password-change-with-user-creds.patch
+
+# rhbz#1595911 - [RFE] Have `adcli join` work without FQDN in `hostname` output
+#                with some additional man page fixes from rhbz#1440533
+Patch37:        0001-doc-fix-typos-in-the-adcli-man-page.patch
+Patch38:        0001-library-use-getaddrinfo-with-AI_CANONNAME-to-find-a-.patch
+
+# rhbz#1644311 - Improve handling of service principals
+Patch39:        0001-join-always-add-service-principals.patch
+Patch40:        0002-library-return-error-if-no-matching-key-was-found.patch
+
+# rhbz#1337489 - [RFE] adcli command with --unix-* options doesn't update
+#                values in UnixAttributes Tab for user
+Patch41:        0001-create-user-add-nis-domain-option.patch
+Patch42:        0002-create-user-try-to-find-NIS-domain-if-needed.patch
+
+# rhbz#1630187 - [RFE] adcli join should preserve SPN added by adcli preset-computer
+Patch43:        0001-ensure_keytab_principals-do-not-leak-memory-when-cal.patch
+Patch44:        0002-library-make-_adcli_strv_has_ex-public.patch
+Patch45:        0003-library-_adcli_krb5_build_principal-allow-principals.patch
+Patch46:        0004-library-make-sure-server-side-SPNs-are-preserved.patch
+
+# rhbz#1622583 - [RFE] Need an option for adcli command which will show domain join status.
+Patch47:        0001-Implement-adcli-testjoin.patch
+
+# rhbz#1630187 - [RFE] adcli join should preserve SPN added by adcli preset-computer - additional patch
+Patch48:        0001-library-add-missing-strdup.patch
+
+# rhbz#1588596 - many adcli-krb5-????? directories are created /tmp
+Patch49:        0001-tools-remove-errx-from-computer-commands.patch
+Patch50:        0002-tools-remove-errx-from-user-and-group-commands.patch
+Patch51:        0003-tools-remove-errx-from-info-commands.patch
+Patch52:        0004-tools-remove-errx-from-adcli_read_password_func.patch
+Patch53:        0005-tools-remove-errx-from-setup_krb5_conf_directory.patch
+Patch54:        0006-tools-entry-remove-errx-from-parse_option.patch
+Patch55:        0007-tools-computer-remove-errx-from-parse_option.patch
+
+BuildRequires:  intltool pkgconfig
+BuildRequires:  libtool
+BuildRequires:  gettext-devel
+BuildRequires:  krb5-devel
+BuildRequires:  openldap-devel
+BuildRequires:  libxslt
+BuildRequires:  xmlto
+
+Requires:       cyrus-sasl-gssapi
 
 # adcli no longer has a library of development files
 # the adcli tool itself is to be used by callers
-Obsoletes:	adcli-devel < 0.5
+Obsoletes:      adcli-devel < 0.5
 
 %description
 adcli is a library and tool for joining an Active Directory domain using
@@ -71,41 +111,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
-%patch29 -p1
-%patch30 -p1
-%patch31 -p1
-%patch32 -p1
-%patch33 -p1
-%patch34 -p1
+%autosetup -p1
 
 %build
 autoreconf --force --install --verbose
@@ -132,8 +138,27 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
 %doc %{_mandir}/*/*
 
 %changelog
-* Wed Jan 16 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-6.1
-- join failed if hostname is not FQDN [#1666775]
+* Thu May 02 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-9
+- Fixes for RHEL-7.7 updates
+- additional patch for [RFE] adcli join should preserve SPN added by adcli
+  preset-computer [#1630187]
+- new patches for many adcli-krb5-????? directories are created /tmp [#1588596]
+
+* Fri Mar 22 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-8
+- Various updates for RHEL-7.7
+- many adcli-krb5-????? directories are created /tmp [#1588596]
+- adcli exports kerberos ticket with old kvno [#1642546]
+- [RFE] Have `adcli join` work without FQDN in `hostname` output [#1595911]
+- Improve handling of service principals [#1644311]
+- [RFE] adcli command with --unix-* options doesn't update
+  values in UnixAttributes Tab for user [#1337489]
+- [RFE] adcli join should preserve SPN added by adcli preset-computer [#1630187]
+- [RFE] Need an option for adcli command which will show domain join status. [#1622583]
+
+* Wed Jan 16 2019 Sumit Bose <sbose@redhat.com> - 0.8.1-7
+- use autosetup macro to simplify patch handling
+- fixed rpmlint warnings in the spec file
+- join failed if hostname is not FQDN [#1649868]
 
 * Tue Aug 14 2018 Sumit Bose <sbose@redhat.com> - 0.8.1-6
 - Couldn't set service principals on computer account [#1608212]