diff --git a/SOURCES/0001-Add-trusted-for-delegation-option.patch b/SOURCES/0001-Add-trusted-for-delegation-option.patch
new file mode 100644
index 0000000..5e60e7c
--- /dev/null
+++ b/SOURCES/0001-Add-trusted-for-delegation-option.patch
@@ -0,0 +1,247 @@
+From 17a68288c93100e1810ad22e7fefe7357d3b2519 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 31 May 2018 18:27:37 +0200
+Subject: [PATCH 1/7] Add trusted-for-delegation option
+
+Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1538730
+---
+ doc/adcli.xml      | 14 ++++++++++
+ library/adenroll.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
+ library/adenroll.h |  4 +++
+ tools/computer.c   | 12 ++++++++
+ 4 files changed, 108 insertions(+), 2 deletions(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index c2b7760..b246190 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -283,6 +283,13 @@ Password for Administrator:
+ 			<option>--login-type=computer</option> and providing a
+ 			password as input.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--trusted-for-delegation=<parameter>yes|no|true|false</parameter></option></term>
++			<listitem><para>Set or unset the TRUSTED_FOR_DELEGATION
++			flag in the userAccountControl attribute to allow or
++			not allow that Kerberos tickets can be forwarded to the
++			host.</para></listitem>
++		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--show-details</option></term>
+ 			<listitem><para>After a successful join print out information
+@@ -402,6 +409,13 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 			in days. By default the password is updated if it is
+ 			older than 30 days.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--trusted-for-delegation=<parameter>yes|no|true|false</parameter></option></term>
++			<listitem><para>Set or unset the TRUSTED_FOR_DELEGATION
++			flag in the userAccountControl attribute to allow or
++			not allow that Kerberos tickets can be forwarded to the
++			host.</para></listitem>
++		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--show-details</option></term>
+ 			<listitem><para>After a successful join print out information
+diff --git a/library/adenroll.c b/library/adenroll.c
+index d64c2c0..7c59078 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -63,6 +63,13 @@ static krb5_enctype v51_earlier_enctypes[] = {
+ 	0
+ };
+ 
++/* Some constants for the userAccountControl AD LDAP attribute, see e.g.
++ * https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
++ * for details. */
++#define UAC_WORKSTATION_TRUST_ACCOUNT  0x1000
++#define UAC_DONT_EXPIRE_PASSWORD      0x10000
++#define UAC_TRUSTED_FOR_DELEGATION    0x80000
++
+ struct _adcli_enroll {
+ 	int refs;
+ 	adcli_conn *conn;
+@@ -105,6 +112,7 @@ struct _adcli_enroll {
+ 	unsigned int computer_password_lifetime;
+ 	int computer_password_lifetime_explicit;
+ 	char *samba_data_tool;
++	bool trusted_for_delegation;
+ };
+ 
+ static adcli_result
+@@ -538,6 +546,10 @@ create_computer_account (adcli_enroll *enroll,
+ 		NULL,
+ 	};
+ 
++	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
++		vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */
++	}
++
+ 	ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
+ 
+ 	/*
+@@ -971,6 +983,7 @@ retrieve_computer_account (adcli_enroll *enroll)
+ 		"operatingSystemVersion",
+ 		"operatingSystemServicePack",
+ 		"pwdLastSet",
++		"userAccountControl",
+ 		NULL,
+ 	};
+ 
+@@ -1149,6 +1162,47 @@ update_computer_attribute (adcli_enroll *enroll,
+ 	return res;
+ }
+ 
++static char *get_user_account_control (adcli_enroll *enroll)
++{
++	uint32_t uac = 0;
++	unsigned long attr_val;
++	char *uac_str;
++	LDAP *ldap;
++	char *end;
++
++	ldap = adcli_conn_get_ldap_connection (enroll->conn);
++	return_val_if_fail (ldap != NULL, NULL);
++
++	uac_str = _adcli_ldap_parse_value (ldap, enroll->computer_attributes, "userAccountControl");
++	if (uac_str != NULL) {
++
++		attr_val = strtoul (uac_str, &end, 10);
++		if (*end != '\0' || attr_val > UINT32_MAX) {
++			_adcli_warn ("Invalid userAccountControl '%s' for computer account in directory: %s, assuming 0",
++			            uac_str, enroll->computer_dn);
++		} else {
++			uac = attr_val;
++		}
++		free (uac_str);
++	}
++
++	if (uac == 0) {
++		uac = UAC_WORKSTATION_TRUST_ACCOUNT | UAC_DONT_EXPIRE_PASSWORD;
++	}
++
++	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
++		uac |= UAC_TRUSTED_FOR_DELEGATION;
++	} else {
++		uac &= ~(UAC_TRUSTED_FOR_DELEGATION);
++	}
++
++	if (asprintf (&uac_str, "%d", uac) < 0) {
++		return_val_if_reached (NULL);
++	}
++
++	return uac_str;
++}
++
+ static void
+ update_computer_account (adcli_enroll *enroll)
+ {
+@@ -1167,11 +1221,16 @@ update_computer_account (adcli_enroll *enroll)
+ 	}
+ 
+ 	if (res == ADCLI_SUCCESS) {
+-		char *vals_userAccountControl[] = { "69632", NULL }; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD */
++		char *vals_userAccountControl[] = { NULL , NULL };
+ 		LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
+ 		LDAPMod *mods[] = { &userAccountControl, NULL };
+ 
+-		res |= update_computer_attribute (enroll, ldap, mods);
++		vals_userAccountControl[0] = get_user_account_control (enroll);
++		if (vals_userAccountControl[0] != NULL) {
++			res |= update_computer_attribute (enroll, ldap, mods);
++		} else {
++			_adcli_warn ("Cannot update userAccountControl");
++		}
+ 	}
+ 
+ 	if (res == ADCLI_SUCCESS) {
+@@ -2375,3 +2434,20 @@ adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
+ 	return_val_if_fail (enroll != NULL, NULL);
+ 	return enroll->samba_data_tool;
+ }
++
++bool
++adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll)
++{
++	return_val_if_fail (enroll != NULL, false);
++
++	return enroll->trusted_for_delegation;
++}
++
++void
++adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
++                                         bool value)
++{
++	return_if_fail (enroll != NULL);
++
++	enroll->trusted_for_delegation = value;
++}
+diff --git a/library/adenroll.h b/library/adenroll.h
+index 31ca0bc..be2ca18 100644
+--- a/library/adenroll.h
++++ b/library/adenroll.h
+@@ -109,6 +109,10 @@ unsigned int       adcli_enroll_get_computer_password_lifetime (adcli_enroll *en
+ void               adcli_enroll_set_computer_password_lifetime (adcli_enroll *enroll,
+                                                          unsigned int lifetime);
+ 
++bool               adcli_enroll_get_trusted_for_delegation (adcli_enroll *enroll);
++void               adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
++                                                            bool value);
++
+ krb5_kvno          adcli_enroll_get_kvno                (adcli_enroll *enroll);
+ 
+ void               adcli_enroll_set_kvno                (adcli_enroll *enroll,
+diff --git a/tools/computer.c b/tools/computer.c
+index f86548b..b905fd1 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -109,6 +109,7 @@ typedef enum {
+ 	opt_computer_password_lifetime,
+ 	opt_add_samba_data,
+ 	opt_samba_data_tool,
++	opt_trusted_for_delegation,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+@@ -135,6 +136,8 @@ static adcli_tool_desc common_usages[] = {
+ 	{ opt_os_service_pack, "the computer operating system service pack", },
+ 	{ opt_user_principal, "add an authentication principal to the account", },
+ 	{ opt_computer_password_lifetime, "lifetime of the host accounts password in days", },
++	{ opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n"
++	                              "in the userAccountControl attribute", },
+ 	{ opt_no_password, "don't prompt for or read a password" },
+ 	{ opt_prompt_password, "prompt for a password if necessary" },
+ 	{ opt_stdin_password, "read a password from stdin (until EOF) if\n"
+@@ -279,6 +282,13 @@ parse_option (Option opt,
+ 			adcli_enroll_set_samba_data_tool (enroll, optarg);
+ 		}
+ 		return;
++	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;
+ 	case opt_verbose:
+ 		return;
+ 
+@@ -342,6 +352,7 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 		{ "os-version", required_argument, NULL, opt_os_version },
+ 		{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
+ 		{ "user-principal", optional_argument, NULL, opt_user_principal },
++		{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
+ 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+@@ -446,6 +457,7 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 		{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
+ 		{ "user-principal", optional_argument, NULL, opt_user_principal },
+ 		{ "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime },
++		{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
+ 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+-- 
+2.14.4
+
diff --git a/SOURCES/0001-Fix-memory-leak-in-test_check_nt_time_string_lifetim.patch b/SOURCES/0001-Fix-memory-leak-in-test_check_nt_time_string_lifetim.patch
new file mode 100644
index 0000000..178c54f
--- /dev/null
+++ b/SOURCES/0001-Fix-memory-leak-in-test_check_nt_time_string_lifetim.patch
@@ -0,0 +1,28 @@
+From e2ae8bc7454a52e2b929f9b09ad9be21e377342b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 14:39:46 +0100
+Subject: [PATCH 1/9] Fix memory leak in test_check_nt_time_string_lifetime
+
+The test added with 650e5d33ef31437a049fb454ad3dc5457c56abe7 introduced
+a small memory leak.
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ library/adutil.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/library/adutil.c b/library/adutil.c
+index 21ccd27..cd40f45 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -501,6 +501,7 @@ test_check_nt_time_string_lifetime (void)
+ 			  (time (NULL) + 10 + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 *10)
+ 		!= -1);
+ 	assert (!_adcli_check_nt_time_string_lifetime (time_str, 0));
++	free (time_str);
+ 
+ 	/* This test will fail some time after 2200AD as a reminder to reflect
+ 	 * why adcli is still needed. */
+-- 
+2.14.4
+
diff --git a/SOURCES/0001-adcli_conn_is_writeable-do-not-crash-id-domain_disco.patch b/SOURCES/0001-adcli_conn_is_writeable-do-not-crash-id-domain_disco.patch
new file mode 100644
index 0000000..20518ba
--- /dev/null
+++ b/SOURCES/0001-adcli_conn_is_writeable-do-not-crash-id-domain_disco.patch
@@ -0,0 +1,32 @@
+From 05eae8a57a556412aa18d37660ebfabb74ab2890 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 31 May 2018 17:01:36 +0200
+Subject: [PATCH] adcli_conn_is_writeable: do not crash id domain_disco is
+ missing
+
+Resolves https://bugzilla.redhat.com/show_bug.cgi?id=1575554
+---
+ library/adconn.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/library/adconn.c b/library/adconn.c
+index d2fb1d5..e2250e3 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -1567,6 +1567,11 @@ adcli_conn_server_has_capability (adcli_conn *conn,
+ 
+ bool adcli_conn_is_writeable (adcli_conn *conn)
+ {
+-    disco_dance_if_necessary (conn);
+-    return ( (conn->domain_disco->flags & ADCLI_DISCO_WRITABLE) != 0);
++	disco_dance_if_necessary (conn);
++
++	if (conn->domain_disco == NULL) {
++		return false;
++	}
++
++	return ( (conn->domain_disco->flags & ADCLI_DISCO_WRITABLE) != 0);
+ }
+-- 
+2.14.4
+
diff --git a/SOURCES/0001-fix-typo-in-flag-value.patch b/SOURCES/0001-fix-typo-in-flag-value.patch
new file mode 100644
index 0000000..07577b7
--- /dev/null
+++ b/SOURCES/0001-fix-typo-in-flag-value.patch
@@ -0,0 +1,25 @@
+From 870ecd8f982ebb97092a93d730ad4006bd78505c Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 8 Aug 2018 12:03:01 +0200
+Subject: [PATCH 1/4] fix typo in flag value
+
+---
+ library/adenroll.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/library/adenroll.h b/library/adenroll.h
+index f87dffa..abbbfd4 100644
+--- a/library/adenroll.h
++++ b/library/adenroll.h
+@@ -30,7 +30,7 @@ typedef enum {
+ 	ADCLI_ENROLL_NO_KEYTAB = 1 << 1,
+ 	ADCLI_ENROLL_ALLOW_OVERWRITE = 1 << 2,
+ 	ADCLI_ENROLL_PASSWORD_VALID = 1 << 3,
+-	ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 3,
++	ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 4,
+ } adcli_enroll_flags;
+ 
+ typedef struct _adcli_enroll adcli_enroll;
+-- 
+2.17.1
+
diff --git a/SOURCES/0002-Only-update-attributes-given-on-the-command-line.patch b/SOURCES/0002-Only-update-attributes-given-on-the-command-line.patch
new file mode 100644
index 0000000..d69ff8a
--- /dev/null
+++ b/SOURCES/0002-Only-update-attributes-given-on-the-command-line.patch
@@ -0,0 +1,126 @@
+From 5eca1f995ced1ce4ddead4471ac7ac9037bedb73 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Fri, 1 Jun 2018 21:26:47 +0200
+Subject: [PATCH 2/7] Only update attributes given on the command line
+
+When updating attributes of the LDAP computer object we only want to
+update attributes which are related to options given on the command
+line. Otherwise a simple call of 'adcli update' to check if the machine
+account password needs an update might unexpectedly reset other
+attributes as well.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547013
+           https://bugzilla.redhat.com/show_bug.cgi?id=1545568
+           https://bugzilla.redhat.com/show_bug.cgi?id=1538730
+---
+ library/adenroll.c | 35 ++++++++++++++++++++++++++++++-----
+ 1 file changed, 30 insertions(+), 5 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 7c59078..2be6796 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -99,8 +99,11 @@ struct _adcli_enroll {
+ 	int user_princpal_generate;
+ 
+ 	char *os_name;
++	int os_name_explicit;
+ 	char *os_version;
++	int os_version_explicit;
+ 	char *os_service_pack;
++	int os_service_pack_explicit;
+ 
+ 	krb5_kvno kvno;
+ 	char *keytab_name;
+@@ -113,6 +116,7 @@ struct _adcli_enroll {
+ 	int computer_password_lifetime_explicit;
+ 	char *samba_data_tool;
+ 	bool trusted_for_delegation;
++	int trusted_for_delegation_explicit;
+ };
+ 
+ static adcli_result
+@@ -1212,7 +1216,11 @@ update_computer_account (adcli_enroll *enroll)
+ 	ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ 	return_if_fail (ldap != NULL);
+ 
+-	{
++	/* Only update attributes which are explicitly given on the command
++	 * line. Otherwise 'adcli update' must be always called with the same
++	 * set of options to make sure existing attributes are not deleted or
++	 * overwritten with different values. */
++	if (enroll->host_fqdn_explicit) {
+ 		char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
+ 		LDAPMod dNSHostName = { LDAP_MOD_REPLACE, "dNSHostName", { vals_dNSHostName, } };
+ 		LDAPMod *mods[] = { &dNSHostName, NULL };
+@@ -1220,7 +1228,7 @@ update_computer_account (adcli_enroll *enroll)
+ 		res |= update_computer_attribute (enroll, ldap, mods);
+ 	}
+ 
+-	if (res == ADCLI_SUCCESS) {
++	if (res == ADCLI_SUCCESS && enroll->trusted_for_delegation_explicit) {
+ 		char *vals_userAccountControl[] = { NULL , NULL };
+ 		LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
+ 		LDAPMod *mods[] = { &userAccountControl, NULL };
+@@ -1240,12 +1248,25 @@ update_computer_account (adcli_enroll *enroll)
+ 		LDAPMod operatingSystemVersion = { LDAP_MOD_REPLACE, "operatingSystemVersion", { vals_operatingSystemVersion, } };
+ 		char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
+ 		LDAPMod operatingSystemServicePack = { LDAP_MOD_REPLACE, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
+-		LDAPMod *mods[] = { &operatingSystem, &operatingSystemVersion, &operatingSystemServicePack, NULL };
++		LDAPMod *mods[] = { NULL, NULL, NULL, NULL };
++		size_t c = 0;
+ 
+-		res |= update_computer_attribute (enroll, ldap, mods);
++		if (enroll->os_name_explicit) {
++			mods[c++] = &operatingSystem;
++		}
++		if (enroll->os_version_explicit) {
++			mods[c++] = &operatingSystemVersion;
++		}
++		if (enroll->os_service_pack_explicit) {
++			mods[c++] = &operatingSystemServicePack;
++		}
++
++		if (c != 0) {
++			res |= update_computer_attribute (enroll, ldap, mods);
++		}
+ 	}
+ 
+-	if (res == ADCLI_SUCCESS) {
++	if (res == ADCLI_SUCCESS && !enroll->user_princpal_generate) {
+ 		char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
+ 		LDAPMod userPrincipalName = { LDAP_MOD_REPLACE, "userPrincipalName", { vals_userPrincipalName, }, };
+ 		LDAPMod *mods[] = { &userPrincipalName, NULL, };
+@@ -2337,6 +2358,7 @@ adcli_enroll_set_os_name (adcli_enroll *enroll,
+ 	if (value && value[0] == '\0')
+ 		value = NULL;
+ 	_adcli_str_set (&enroll->os_name, value);
++	enroll->os_name_explicit = 1;
+ }
+ 
+ const char *
+@@ -2354,6 +2376,7 @@ adcli_enroll_set_os_version (adcli_enroll *enroll,
+ 	if (value && value[0] == '\0')
+ 		value = NULL;
+ 	_adcli_str_set (&enroll->os_version, value);
++	enroll->os_version_explicit = 1;
+ }
+ 
+ const char *
+@@ -2371,6 +2394,7 @@ adcli_enroll_set_os_service_pack (adcli_enroll *enroll,
+ 	if (value && value[0] == '\0')
+ 		value = NULL;
+ 	_adcli_str_set (&enroll->os_service_pack, value);
++	enroll->os_service_pack_explicit = 1;
+ }
+ 
+ const char *
+@@ -2450,4 +2474,5 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
+ 	return_if_fail (enroll != NULL);
+ 
+ 	enroll->trusted_for_delegation = value;
++	enroll->trusted_for_delegation_explicit = 1;
+ }
+-- 
+2.14.4
+
diff --git a/SOURCES/0002-_adcli_call_external_program-silence-noisy-debug-mes.patch b/SOURCES/0002-_adcli_call_external_program-silence-noisy-debug-mes.patch
new file mode 100644
index 0000000..76fe1dc
--- /dev/null
+++ b/SOURCES/0002-_adcli_call_external_program-silence-noisy-debug-mes.patch
@@ -0,0 +1,25 @@
+From 8cc4ef1cae7d4d753f2cf9aeb8021dd96cb75d36 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 8 Aug 2018 12:17:18 +0200
+Subject: [PATCH 2/4] _adcli_call_external_program: silence noisy debug message
+
+---
+ library/adutil.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/library/adutil.c b/library/adutil.c
+index 6334b52..17d2caa 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -672,7 +672,7 @@ done:
+ 		if (wret == -1) {
+ 			_adcli_err ("No sure what happend to net command.");
+ 		} else {
+-			if (WIFEXITED (status)) {
++			if (WIFEXITED (status) && WEXITSTATUS (status) != 0) {
+ 				_adcli_err ("net command failed with %d.",
+ 				            WEXITSTATUS (status));
+ 			}
+-- 
+2.17.1
+
diff --git a/SOURCES/0002-library-add-_adcli_bin_sid_to_str.patch b/SOURCES/0002-library-add-_adcli_bin_sid_to_str.patch
new file mode 100644
index 0000000..4fad98c
--- /dev/null
+++ b/SOURCES/0002-library-add-_adcli_bin_sid_to_str.patch
@@ -0,0 +1,178 @@
+From 0d0c1bf9721ba523d8c3ac584bdbb9a8ffdddee7 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 14:37:05 +0100
+Subject: [PATCH 2/9] library: add _adcli_bin_sid_to_str()
+
+Convert a binary SID to the string representation.
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ library/adprivate.h |   4 ++
+ library/adutil.c    | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 117 insertions(+)
+
+diff --git a/library/adprivate.h b/library/adprivate.h
+index fc146af..e99f9fc 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -31,6 +31,7 @@
+ #include <limits.h>
+ #include <stdlib.h>
+ #include <stdio.h>
++#include <stdint.h>
+ 
+ #include <ldap.h>
+ 
+@@ -132,6 +133,9 @@ int            _adcli_str_has_prefix         (const char *str,
+ int            _adcli_str_has_suffix         (const char *str,
+ 		                              const char *suffix);
+ 
++char *          _adcli_bin_sid_to_str        (const uint8_t *data,
++                                              size_t len);
++
+ char *         _adcli_str_dupn               (void *data,
+                                               size_t len);
+ 
+diff --git a/library/adutil.c b/library/adutil.c
+index cd40f45..829cdd9 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -293,6 +293,83 @@ _adcli_strv_set (char ***field,
+ 	*field = newval;
+ }
+ 
++char *
++_adcli_bin_sid_to_str (const uint8_t *data,
++                       size_t len)
++{
++	uint8_t sid_rev_num;
++	int8_t num_auths;
++	uint8_t id_auth[6];
++	uint32_t id_auth_val;
++	uint32_t sub_auths[15];
++	uint32_t val;
++	size_t p = 0;
++	size_t c;
++	int nc;
++	char *sid_buf;
++	size_t sid_buf_len;
++
++	if (data == NULL || len < 8) {
++		return NULL;
++	}
++
++	sid_rev_num = (uint8_t) data [p];
++	p++;
++
++	num_auths = (int8_t) data[p];
++	p++;
++
++	if (num_auths > 15 || len < 8 + (num_auths * sizeof (uint32_t))) {
++		return NULL;
++	}
++
++	for (c = 0; c < 6; c++) {
++		id_auth[c] = (uint8_t) data[p];
++		p++;
++	}
++
++	/* Only 32bits are used for the string representation */
++	id_auth_val = (id_auth[2] << 24) +
++	              (id_auth[3] << 16) +
++	              (id_auth[4] << 8) +
++	              (id_auth[5]);
++
++	for (c = 0; c < num_auths; c++) {
++		memcpy (&val, data + p, sizeof (uint32_t));
++		sub_auths[c] = le32toh (val);
++
++		p += sizeof (uint32_t);
++	}
++
++	sid_buf_len = 17 + (num_auths * 11);
++	sid_buf = calloc (1, sid_buf_len);
++	if (sid_buf == NULL) {
++		return NULL;
++	}
++
++	nc = snprintf (sid_buf, sid_buf_len, "S-%u-%lu", sid_rev_num,
++	              (unsigned long) id_auth_val);
++	if (nc < 0 || nc >= sid_buf_len) {
++		free (sid_buf);
++		return NULL;
++	}
++
++	p = 0;
++	for (c = 0; c < num_auths; c++) {
++		p += nc;
++		sid_buf_len -= nc;
++
++		nc = snprintf (sid_buf + p, sid_buf_len, "-%lu",
++		               (unsigned long) sub_auths[c]);
++		if (nc < 0 || nc >= sid_buf_len) {
++			free (sid_buf);
++			return NULL;
++		}
++	}
++
++	return sid_buf;
++}
++
+ char *
+ _adcli_str_dupn (void *data,
+                  size_t len)
+@@ -508,6 +585,41 @@ test_check_nt_time_string_lifetime (void)
+ 	assert (_adcli_check_nt_time_string_lifetime ("130645404000000000", 100000));
+ }
+ 
++static void
++test_bin_sid_to_str (void)
++{
++	uint8_t sid1[] = { 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
++	                   0x15, 0x00, 0x00, 0x00, 0xF8, 0x12, 0x13, 0xDC,
++	                   0x47, 0xF3, 0x1C, 0x76, 0x47, 0x2F, 0x2E, 0xD7,
++	                   0x51, 0x04, 0x00, 0x00 };
++
++	uint8_t sid2[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
++	                   0x15, 0x00, 0x00, 0x00, 0xF8, 0x12, 0x13, 0xDC,
++	                   0x47, 0xF3, 0x1C, 0x76, 0x47, 0x2F, 0x2E, 0xD7};
++
++	uint8_t sid3[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
++	                   0x15, 0x00, 0x00, 0x00, 0x29, 0xC9, 0x4F, 0xD9,
++	                   0xC2, 0x3C, 0xC3, 0x78, 0x36, 0x55, 0x87, 0xF8};
++
++
++	char *str;
++
++	str = _adcli_bin_sid_to_str (sid1, sizeof (sid1));
++	assert (str != NULL);
++	assert (strcmp (str, "S-1-5-21-3692237560-1981608775-3610128199-1105") == 0);
++	free (str);
++
++	str = _adcli_bin_sid_to_str (sid2, sizeof (sid2));
++	assert (str != NULL);
++	assert (strcmp (str, "S-1-5-21-3692237560-1981608775-3610128199") == 0);
++	free (str);
++
++	str = _adcli_bin_sid_to_str (sid3, sizeof (sid2));
++	assert (str != NULL);
++	assert (strcmp (str, "S-1-5-21-3645884713-2026060994-4169618742") == 0);
++	free (str);
++}
++
+ int
+ main (int argc,
+       char *argv[])
+@@ -516,6 +628,7 @@ main (int argc,
+ 	test_func (test_strv_dup, "/util/strv_dup");
+ 	test_func (test_strv_count, "/util/strv_count");
+ 	test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
++	test_func (test_bin_sid_to_str, "/util/bin_sid_to_str");
+ 	return test_run (argc, argv);
+ }
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0003-Do-not-add-service-principals-twice.patch b/SOURCES/0003-Do-not-add-service-principals-twice.patch
new file mode 100644
index 0000000..5d0bfcf
--- /dev/null
+++ b/SOURCES/0003-Do-not-add-service-principals-twice.patch
@@ -0,0 +1,57 @@
+From f05adc23d5cc9f1dfa5638e31949dcd81d632df9 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 13 Aug 2018 17:32:24 +0200
+Subject: [PATCH 3/4] Do not add service principals twice
+
+---
+ library/adenroll.c | 23 +++++++++++++++++++----
+ 1 file changed, 19 insertions(+), 4 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index c4ba537..bb50365 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -313,6 +313,7 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
+ 	char *name;
+ 	int length = 0;
+ 	int i;
++	size_t c;
+ 
+ 	if (enroll->service_principals != NULL) {
+ 		length = seq_count (enroll->service_principals);
+@@ -321,14 +322,28 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
+ 	for (i = 0; enroll->service_names[i] != NULL; i++) {
+ 		if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
+ 			return_unexpected_if_reached ();
+-		enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-			                                      name, &length);
++		for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
++			if (strcmp (name, enroll->service_principals[c]) == 0) {
++				break;
++			}
++		}
++		if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
++			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
++				                                      name, &length);
++		}
+ 
+ 		if (enroll->host_fqdn) {
+ 			if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
+ 				return_unexpected_if_reached ();
+-			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-				                                      name, &length);
++			for (c = 0; enroll->service_principals != NULL && enroll->service_principals[c] != NULL; c++) {
++				if (strcmp (name, enroll->service_principals[c]) == 0) {
++					break;
++				}
++			}
++			if (enroll->service_principals == NULL || enroll->service_principals[c] == NULL) {
++				enroll->service_principals = _adcli_strv_add (enroll->service_principals,
++					                                      name, &length);
++			}
+ 		}
+ 	}
+ 
+-- 
+2.17.1
+
diff --git a/SOURCES/0003-library-add-_adcli_call_external_program.patch b/SOURCES/0003-library-add-_adcli_call_external_program.patch
new file mode 100644
index 0000000..9553e0d
--- /dev/null
+++ b/SOURCES/0003-library-add-_adcli_call_external_program.patch
@@ -0,0 +1,317 @@
+From 8abf673c508db9d8bbdaaa5bbee50dedd3a95faf Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 14:39:17 +0100
+Subject: [PATCH 3/9] library: add _adcli_call_external_program()
+
+Allow adcli to call an external program given by an absolute path name
+and an array of options. stdin and stdout can be used if needed.
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ configure.ac        |  28 +++++++
+ library/adprivate.h |   6 ++
+ library/adutil.c    | 211 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 245 insertions(+)
+
+diff --git a/configure.ac b/configure.ac
+index 221d8ae..fe86638 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -263,6 +263,34 @@ AC_SUBST(LCOV)
+ AC_SUBST(GCOV)
+ AC_SUBST(GENHTML)
+ 
++AC_PATH_PROG(BIN_CAT, cat, no)
++if test "$BIN_CAT" = "no" ; then
++	AC_MSG_ERROR([cat is not available])
++else
++	AC_DEFINE_UNQUOTED(BIN_CAT, "$BIN_CAT", [path to cat, used in unit test])
++fi
++
++AC_PATH_PROG(BIN_TAC, tac, no)
++if test "$BIN_TAC" = "no" ; then
++	AC_MSG_ERROR([tac is not available])
++else
++	AC_DEFINE_UNQUOTED(BIN_TAC, "$BIN_TAC", [path to tac, used in unit test])
++fi
++
++AC_PATH_PROG(BIN_REV, rev, no)
++if test "$BIN_REV" = "no" ; then
++	AC_MSG_ERROR([rev is not available])
++else
++	AC_DEFINE_UNQUOTED(BIN_REV, "$BIN_REV", [path to rev, used in unit test])
++fi
++
++AC_PATH_PROG(BIN_ECHO, echo, no)
++if test "$BIN_ECHO" = "no" ; then
++	AC_MSG_ERROR([echo is not available])
++else
++	AC_DEFINE_UNQUOTED(BIN_ECHO, "$BIN_ECHO", [path to echo, used in unit test])
++fi
++
+ # ---------------------------------------------------------------------
+ 
+ ADCLI_LT_RELEASE=$ADCLI_CURRENT:$ADCLI_REVISION:$ADCLI_AGE
+diff --git a/library/adprivate.h b/library/adprivate.h
+index e99f9fc..7257c93 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -285,4 +285,10 @@ struct _adcli_attrs {
+ 
+ bool             _adcli_check_nt_time_string_lifetime (const char *nt_time_string, unsigned int lifetime);
+ 
++adcli_result     _adcli_call_external_program     (const char *binary,
++                                                   char * const *argv,
++                                                   const char *stdin_data,
++                                                   uint8_t **stdout_data,
++                                                   size_t *stdout_data_len);
++
+ #endif /* ADPRIVATE_H_ */
+diff --git a/library/adutil.c b/library/adutil.c
+index 829cdd9..a27bd68 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -36,6 +36,7 @@
+ #include <unistd.h>
+ #include <stdint.h>
+ #include <time.h>
++#include <sys/wait.h>
+ 
+ static adcli_message_func message_func = NULL;
+ static char last_error[2048] = { 0, };
+@@ -506,6 +507,161 @@ _adcli_check_nt_time_string_lifetime (const char *nt_time_string,
+ 	return false;
+ }
+ 
++adcli_result
++_adcli_call_external_program (const char *binary, char * const *argv,
++                              const char *stdin_data,
++                              uint8_t **stdout_data, size_t *stdout_data_len)
++{
++	int ret;
++	int pipefd_to_child[2] = { -1, -1};
++	int pipefd_from_child[2] = { -1, -1};
++	pid_t child_pid = 0;
++	int err;
++	size_t len;
++	ssize_t rlen;
++	pid_t wret;
++	int status;
++	uint8_t read_buf[4096];
++	uint8_t *out;
++
++	errno = 0;
++	ret = access (binary, X_OK);
++	if (ret != 0) {
++		err = errno;
++		_adcli_err ("Cannot run [%s]: [%d][%s].", binary, err,
++		                                          strerror (err));
++		ret = ADCLI_ERR_FAIL;
++		goto done;
++	}
++
++	ret = pipe (pipefd_from_child);
++	if (ret == -1) {
++		err = errno;
++		_adcli_err ("pipe failed [%d][%s].", err, strerror (err));
++		ret = ADCLI_ERR_FAIL;
++		goto done;
++	}
++
++	ret = pipe (pipefd_to_child);
++	if (ret == -1) {
++		err = errno;
++		_adcli_err ("pipe failed [%d][%s].", err, strerror (err));
++		ret = ADCLI_ERR_FAIL;
++		goto done;
++	}
++
++	child_pid = fork ();
++
++	if (child_pid == 0) { /* child */
++		close (pipefd_to_child[1]);
++		ret = dup2 (pipefd_to_child[0], STDIN_FILENO);
++		if (ret == -1) {
++			err = errno;
++			_adcli_err ("dup2 failed [%d][%s].", err,
++			                                     strerror (err));
++			exit (EXIT_FAILURE);
++		}
++
++		close (pipefd_from_child[0]);
++		ret = dup2 (pipefd_from_child[1], STDOUT_FILENO);
++		if (ret == -1) {
++			err = errno;
++			_adcli_err ("dup2 failed [%d][%s].", err,
++			                                     strerror (err));
++			exit (EXIT_FAILURE);
++		}
++
++		execv (binary, argv);
++		_adcli_err ("Failed to run %s.", binary);
++		ret = ADCLI_ERR_FAIL;
++		goto done;
++	} else if (child_pid > 0) { /* parent */
++
++		if (stdin_data != NULL) {
++			len = strlen (stdin_data);
++			ret = write (pipefd_to_child[1], stdin_data, len);
++			if (ret != len) {
++				_adcli_err ("Failed to send computer account password "
++				            "to net command.");
++				ret = ADCLI_ERR_FAIL;
++				goto done;
++			}
++		}
++
++		close (pipefd_to_child[0]);
++		pipefd_to_child[0] = -1;
++		close (pipefd_to_child[1]);
++		pipefd_to_child[0] = -1;
++
++		if (stdout_data != NULL || stdout_data_len != NULL) {
++			rlen = read (pipefd_from_child[0], read_buf, sizeof (read_buf));
++			if (rlen < 0) {
++				ret = errno;
++				_adcli_err ("Failed to read from child [%d][%s].\n",
++				            ret, strerror (ret));
++				ret = ADCLI_ERR_FAIL;
++				goto done;
++			}
++
++			out = malloc (sizeof(uint8_t) * rlen);
++			if (out == NULL) {
++				_adcli_err ("Failed to allocate memory "
++				            "for child output.");
++				ret = ADCLI_ERR_FAIL;
++				goto done;
++			} else {
++				memcpy (out, read_buf, rlen);
++			}
++
++			if (stdout_data != NULL) {
++				*stdout_data = out;
++			} else {
++				free (out);
++			}
++
++			if (stdout_data_len != NULL) {
++				*stdout_data_len = rlen;
++			}
++		}
++
++	} else {
++		_adcli_err ("Cannot run net command.");
++		ret = ADCLI_ERR_FAIL;
++		goto done;
++	}
++
++	ret = ADCLI_SUCCESS;
++
++done:
++	if (pipefd_from_child[0] != -1) {
++		close (pipefd_from_child[0]);
++	}
++	if (pipefd_from_child[1] != -1) {
++		close (pipefd_from_child[1]);
++	}
++	if (pipefd_to_child[0] != -1) {
++		close (pipefd_to_child[0]);
++	}
++	if (pipefd_to_child[1] != -1) {
++		close (pipefd_to_child[1]);
++	}
++
++	if (child_pid > 0) {
++		wret = waitpid (child_pid, &status, 0);
++		if (wret == -1) {
++			_adcli_err ("No sure what happend to net command.");
++		} else {
++			if (WIFEXITED (status)) {
++				_adcli_err ("net command failed with %d.",
++				            WEXITSTATUS (status));
++			}
++		}
++	}
++
++	return ret;
++}
++
++
+ #ifdef UTIL_TESTS
+ 
+ #include "test.h"
+@@ -620,6 +776,60 @@ test_bin_sid_to_str (void)
+ 	free (str);
+ }
+ 
++static void
++test_call_external_program (void)
++{
++	adcli_result res;
++	char *argv[] = { NULL, NULL, NULL };
++	uint8_t *stdout_data;
++	size_t stdout_data_len;
++
++	argv[0] = "/does/not/exists";
++	res = _adcli_call_external_program (argv[0], argv, NULL, NULL, NULL);
++	assert (res == ADCLI_ERR_FAIL);
++
++#ifdef BIN_CAT
++	argv[0] = BIN_CAT;
++	res = _adcli_call_external_program (argv[0], argv, "Hello",
++	                                    &stdout_data, &stdout_data_len);
++	assert (res == ADCLI_SUCCESS);
++	assert (strncmp ("Hello", (char *) stdout_data, stdout_data_len) == 0);
++	free (stdout_data);
++
++	res = _adcli_call_external_program (argv[0], argv, "Hello",
++	                                    NULL, NULL);
++	assert (res == ADCLI_SUCCESS);
++#endif
++
++#ifdef BIN_REV
++	argv[0] = BIN_REV;
++	res = _adcli_call_external_program (argv[0], argv, "Hello\n",
++	                                    &stdout_data, &stdout_data_len);
++	assert (res == ADCLI_SUCCESS);
++	assert (strncmp ("olleH\n", (char *) stdout_data, stdout_data_len) == 0);
++	free (stdout_data);
++#endif
++
++#ifdef BIN_TAC
++	argv[0] = BIN_TAC;
++	res = _adcli_call_external_program (argv[0], argv, "Hello\nWorld\n",
++	                                    &stdout_data, &stdout_data_len);
++	assert (res == ADCLI_SUCCESS);
++	assert (strncmp ("World\nHello\n", (char *) stdout_data, stdout_data_len) == 0);
++	free (stdout_data);
++#endif
++
++#ifdef BIN_ECHO
++	argv[0] = BIN_ECHO;
++	argv[1] = "Hello";
++	res = _adcli_call_external_program (argv[0], argv, NULL,
++	                                    &stdout_data, &stdout_data_len);
++	assert (res == ADCLI_SUCCESS);
++	assert (strncmp ("Hello\n", (char *) stdout_data, stdout_data_len) == 0);
++	free (stdout_data);
++#endif
++}
++
+ int
+ main (int argc,
+       char *argv[])
+@@ -629,6 +839,7 @@ main (int argc,
+ 	test_func (test_strv_count, "/util/strv_count");
+ 	test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
+ 	test_func (test_bin_sid_to_str, "/util/bin_sid_to_str");
++	test_func (test_call_external_program, "/util/call_external_program");
+ 	return test_run (argc, argv);
+ }
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0003-update-allow-to-add-service-names.patch b/SOURCES/0003-update-allow-to-add-service-names.patch
new file mode 100644
index 0000000..9eb1d68
--- /dev/null
+++ b/SOURCES/0003-update-allow-to-add-service-names.patch
@@ -0,0 +1,387 @@
+From c53a51a61d7ac20900836b1bb005bf272c08a849 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 4 Jun 2018 10:49:33 +0200
+Subject: [PATCH 3/7] update: allow to add service names
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547013
+           https://bugzilla.redhat.com/show_bug.cgi?id=1545568
+---
+ library/adenroll.c  | 136 +++++++++++++++++++++++++++++++++-------------------
+ library/adkrb5.c    | 113 +++++++++++++++++++++++++++++++++++++++++++
+ library/adprivate.h |   6 +++
+ 3 files changed, 206 insertions(+), 49 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 2be6796..1221e89 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -305,13 +305,37 @@ ensure_service_names (adcli_result res,
+ }
+ 
+ static adcli_result
+-ensure_service_principals (adcli_result res,
+-                           adcli_enroll *enroll)
++add_service_names_to_service_principals (adcli_enroll *enroll)
+ {
+ 	char *name;
+ 	int length = 0;
+ 	int i;
+ 
++	if (enroll->service_principals != NULL) {
++		length = seq_count (enroll->service_principals);
++	}
++
++	for (i = 0; enroll->service_names[i] != NULL; i++) {
++		if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
++			return_unexpected_if_reached ();
++		enroll->service_principals = _adcli_strv_add (enroll->service_principals,
++			                                      name, &length);
++
++		if (enroll->host_fqdn) {
++			if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
++				return_unexpected_if_reached ();
++			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
++				                                      name, &length);
++		}
++	}
++
++	return ADCLI_SUCCESS;
++}
++
++static adcli_result
++ensure_service_principals (adcli_result res,
++                           adcli_enroll *enroll)
++{
+ 	if (res != ADCLI_SUCCESS)
+ 		return res;
+ 
+@@ -319,20 +343,7 @@ ensure_service_principals (adcli_result res,
+ 
+ 	if (!enroll->service_principals) {
+ 		assert (enroll->service_names != NULL);
+-
+-		for (i = 0; enroll->service_names[i] != NULL; i++) {
+-			if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->computer_name) < 0)
+-				return_unexpected_if_reached ();
+-			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-			                                              name, &length);
+-
+-			if (enroll->host_fqdn) {
+-				if (asprintf (&name, "%s/%s", enroll->service_names[i], enroll->host_fqdn) < 0)
+-					return_unexpected_if_reached ();
+-				enroll->service_principals = _adcli_strv_add (enroll->service_principals,
+-				                                              name, &length);
+-			}
+-		}
++		return add_service_names_to_service_principals (enroll);
+ 	}
+ 
+ 	return ADCLI_SUCCESS;
+@@ -356,6 +367,7 @@ ensure_keytab_principals (adcli_result res,
+ 	return_unexpected_if_fail (k5 != NULL);
+ 
+ 	enroll->keytab_principals = calloc (count + 3, sizeof (krb5_principal));
++	return_unexpected_if_fail (enroll->keytab_principals != NULL);
+ 	at = 0;
+ 
+ 	/* First add the principal for the computer account name */
+@@ -1266,7 +1278,7 @@ update_computer_account (adcli_enroll *enroll)
+ 		}
+ 	}
+ 
+-	if (res == ADCLI_SUCCESS && !enroll->user_princpal_generate) {
++	if (res == ADCLI_SUCCESS && enroll->user_principal != NULL && !enroll->user_princpal_generate) {
+ 		char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
+ 		LDAPMod userPrincipalName = { LDAP_MOD_REPLACE, "userPrincipalName", { vals_userPrincipalName, }, };
+ 		LDAPMod *mods[] = { &userPrincipalName, NULL, };
+@@ -1519,7 +1531,8 @@ add_principal_to_keytab (adcli_enroll *enroll,
+                          krb5_context k5,
+                          krb5_principal principal,
+                          const char *principal_name,
+-                         int *which_salt)
++                         int *which_salt,
++                         adcli_enroll_flags flags)
+ {
+ 	match_principal_kvno closure;
+ 	krb5_data password;
+@@ -1547,41 +1560,47 @@ add_principal_to_keytab (adcli_enroll *enroll,
+ 		             enroll->keytab_name);
+ 	}
+ 
+-	password.data = enroll->computer_password;
+-	password.length = strlen (enroll->computer_password);
+-
+ 	enctypes = adcli_enroll_get_keytab_enctypes (enroll);
+ 
+-	/*
+-	 * So we need to discover which salt to use. As a side effect we are
+-	 * also testing that our account works.
+-	 */
++	if (flags & ADCLI_ENROLL_PASSWORD_VALID) {
++		code = _adcli_krb5_keytab_copy_entries (k5, enroll->keytab, principal,
++		                                        enroll->kvno, enctypes);
++	} else {
+ 
+-	salts = build_principal_salts (enroll, k5, principal);
+-	return_unexpected_if_fail (salts != NULL);
++		password.data = enroll->computer_password;
++		password.length = strlen (enroll->computer_password);
+ 
+-	if (*which_salt < 0) {
+-		code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
+-		                                         enctypes, salts, which_salt);
+-		if (code != 0) {
+-			_adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
+-			             principal_name, krb5_get_error_message (k5, code));
+-			*which_salt = DEFAULT_SALT;
+-		} else {
+-			assert (*which_salt >= 0);
+-			_adcli_info ("Discovered which keytab salt to use");
++		/*
++		 * So we need to discover which salt to use. As a side effect we are
++		 * also testing that our account works.
++		 */
++
++		salts = build_principal_salts (enroll, k5, principal);
++		return_unexpected_if_fail (salts != NULL);
++
++		if (*which_salt < 0) {
++			code = _adcli_krb5_keytab_discover_salt (k5, principal, enroll->kvno, &password,
++			                                         enctypes, salts, which_salt);
++			if (code != 0) {
++				_adcli_warn ("Couldn't authenticate with keytab while discovering which salt to use: %s: %s",
++				             principal_name, krb5_get_error_message (k5, code));
++				*which_salt = DEFAULT_SALT;
++			} else {
++				assert (*which_salt >= 0);
++				_adcli_info ("Discovered which keytab salt to use");
++			}
+ 		}
+-	}
+ 
+-	code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
+-	                                       enroll->kvno, &password, enctypes, &salts[*which_salt]);
++		code = _adcli_krb5_keytab_add_entries (k5, enroll->keytab, principal,
++		                                       enroll->kvno, &password, enctypes, &salts[*which_salt]);
+ 
+-	free_principal_salts (k5, salts);
++		free_principal_salts (k5, salts);
+ 
+-	if (code != 0) {
+-		_adcli_err ("Couldn't add keytab entries: %s: %s",
+-		            enroll->keytab_name, krb5_get_error_message (k5, code));
+-		return ADCLI_ERR_FAIL;
++		if (code != 0) {
++			_adcli_err ("Couldn't add keytab entries: %s: %s",
++			            enroll->keytab_name, krb5_get_error_message (k5, code));
++			return ADCLI_ERR_FAIL;
++		}
+ 	}
+ 
+ 
+@@ -1591,7 +1610,8 @@ add_principal_to_keytab (adcli_enroll *enroll,
+ }
+ 
+ static adcli_result
+-update_keytab_for_principals (adcli_enroll *enroll)
++update_keytab_for_principals (adcli_enroll *enroll,
++                              adcli_enroll_flags flags)
+ {
+ 	krb5_context k5;
+ 	adcli_result res;
+@@ -1608,7 +1628,7 @@ update_keytab_for_principals (adcli_enroll *enroll)
+ 		if (krb5_unparse_name (k5, enroll->keytab_principals[i], &name) != 0)
+ 			name = "";
+ 		res = add_principal_to_keytab (enroll, k5, enroll->keytab_principals[i],
+-		                               name, &which_salt);
++		                               name, &which_salt, flags);
+ 		krb5_free_unparsed_name (k5, name);
+ 
+ 		if (res != ADCLI_SUCCESS)
+@@ -1807,6 +1827,20 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
+ 	/* We ignore failures of setting these fields */
+ 	update_and_calculate_enctypes (enroll);
+ 	update_computer_account (enroll);
++
++	/* 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) {
++		res = add_service_names_to_service_principals (enroll);
++		if (res != ADCLI_SUCCESS) {
++			return res;
++		}
++		res = ensure_keytab_principals (res, enroll);
++		if (res != ADCLI_SUCCESS) {
++			return res;
++		}
++	}
++
+ 	update_service_principals (enroll);
+ 
+ 	if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
+@@ -1826,7 +1860,7 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
+ 	 * that we use for salting.
+ 	 */
+ 
+-	return update_keytab_for_principals (enroll);
++	return update_keytab_for_principals (enroll, flags);
+ }
+ 
+ adcli_result
+@@ -1927,7 +1961,11 @@ adcli_enroll_update (adcli_enroll *enroll,
+ 
+ 	if (_adcli_check_nt_time_string_lifetime (value,
+ 	                adcli_enroll_get_computer_password_lifetime (enroll))) {
+-		flags |= ADCLI_ENROLL_NO_KEYTAB;
++		/* Do not update keytab if neither new service principals have
++                 * to be added nor the user principal has to be changed. */
++		if (enroll->service_names == NULL && (enroll->user_principal == NULL || enroll->user_princpal_generate)) {
++			flags |= ADCLI_ENROLL_NO_KEYTAB;
++		}
+ 		flags |= ADCLI_ENROLL_PASSWORD_VALID;
+ 	}
+ 	free (value);
+diff --git a/library/adkrb5.c b/library/adkrb5.c
+index b0e903e..033c181 100644
+--- a/library/adkrb5.c
++++ b/library/adkrb5.c
+@@ -204,6 +204,119 @@ _adcli_krb5_open_keytab (krb5_context k5,
+ 	return ADCLI_SUCCESS;
+ }
+ 
++typedef struct {
++	krb5_kvno kvno;
++	krb5_enctype enctype;
++	int matched;
++} match_enctype_kvno;
++
++static krb5_boolean
++match_enctype_and_kvno (krb5_context k5,
++                        krb5_keytab_entry *entry,
++                        void *data)
++{
++	krb5_boolean similar = FALSE;
++	match_enctype_kvno *closure = data;
++	krb5_error_code code;
++
++	assert (closure->enctype);
++
++	code = krb5_c_enctype_compare (k5, closure->enctype, entry->key.enctype,
++	                               &similar);
++
++	if (code == 0 && entry->vno == closure->kvno && similar) {
++		closure->matched = 1;
++		return 1;
++	}
++
++	return 0;
++}
++
++static krb5_error_code
++_adcli_krb5_get_keyblock (krb5_context k5,
++                          krb5_keytab keytab,
++                          krb5_keyblock *keyblock,
++                          krb5_boolean (* match_func) (krb5_context,
++                                                       krb5_keytab_entry *,
++                                                       void *),
++                          void *match_data)
++{
++	krb5_kt_cursor cursor;
++	krb5_keytab_entry entry;
++	krb5_error_code code;
++
++	code = krb5_kt_start_seq_get (k5, keytab, &cursor);
++	if (code == KRB5_KT_END || code == ENOENT)
++		return 0;
++	else if (code != 0)
++		return code;
++
++	for (;;) {
++		code = krb5_kt_next_entry (k5, keytab, &entry, &cursor);
++		if (code != 0)
++			break;
++
++		/* See if we should remove this entry */
++		if (!match_func (k5, &entry, match_data)) {
++			krb5_free_keytab_entry_contents (k5, &entry);
++			continue;
++		}
++
++		code = krb5_copy_keyblock_contents (k5, &entry.key, keyblock);
++		krb5_free_keytab_entry_contents (k5, &entry);
++		break;
++
++
++	}
++
++	if (code == KRB5_KT_END)
++		code = 0;
++
++	krb5_kt_end_seq_get (k5, keytab, &cursor);
++	return code;
++}
++
++krb5_error_code
++_adcli_krb5_keytab_copy_entries (krb5_context k5,
++                                 krb5_keytab keytab,
++                                 krb5_principal principal,
++                                 krb5_kvno kvno,
++                                 krb5_enctype *enctypes)
++{
++	krb5_keytab_entry entry;
++	krb5_error_code code;
++	int i;
++	match_enctype_kvno closure;
++
++	for (i = 0; enctypes[i] != 0; i++) {
++
++		closure.kvno = kvno;
++		closure.enctype = enctypes[i];
++		closure.matched = 0;
++
++		memset (&entry, 0, sizeof (entry));
++
++		code = _adcli_krb5_get_keyblock (k5, keytab, &entry.key,
++		                                 match_enctype_and_kvno, &closure);
++		if (code != 0) {
++			return code;
++		}
++
++
++		entry.principal = principal;
++		entry.vno = kvno;
++
++		code = krb5_kt_add_entry (k5, keytab, &entry);
++
++		entry.principal = NULL;
++		krb5_free_keytab_entry_contents (k5, &entry);
++
++		if (code != 0)
++			return code;
++	}
++
++	return 0;
++}
+ 
+ krb5_error_code
+ _adcli_krb5_keytab_add_entries (krb5_context k5,
+diff --git a/library/adprivate.h b/library/adprivate.h
+index 83a88f6..7485249 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -282,6 +282,12 @@ krb5_enctype *   _adcli_krb5_parse_enctypes       (const char *value);
+ 
+ char *           _adcli_krb5_format_enctypes      (krb5_enctype *enctypes);
+ 
++krb5_error_code  _adcli_krb5_keytab_copy_entries  (krb5_context k5,
++                                                   krb5_keytab keytab,
++                                                   krb5_principal principal,
++                                                   krb5_kvno kvno,
++                                                   krb5_enctype *enctypes);
++
+ struct _adcli_attrs {
+ 	LDAPMod **mods;
+ 	int len;
+-- 
+2.14.4
+
diff --git a/SOURCES/0004-Calculate-enctypes-in-a-separate-function.patch b/SOURCES/0004-Calculate-enctypes-in-a-separate-function.patch
new file mode 100644
index 0000000..fd34daf
--- /dev/null
+++ b/SOURCES/0004-Calculate-enctypes-in-a-separate-function.patch
@@ -0,0 +1,181 @@
+From 8d36c3e07a6efc65aadd218c28e2f864db15b7fd Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Wed, 6 Jun 2018 16:31:32 +0200
+Subject: [PATCH 4/7] Calculate enctypes in a separate function
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1542354
+---
+ library/adenroll.c | 137 +++++++++++++++++++++++++++++++----------------------
+ 1 file changed, 81 insertions(+), 56 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 1221e89..1ed94f2 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -542,6 +542,83 @@ calculate_computer_account (adcli_enroll *enroll,
+ 	return ADCLI_SUCCESS;
+ }
+ 
++static adcli_result
++calculate_enctypes (adcli_enroll *enroll, char **enctype)
++{
++	char *value = NULL;
++	krb5_enctype *read_enctypes;
++	char *new_value = NULL;
++	int is_2008_or_later;
++	LDAP *ldap;
++
++	*enctype = NULL;
++	/*
++	 * Because we're using a keytab we want the server to be aware of the
++	 * encryption types supported on the client, because we can't dynamically
++	 * use a new one that's thrown at us.
++	 *
++	 * If the encryption types are not explicitly set by the caller of this
++	 * library, then see if the account already has some encryption types
++	 * marked on it.
++	 *
++	 * If not, write our default set to the account.
++	 *
++	 * Note that Windows 2003 and earlier have a standard set of encryption
++	 * types, and no msDS-supportedEncryptionTypes attribute.
++	 */
++
++	ldap = adcli_conn_get_ldap_connection (enroll->conn);
++	return_unexpected_if_fail (ldap != NULL);
++
++	is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
++
++	/* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
++	if (is_2008_or_later) {
++		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
++		                                 "msDS-supportedEncryptionTypes");
++
++		if (!enroll->keytab_enctypes_explicit && value != NULL) {
++			read_enctypes = _adcli_krb5_parse_enctypes (value);
++			if (read_enctypes == NULL) {
++				_adcli_warn ("Invalid or unsupported encryption types are set on "
++				             "the computer account (%s).", value);
++			} else {
++				free (enroll->keytab_enctypes);
++				enroll->keytab_enctypes = read_enctypes;
++			}
++		}
++
++	/* In 2003 or earlier, standard set of enc types */
++	} else {
++		value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
++	}
++
++	new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll));
++	if (new_value == NULL) {
++		free (value);
++		_adcli_warn ("The encryption types desired are not available in active directory");
++		return ADCLI_ERR_CONFIG;
++	}
++
++	/* If we already have this value, then don't need to update */
++	if (value && strcmp (new_value, value) == 0) {
++		free (value);
++		free (new_value);
++		return ADCLI_SUCCESS;
++	}
++	free (value);
++
++	if (!is_2008_or_later) {
++		free (new_value);
++		_adcli_warn ("Server does not support setting encryption types");
++		return ADCLI_SUCCESS;
++	}
++
++	*enctype = new_value;
++	return ADCLI_SUCCESS;
++}
++
++
+ static adcli_result
+ create_computer_account (adcli_enroll *enroll,
+                          LDAP *ldap)
+@@ -1053,75 +1130,23 @@ retrieve_computer_account (adcli_enroll *enroll)
+ static adcli_result
+ update_and_calculate_enctypes (adcli_enroll *enroll)
+ {
+-	char *value = NULL;
+-	krb5_enctype *read_enctypes;
+ 	char *vals_supportedEncryptionTypes[] = { NULL, NULL };
+ 	LDAPMod mod = { LDAP_MOD_REPLACE, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
+ 	LDAPMod *mods[2] = { &mod, NULL };
+-	int is_2008_or_later;
+ 	char *new_value;
+ 	LDAP *ldap;
+ 	int ret;
+ 
+-	/*
+-	 * Because we're using a keytab we want the server to be aware of the
+-	 * encryption types supported on the client, because we can't dynamically
+-	 * use a new one that's thrown at us.
+-	 *
+-	 * If the encryption types are not explicitly set by the caller of this
+-	 * library, then see if the account already has some encryption types
+-	 * marked on it.
+-	 *
+-	 * If not, write our default set to the account.
+-	 *
+-	 * Note that Windows 2003 and earlier have a standard set of encryption
+-	 * types, and no msDS-supportedEncryptionTypes attribute.
+-	 */
+-
+ 	ldap = adcli_conn_get_ldap_connection (enroll->conn);
+ 	return_unexpected_if_fail (ldap != NULL);
+ 
+-	is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
+-
+-	/* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
+-	if (is_2008_or_later) {
+-		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
+-		                                 "msDS-supportedEncryptionTypes");
+-
+-		if (!enroll->keytab_enctypes_explicit && value != NULL) {
+-			read_enctypes = _adcli_krb5_parse_enctypes (value);
+-			if (read_enctypes == NULL) {
+-				_adcli_warn ("Invalid or unsupported encryption types are set on "
+-				             "the computer account (%s).", value);
+-			} else {
+-				free (enroll->keytab_enctypes);
+-				enroll->keytab_enctypes = read_enctypes;
+-			}
+-		}
+-
+-	/* In 2003 or earlier, standard set of enc types */
+-	} else {
+-		value = _adcli_krb5_format_enctypes (v51_earlier_enctypes);
+-	}
+-
+-	new_value = _adcli_krb5_format_enctypes (adcli_enroll_get_keytab_enctypes (enroll));
+-	if (new_value == NULL) {
+-		free (value);
+-		_adcli_warn ("The encryption types desired are not available in active directory");
+-		return ADCLI_ERR_CONFIG;
+-	}
+-
+-	/* If we already have this value, then don't need to update */
+-	if (value && strcmp (new_value, value) == 0) {
+-		free (value);
++	ret = calculate_enctypes (enroll, &new_value);
++	if (ret != ADCLI_SUCCESS) {
+ 		free (new_value);
+-		return ADCLI_SUCCESS;
++		return ret;
+ 	}
+-	free (value);
+ 
+-	if (!is_2008_or_later) {
+-		free (new_value);
+-		_adcli_warn ("Server does not support setting encryption types");
++	if (new_value == NULL) {
+ 		return ADCLI_SUCCESS;
+ 	}
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0004-Do-not-depend-on-default_realm-in-krb5.conf.patch b/SOURCES/0004-Do-not-depend-on-default_realm-in-krb5.conf.patch
new file mode 100644
index 0000000..d12f335
--- /dev/null
+++ b/SOURCES/0004-Do-not-depend-on-default_realm-in-krb5.conf.patch
@@ -0,0 +1,27 @@
+From 8f726817b9ff643a382fa12ea9ff489cd5ab9068 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 13 Aug 2018 18:24:58 +0200
+Subject: [PATCH 4/4] Do not depend on default_realm in krb5.conf
+
+---
+ library/adenroll.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index bb50365..02bd9e3 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -1661,7 +1661,9 @@ remove_principal_from_keytab (adcli_enroll *enroll,
+ 	krb5_principal principal;
+ 	match_principal_kvno closure;
+ 
+-	code = krb5_parse_name (k5, principal_name, &principal);
++	code = _adcli_krb5_build_principal (k5, principal_name,
++	                                    adcli_conn_get_domain_realm (enroll->conn),
++	                                    &principal);
+ 	if (code != 0) {
+ 		_adcli_err ("Couldn't parse principal: %s: %s",
+ 		            principal_name, krb5_get_error_message (k5, code));
+-- 
+2.17.1
+
diff --git a/SOURCES/0004-library-add-_adcli_ldap_parse_sid.patch b/SOURCES/0004-library-add-_adcli_ldap_parse_sid.patch
new file mode 100644
index 0000000..e3cfb75
--- /dev/null
+++ b/SOURCES/0004-library-add-_adcli_ldap_parse_sid.patch
@@ -0,0 +1,69 @@
+From fc48976e49ebffb6db8b640eebcc3015e55a886f Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 14:44:45 +0100
+Subject: [PATCH 4/9] library: add _adcli_ldap_parse_sid()
+
+Get a binary SID from a LDAP message and return it in the string
+representation.
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ library/adldap.c    | 24 ++++++++++++++++++++++++
+ library/adprivate.h |  4 ++++
+ 2 files changed, 28 insertions(+)
+
+diff --git a/library/adldap.c b/library/adldap.c
+index 7c7a01b..07dc373 100644
+--- a/library/adldap.c
++++ b/library/adldap.c
+@@ -67,6 +67,30 @@ _adcli_ldap_handle_failure (LDAP *ldap,
+ 	return defres;
+ }
+ 
++char *
++_adcli_ldap_parse_sid (LDAP *ldap,
++                         LDAPMessage *results,
++                         const char *attr_name)
++{
++	LDAPMessage *entry;
++	struct berval **bvs;
++	char *val = NULL;
++
++	entry = ldap_first_entry (ldap, results);
++	if (entry != NULL) {
++		bvs = ldap_get_values_len (ldap, entry, attr_name);
++		if (bvs != NULL) {
++			if (bvs[0]) {
++				val = _adcli_bin_sid_to_str ( (uint8_t *) bvs[0]->bv_val,
++				                              bvs[0]->bv_len);
++				return_val_if_fail (val != NULL, NULL);
++			}
++			ldap_value_free_len (bvs);
++		}
++	}
++
++	return val;
++}
+ 
+ char *
+ _adcli_ldap_parse_value (LDAP *ldap,
+diff --git a/library/adprivate.h b/library/adprivate.h
+index 7257c93..83a88f6 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -174,6 +174,10 @@ adcli_result  _adcli_ldap_handle_failure     (LDAP *ldap,
+                                               const char *desc,
+                                               ...) GNUC_PRINTF(3, 4);
+ 
++char *         _adcli_ldap_parse_sid         (LDAP *ldap,
++                                              LDAPMessage *results,
++                                              const char *attr_name);
++
+ char *        _adcli_ldap_parse_value        (LDAP *ldap,
+                                               LDAPMessage *results,
+                                               const char *attr_name);
+-- 
+2.14.4
+
diff --git a/SOURCES/0005-join-add-all-attributes-while-creating-computer-obje.patch b/SOURCES/0005-join-add-all-attributes-while-creating-computer-obje.patch
new file mode 100644
index 0000000..2aeb04a
--- /dev/null
+++ b/SOURCES/0005-join-add-all-attributes-while-creating-computer-obje.patch
@@ -0,0 +1,110 @@
+From e9198751411d11785ac6e7e533d63911b6e51326 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Mon, 11 Jun 2018 09:44:49 +0200
+Subject: [PATCH 5/7] join: add all attributes while creating computer object
+
+It is possible to create special accounts which can only join a computer
+to a domain but is not allowed to do any further operations which the
+computer object. As a result if such an account is used during the join
+only the ldapadd operation is permitted but not any later ldapmodify
+operation. To create the computer object correctly in this case all
+attributes must be added while the object is created and not later.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1542354
+---
+ library/adenroll.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 47 insertions(+), 5 deletions(-)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 1ed94f2..3f8d017 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -573,7 +573,7 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
+ 	is_2008_or_later = adcli_conn_server_has_capability (enroll->conn, ADCLI_CAP_V60_OID);
+ 
+ 	/* In 2008 or later, use the msDS-supportedEncryptionTypes attribute */
+-	if (is_2008_or_later) {
++	if (is_2008_or_later && enroll->computer_attributes != NULL) {
+ 		value = _adcli_ldap_parse_value (ldap, enroll->computer_attributes,
+ 		                                 "msDS-supportedEncryptionTypes");
+ 
+@@ -618,7 +618,6 @@ calculate_enctypes (adcli_enroll *enroll, char **enctype)
+ 	return ADCLI_SUCCESS;
+ }
+ 
+-
+ static adcli_result
+ create_computer_account (adcli_enroll *enroll,
+                          LDAP *ldap)
+@@ -628,22 +627,65 @@ create_computer_account (adcli_enroll *enroll,
+ 	char *vals_sAMAccountName[] = { enroll->computer_sam, NULL };
+ 	LDAPMod sAMAccountName = { LDAP_MOD_ADD, "sAMAccountName", { vals_sAMAccountName, } };
+ 	char *vals_userAccountControl[] = { "69632", NULL }; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD */
+-	LDAPMod userAccountControl = { LDAP_MOD_REPLACE, "userAccountControl", { vals_userAccountControl, } };
++	LDAPMod userAccountControl = { LDAP_MOD_ADD, "userAccountControl", { vals_userAccountControl, } };
++	char *vals_supportedEncryptionTypes[] = { NULL, NULL };
++	LDAPMod encTypes = { LDAP_MOD_ADD, "msDS-supportedEncryptionTypes", { vals_supportedEncryptionTypes, } };
++	char *vals_dNSHostName[] = { enroll->host_fqdn, NULL };
++	LDAPMod dNSHostName = { LDAP_MOD_ADD, "dNSHostName", { vals_dNSHostName, } };
++	char *vals_operatingSystem[] = { enroll->os_name, NULL };
++	LDAPMod operatingSystem = { LDAP_MOD_ADD, "operatingSystem", { vals_operatingSystem, } };
++	char *vals_operatingSystemVersion[] = { enroll->os_version, NULL };
++	LDAPMod operatingSystemVersion = { LDAP_MOD_ADD, "operatingSystemVersion", { vals_operatingSystemVersion, } };
++	char *vals_operatingSystemServicePack[] = { enroll->os_service_pack, NULL };
++	LDAPMod operatingSystemServicePack = { LDAP_MOD_ADD, "operatingSystemServicePack", { vals_operatingSystemServicePack, } };
++	char *vals_userPrincipalName[] = { enroll->user_principal, NULL };
++	LDAPMod userPrincipalName = { LDAP_MOD_ADD, "userPrincipalName", { vals_userPrincipalName, }, };
++	LDAPMod servicePrincipalName = { LDAP_MOD_ADD, "servicePrincipalName", { enroll->service_principals, } };
++
++	char *val = NULL;
+ 
+ 	int ret;
++	size_t c;
++	size_t m;
+ 
+-	LDAPMod *mods[] = {
++	LDAPMod *all_mods[] = {
+ 		&objectClass,
+ 		&sAMAccountName,
+ 		&userAccountControl,
+-		NULL,
++		&encTypes,
++		&dNSHostName,
++		&operatingSystem,
++		&operatingSystemVersion,
++		&operatingSystemServicePack,
++		&userPrincipalName,
++		&servicePrincipalName,
++		NULL
+ 	};
+ 
++	size_t mods_count = sizeof (all_mods) / sizeof (LDAPMod *);
++	LDAPMod *mods[mods_count];
++
+ 	if (adcli_enroll_get_trusted_for_delegation (enroll)) {
+ 		vals_userAccountControl[0] = "593920"; /* WORKSTATION_TRUST_ACCOUNT | DONT_EXPIRE_PASSWD | TRUSTED_FOR_DELEGATION */
+ 	}
+ 
++	ret = calculate_enctypes (enroll, &val);
++	if (ret != ADCLI_SUCCESS) {
++		return ret;
++	}
++	vals_supportedEncryptionTypes[0] = val;
++
++	m = 0;
++	for (c = 0; c < mods_count - 1; c++) {
++		/* Skip empty LDAP sttributes */
++		if (all_mods[c]->mod_vals.modv_strvals[0] != NULL) {
++			mods[m++] = all_mods[c];
++		}
++	}
++	mods[m] = NULL;
++
+ 	ret = ldap_add_ext_s (ldap, enroll->computer_dn, mods, NULL, NULL);
++	free (val);
+ 
+ 	/*
+ 	 * Hand to head. This is really dumb... AD returns
+-- 
+2.14.4
+
diff --git a/SOURCES/0005-library-add-lookup_domain_sid.patch b/SOURCES/0005-library-add-lookup_domain_sid.patch
new file mode 100644
index 0000000..89e68e7
--- /dev/null
+++ b/SOURCES/0005-library-add-lookup_domain_sid.patch
@@ -0,0 +1,71 @@
+From 43fe15cc27ebf5f33234c30067a295ef0bd864bb Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 14:40:46 +0100
+Subject: [PATCH 5/9] library: add lookup_domain_sid()
+
+Read the domain SID from the default naming context AD object and store
+it in adcli_conn.
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ library/adconn.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/library/adconn.c b/library/adconn.c
+index 67bdfd9..6b84b88 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -72,6 +72,7 @@ struct _adcli_conn_ctx {
+ 	char *domain_controller;
+ 	char *canonical_host;
+ 	char *domain_short;
++	char *domain_sid;
+ 	adcli_disco *domain_disco;
+ 	char *default_naming_context;
+ 	char *configuration_naming_context;
+@@ -1068,6 +1069,32 @@ lookup_short_name (adcli_conn *conn)
+ 	}
+ }
+ 
++static void
++lookup_domain_sid (adcli_conn *conn)
++{
++	char *attrs[] = { "objectSid", NULL, };
++	LDAPMessage *results;
++	int ret;
++
++	free (conn->domain_sid);
++	conn->domain_sid = NULL;
++
++	ret = ldap_search_ext_s (conn->ldap, conn->default_naming_context, LDAP_SCOPE_BASE,
++	                         NULL, attrs, 0, NULL, NULL, NULL, -1, &results);
++	if (ret == LDAP_SUCCESS) {
++		conn->domain_sid = _adcli_ldap_parse_sid (conn->ldap, results, "objectSid");
++		ldap_msgfree (results);
++
++		if (conn->domain_sid)
++			_adcli_info ("Looked up domain SID: %s", conn->domain_sid);
++		else
++			_adcli_err ("No domain SID found");
++	} else {
++		_adcli_ldap_handle_failure (conn->ldap, ADCLI_ERR_DIRECTORY,
++		                            "Couldn't lookup domain SID");
++	}
++}
++
+ static void
+ conn_clear_state (adcli_conn *conn)
+ {
+@@ -1148,6 +1175,7 @@ adcli_conn_connect (adcli_conn *conn)
+ 		return res;
+ 
+ 	lookup_short_name (conn);
++	lookup_domain_sid (conn);
+ 	return ADCLI_SUCCESS;
+ }
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0006-library-add-adcli_conn_get_domain_sid.patch b/SOURCES/0006-library-add-adcli_conn_get_domain_sid.patch
new file mode 100644
index 0000000..a390fd9
--- /dev/null
+++ b/SOURCES/0006-library-add-adcli_conn_get_domain_sid.patch
@@ -0,0 +1,61 @@
+From f2d54486b911974e396255a5e27003abbf7268ab Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 18:23:03 +0100
+Subject: [PATCH 6/9] library: add adcli_conn_get_domain_sid()
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ library/adconn.c | 8 ++++++++
+ library/adconn.h | 2 ++
+ tools/computer.c | 1 +
+ 3 files changed, 11 insertions(+)
+
+diff --git a/library/adconn.c b/library/adconn.c
+index 6b84b88..d2fb1d5 100644
+--- a/library/adconn.c
++++ b/library/adconn.c
+@@ -1355,6 +1355,14 @@ adcli_conn_get_domain_short (adcli_conn *conn)
+ 	return conn->domain_short;
+ }
+ 
++const char *
++adcli_conn_get_domain_sid (adcli_conn *conn)
++{
++	return_val_if_fail (conn != NULL, NULL);
++	return conn->domain_sid;
++}
++
++
+ LDAP *
+ adcli_conn_get_ldap_connection (adcli_conn *conn)
+ {
+diff --git a/library/adconn.h b/library/adconn.h
+index ed1cc58..13cfd32 100644
+--- a/library/adconn.h
++++ b/library/adconn.h
+@@ -91,6 +91,8 @@ void                adcli_conn_set_domain_controller (adcli_conn *conn,
+ 
+ const char *        adcli_conn_get_domain_short      (adcli_conn *conn);
+ 
++const char *        adcli_conn_get_domain_sid        (adcli_conn *conn);
++
+ LDAP *              adcli_conn_get_ldap_connection   (adcli_conn *conn);
+ 
+ krb5_context        adcli_conn_get_krb5_context      (adcli_conn *conn);
+diff --git a/tools/computer.c b/tools/computer.c
+index d8a58c9..a3d0f03 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -43,6 +43,7 @@ dump_details (adcli_conn *conn,
+ 	printf ("domain-realm = %s\n", adcli_conn_get_domain_realm (conn));
+ 	printf ("domain-controller = %s\n", adcli_conn_get_domain_controller (conn));
+ 	printf ("domain-short = %s\n", adcli_conn_get_domain_short (conn));
++	printf ("domain-SID = %s\n", adcli_conn_get_domain_sid (conn));
+ 	printf ("naming-context = %s\n", adcli_conn_get_default_naming_context (conn));
+ 	printf ("domain-ou = %s\n", adcli_enroll_get_domain_ou (enroll));
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0006-util-add-_adcli_strv_remove_unsorted.patch b/SOURCES/0006-util-add-_adcli_strv_remove_unsorted.patch
new file mode 100644
index 0000000..eb5f96b
--- /dev/null
+++ b/SOURCES/0006-util-add-_adcli_strv_remove_unsorted.patch
@@ -0,0 +1,288 @@
+From 3c97263990648f808010220a080f4f9a4e846dac Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 14 Jun 2018 16:48:22 +0200
+Subject: [PATCH 6/7] util: add _adcli_strv_remove_unsorted
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547014
+---
+ library/adprivate.h |   4 ++
+ library/adutil.c    |  21 ++++++++
+ library/seq.c       | 149 +++++++++++++++++++++++++++++++++++++++++++++++++---
+ library/seq.h       |  12 +++++
+ 4 files changed, 179 insertions(+), 7 deletions(-)
+
+diff --git a/library/adprivate.h b/library/adprivate.h
+index 7485249..bc9df6d 100644
+--- a/library/adprivate.h
++++ b/library/adprivate.h
+@@ -111,6 +111,10 @@ char **        _adcli_strv_add               (char **strv,
+                                               char *string,
+                                               int *length) GNUC_WARN_UNUSED;
+ 
++void           _adcli_strv_remove_unsorted   (char **strv,
++                                              const char *string,
++                                              int *length);
++
+ void           _adcli_strv_free              (char **strv);
+ 
+ int            _adcli_strv_has               (char **strv,
+diff --git a/library/adutil.c b/library/adutil.c
+index a27bd68..6334b52 100644
+--- a/library/adutil.c
++++ b/library/adutil.c
+@@ -221,6 +221,27 @@ _adcli_strv_add (char **strv,
+ 	return seq_push (strv, length, string);
+ }
+ 
++#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
++
++void
++_adcli_strv_remove_unsorted (char **strv,
++                             const char *string,
++                             int *length)
++{
++	int len;
++
++	return_if_fail (string != NULL);
++
++	if (!length) {
++		len = seq_count (strv);
++		length = &len;
++	}
++
++	return seq_remove_unsorted (strv, length, discard_const (string),
++	                            (seq_compar)strcasecmp, free);
++}
++
++
+ int
+ _adcli_strv_has (char **strv,
+                  const char *str)
+diff --git a/library/seq.c b/library/seq.c
+index 627dcaf..8e7475d 100644
+--- a/library/seq.c
++++ b/library/seq.c
+@@ -111,6 +111,24 @@ seq_push (seq_voidp sequence,
+ 	return seq;
+ }
+ 
++static int
++linear_search (void **seq,
++               int low,
++               int high,
++               void *match,
++               seq_compar compar)
++{
++	int at;
++
++	for (at = low; at < high; at++) {
++		if (compar (match, seq[at]) == 0) {
++			break;
++		}
++	}
++
++	return at;
++}
++
+ static int
+ binary_search (void **seq,
+                int low,
+@@ -171,12 +189,13 @@ seq_insert (seq_voidp sequence,
+ 	return seq;
+ }
+ 
+-void
+-seq_remove (seq_voidp sequence,
+-            int *length,
+-            void *match,
+-            seq_compar compar,
+-            seq_destroy destroy)
++static void
++seq_remove_int (seq_voidp sequence,
++                int *length,
++                void *match,
++                seq_search search,
++                seq_compar compar,
++                seq_destroy destroy)
+ {
+ 	void **seq = sequence;
+ 	int at;
+@@ -187,7 +206,7 @@ seq_remove (seq_voidp sequence,
+ 	assert (match != NULL);
+ 
+ 	len = *length;
+-	at = binary_search (seq, 0, len, match, compar);
++	at = search (seq, 0, len, match, compar);
+ 
+ 	/* We have a matching value */
+ 	if (at < len && compar (match, seq[at]) == 0) {
+@@ -201,6 +220,26 @@ seq_remove (seq_voidp sequence,
+ 	*length = len;
+ }
+ 
++void
++seq_remove (seq_voidp sequence,
++            int *length,
++            void *match,
++            seq_compar compar,
++            seq_destroy destroy)
++{
++	return seq_remove_int (sequence, length, match, binary_search, compar, destroy);
++}
++
++void
++seq_remove_unsorted (seq_voidp sequence,
++                     int *length,
++                     void *match,
++                     seq_compar compar,
++                     seq_destroy destroy)
++{
++	return seq_remove_int (sequence, length, match, linear_search, compar, destroy);
++}
++
+ void
+ seq_filter (seq_voidp sequence,
+             int *length,
+@@ -430,6 +469,99 @@ test_remove (void)
+ 	seq_free (seq, NULL);
+ }
+ 
++static void
++test_remove_unsorted (void)
++{
++	void **seq = NULL;
++	int len = 0;
++
++	seq = seq_push (seq, &len, "3");
++	seq = seq_push (seq, &len, "5");
++	seq = seq_push (seq, &len, "1");
++	seq = seq_push (seq, &len, "4");
++	seq = seq_push (seq, &len, "2");
++
++	assert_str_eq (seq[0], "3");
++	assert_str_eq (seq[1], "5");
++	assert_str_eq (seq[2], "1");
++	assert_str_eq (seq[3], "4");
++	assert_str_eq (seq[4], "2");
++	assert (seq[5] == NULL);
++	assert_num_eq (len, 5);
++
++	seq_remove_unsorted (seq, &len, "3", (seq_compar)strcmp, NULL);
++	seq_remove_unsorted (seq, &len, "2", (seq_compar)strcmp, NULL);
++
++	assert_str_eq (seq[0], "5");
++	assert_str_eq (seq[1], "1");
++	assert_str_eq (seq[2], "4");
++	assert (seq[3] == NULL);
++	assert_num_eq (len, 3);
++
++	seq_free (seq, NULL);
++}
++
++static void
++test_remove_first (void)
++{
++	void **seq = NULL;
++	int len = 0;
++
++	seq = seq_insert (seq, &len, "3", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "5", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "1", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "4", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "2", (seq_compar)strcmp, NULL);
++
++	assert_str_eq (seq[0], "1");
++	assert_str_eq (seq[1], "2");
++	assert_str_eq (seq[2], "3");
++	assert_str_eq (seq[3], "4");
++	assert_str_eq (seq[4], "5");
++	assert (seq[5] == NULL);
++	assert_num_eq (len, 5);
++
++	seq_remove (seq, &len, "1", (seq_compar)strcmp, NULL);
++
++	assert_str_eq (seq[0], "2");
++	assert_str_eq (seq[1], "3");
++	assert_str_eq (seq[2], "4");
++	assert_str_eq (seq[3], "5");
++	assert (seq[4] == NULL);
++	assert_num_eq (len, 4);
++
++	seq_free (seq, NULL);
++}
++
++static void
++test_remove_last (void)
++{
++	void **seq = NULL;
++	int len = 0;
++
++	seq = seq_insert (seq, &len, "3", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "1", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "4", (seq_compar)strcmp, NULL);
++	seq = seq_insert (seq, &len, "2", (seq_compar)strcmp, NULL);
++
++	assert_str_eq (seq[0], "1");
++	assert_str_eq (seq[1], "2");
++	assert_str_eq (seq[2], "3");
++	assert_str_eq (seq[3], "4");
++	assert (seq[4] == NULL);
++	assert_num_eq (len, 4);
++
++	seq_remove (seq, &len, "4", (seq_compar)strcmp, NULL);
++
++	assert_str_eq (seq[0], "1");
++	assert_str_eq (seq[1], "2");
++	assert_str_eq (seq[2], "3");
++	assert (seq[3] == NULL);
++	assert_num_eq (len, 3);
++
++	seq_free (seq, NULL);
++}
++
+ static int
+ compar_even (void *match,
+              void *value)
+@@ -631,6 +763,9 @@ main (int argc,
+ 	test_func (test_insert, "/seq/insert");
+ 	test_func (test_insert_destroys, "/seq/insert_destroys");
+ 	test_func (test_remove, "/seq/remove");
++	test_func (test_remove_unsorted, "/seq/remove_unsorted");
++	test_func (test_remove_first, "/seq/remove_first");
++	test_func (test_remove_last, "/seq/remove_last");
+ 	test_func (test_remove_destroys, "/seq/remove_destroys");
+ 	test_func (test_filter, "/seq/filter");
+ 	test_func (test_filter_null, "/seq/filter_null");
+diff --git a/library/seq.h b/library/seq.h
+index 694965b..5d48848 100644
+--- a/library/seq.h
++++ b/library/seq.h
+@@ -44,6 +44,12 @@ typedef void *     (* seq_copy)               (void *value);
+ 
+ typedef void       (* seq_destroy)            (void *value);
+ 
++typedef int        (* seq_search)             (void **seq,
++                                               int low,
++                                               int high,
++                                               void *match,
++                                               seq_compar compar);
++
+ seq_voidp          seq_push                   (seq_voidp seq,
+                                                int *length,
+                                                void *value) WARN_UNUSED;
+@@ -62,6 +68,12 @@ void               seq_remove                 (seq_voidp seq,
+                                                seq_compar compar,
+                                                seq_destroy destroy);
+ 
++void               seq_remove_unsorted        (seq_voidp seq,
++                                               int *length,
++                                               void *match,
++                                               seq_compar compar,
++                                               seq_destroy destroy);
++
+ seq_voidp          seq_lookup                 (seq_voidp seq,
+                                                int *length,
+                                                void *match,
+-- 
+2.14.4
+
diff --git a/SOURCES/0007-Add-add-service-principal-and-remove-service-princip.patch b/SOURCES/0007-Add-add-service-principal-and-remove-service-princip.patch
new file mode 100644
index 0000000..f665593
--- /dev/null
+++ b/SOURCES/0007-Add-add-service-principal-and-remove-service-princip.patch
@@ -0,0 +1,360 @@
+From 767e905e096d9b4f2361a5f307dfb9e622e847aa Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 14 Jun 2018 16:49:26 +0200
+Subject: [PATCH 7/7] Add add-service-principal and remove-service-principal
+ options
+
+Currently it is only possible to specific a service name for service
+principals but not to set the full service principal. This is e.g.
+needed if there is a service running on a host which should be reachable
+by a different DNS name as well.
+
+With this patch service principal can be added and removed by specifying
+the full name.
+
+Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547014
+---
+ doc/adcli.xml      |  21 ++++++++
+ library/adenroll.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++--
+ library/adenroll.h |   8 +++
+ library/adldap.c   |  16 ++++--
+ tools/computer.c   |  13 +++++
+ 5 files changed, 189 insertions(+), 8 deletions(-)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index b246190..83b6981 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -290,6 +290,14 @@ Password for Administrator:
+ 			not allow that Kerberos tickets can be forwarded to the
+ 			host.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--add-service-principal=<parameter>service/hostname</parameter></option></term>
++			<listitem><para>Add a service principal name. In
++			contrast to the <option>--service-name</option> the
++			hostname part can be specified as well in case the
++			service should be accessible with a different host
++			name as well.</para></listitem>
++		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--show-details</option></term>
+ 			<listitem><para>After a successful join print out information
+@@ -416,6 +424,19 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 			not allow that Kerberos tickets can be forwarded to the
+ 			host.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--add-service-principal=<parameter>service/hostname</parameter></option></term>
++			<listitem><para>Add a service principal name. In
++			contrast to the <option>--service-name</option> the
++			hostname part can be specified as well in case the
++			service should be accessible with a different host
++			name as well.</para></listitem>
++		</varlistentry>
++		<varlistentry>
++			<term><option>--remove-service-principal=<parameter>service/hostname</parameter></option></term>
++			<listitem><para>Remove a service principal name from
++			the keytab and the AD host object.</para></listitem>
++		</varlistentry>
+ 		<varlistentry>
+ 			<term><option>--show-details</option></term>
+ 			<listitem><para>After a successful join print out information
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 3f8d017..1ecd371 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -95,6 +95,9 @@ struct _adcli_enroll {
+ 	char **service_principals;
+ 	int service_principals_explicit;
+ 
++	char **service_principals_to_add;
++	char **service_principals_to_remove;
++
+ 	char *user_principal;
+ 	int user_princpal_generate;
+ 
+@@ -332,6 +335,43 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
+ 	return ADCLI_SUCCESS;
+ }
+ 
++static adcli_result
++add_and_remove_service_principals (adcli_enroll *enroll)
++{
++	int length = 0;
++	size_t c;
++	const char **list;
++
++	if (enroll->service_principals != NULL) {
++		length = seq_count (enroll->service_principals);
++	}
++
++	list = adcli_enroll_get_service_principals_to_add (enroll);
++	if (list != NULL) {
++		for (c = 0; list[c] != NULL; c++) {
++			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
++			                                              strdup (list[c]),
++			                                              &length);
++			if (enroll->service_principals == NULL) {
++				return ADCLI_ERR_UNEXPECTED;
++			}
++		}
++	}
++
++	list = adcli_enroll_get_service_principals_to_remove (enroll);
++	if (list != NULL) {
++		for (c = 0; list[c] != NULL; c++) {
++			/* enroll->service_principals typically refects the
++			 * order of the principal in the keytabm so it is not
++			 * ordered. */
++			_adcli_strv_remove_unsorted (enroll->service_principals,
++			                             list[c], &length);
++		}
++	}
++
++	return ADCLI_SUCCESS;
++}
++
+ static adcli_result
+ ensure_service_principals (adcli_result res,
+                            adcli_enroll *enroll)
+@@ -343,10 +383,14 @@ ensure_service_principals (adcli_result res,
+ 
+ 	if (!enroll->service_principals) {
+ 		assert (enroll->service_names != NULL);
+-		return add_service_names_to_service_principals (enroll);
++		res = add_service_names_to_service_principals (enroll);
+ 	}
+ 
+-	return ADCLI_SUCCESS;
++	if (res == ADCLI_SUCCESS) {
++		res = add_and_remove_service_principals (enroll);
++	}
++
++	return res;
+ }
+ 
+ static adcli_result
+@@ -1593,6 +1637,39 @@ free_principal_salts (krb5_context k5,
+ 	free (salts);
+ }
+ 
++static adcli_result
++remove_principal_from_keytab (adcli_enroll *enroll,
++                              krb5_context k5,
++                              const char *principal_name)
++{
++	krb5_error_code code;
++	krb5_principal principal;
++	match_principal_kvno closure;
++
++	code = krb5_parse_name (k5, principal_name, &principal);
++	if (code != 0) {
++		_adcli_err ("Couldn't parse principal: %s: %s",
++		            principal_name, krb5_get_error_message (k5, code));
++		return ADCLI_ERR_FAIL;
++	}
++
++	closure.kvno = enroll->kvno;
++	closure.principal = principal;
++	closure.matched = 0;
++
++	code = _adcli_krb5_keytab_clear (k5, enroll->keytab,
++	                                 match_principal_and_kvno, &closure);
++	krb5_free_principal (k5, principal);
++
++	if (code != 0) {
++		_adcli_err ("Couldn't update keytab: %s: %s",
++		            enroll->keytab_name, krb5_get_error_message (k5, code));
++		return ADCLI_ERR_FAIL;
++	}
++
++	return ADCLI_SUCCESS;
++}
++
+ static adcli_result
+ add_principal_to_keytab (adcli_enroll *enroll,
+                          krb5_context k5,
+@@ -1702,6 +1779,17 @@ update_keytab_for_principals (adcli_enroll *enroll,
+ 			return res;
+ 	}
+ 
++	if (enroll->service_principals_to_remove != NULL) {
++		for (i = 0; enroll->service_principals_to_remove[i] != NULL; i++) {
++			res = remove_principal_from_keytab (enroll, k5,
++			                                    enroll->service_principals_to_remove[i]);
++			if (res != ADCLI_SUCCESS) {
++				_adcli_warn ("Failed to remove %s from keytab.",
++				             enroll->service_principals_to_remove[i]);
++			}
++		}
++	}
++
+ 	return ADCLI_SUCCESS;
+ }
+ 
+@@ -2029,8 +2117,11 @@ adcli_enroll_update (adcli_enroll *enroll,
+ 	if (_adcli_check_nt_time_string_lifetime (value,
+ 	                adcli_enroll_get_computer_password_lifetime (enroll))) {
+ 		/* Do not update keytab if neither new service principals have
+-                 * to be added nor the user principal has to be changed. */
+-		if (enroll->service_names == NULL && (enroll->user_principal == NULL || enroll->user_princpal_generate)) {
++                 * to be added or deleted nor the user principal has to be changed. */
++		if (enroll->service_names == NULL
++		              && (enroll->user_principal == NULL || enroll->user_princpal_generate)
++		              && enroll->service_principals_to_add == NULL
++		              && enroll->service_principals_to_remove == NULL) {
+ 			flags |= ADCLI_ENROLL_NO_KEYTAB;
+ 		}
+ 		flags |= ADCLI_ENROLL_PASSWORD_VALID;
+@@ -2581,3 +2672,43 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
+ 	enroll->trusted_for_delegation = value;
+ 	enroll->trusted_for_delegation_explicit = 1;
+ }
++
++const char **
++adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll)
++{
++	return_val_if_fail (enroll != NULL, NULL);
++
++	return (const char **)enroll->service_principals_to_add;
++}
++
++void
++adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
++                                           const char *value)
++{
++	return_if_fail (enroll != NULL);
++	return_if_fail (value != NULL);
++
++	enroll->service_principals_to_add = _adcli_strv_add (enroll->service_principals_to_add,
++							    strdup (value), NULL);
++	return_if_fail (enroll->service_principals_to_add != NULL);
++}
++
++const char **
++adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll)
++{
++	return_val_if_fail (enroll != NULL, NULL);
++
++	return (const char **)enroll->service_principals_to_remove;
++}
++
++void
++adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
++                                              const char *value)
++{
++	return_if_fail (enroll != NULL);
++	return_if_fail (value != NULL);
++
++	enroll->service_principals_to_remove = _adcli_strv_add (enroll->service_principals_to_remove,
++							    strdup (value), NULL);
++	return_if_fail (enroll->service_principals_to_remove != NULL);
++}
+diff --git a/library/adenroll.h b/library/adenroll.h
+index be2ca18..f87dffa 100644
+--- a/library/adenroll.h
++++ b/library/adenroll.h
+@@ -98,6 +98,14 @@ const char **      adcli_enroll_get_service_principals  (adcli_enroll *enroll);
+ void               adcli_enroll_set_service_principals  (adcli_enroll *enroll,
+                                                          const char **value);
+ 
++const char **      adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll);
++void               adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
++                                                              const char *value);
++
++const char **      adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll);
++void               adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
++                                                                 const char *value);
++
+ const char *       adcli_enroll_get_user_principal      (adcli_enroll *enroll);
+ 
+ void               adcli_enroll_set_user_principal      (adcli_enroll *enroll,
+diff --git a/library/adldap.c b/library/adldap.c
+index 07dc373..d93efb7 100644
+--- a/library/adldap.c
++++ b/library/adldap.c
+@@ -210,16 +210,24 @@ _adcli_ldap_have_in_mod (LDAPMod *mod,
+ 	struct berval *vals;
+ 	struct berval **pvals;
+ 	int count = 0;
++	int count_have = 0;
+ 	int i;
+ 	int ret;
+ 
+-	/* Already in berval format, just compare */
+-	if (mod->mod_op & LDAP_MOD_BVALUES)
+-		return _adcli_ldap_have_vals (mod->mod_vals.modv_bvals, have);
+-
+ 	/* Count number of values */
+ 	for (i = 0; mod->mod_vals.modv_strvals[i] != 0; i++)
+ 		count++;
++	for (i = 0; have[i] != 0; i++)
++		count_have++;
++
++	/* If numbers different something has to be added or removed */
++	if (count != count_have) {
++		return 0;
++	}
++
++	/* Already in berval format, just compare */
++	if (mod->mod_op & LDAP_MOD_BVALUES)
++		return _adcli_ldap_have_vals (mod->mod_vals.modv_bvals, have);
+ 
+ 	vals = malloc (sizeof (struct berval) * (count + 1));
+ 	pvals = malloc (sizeof (struct berval *) * (count + 1));
+diff --git a/tools/computer.c b/tools/computer.c
+index b905fd1..377d449 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -110,6 +110,8 @@ typedef enum {
+ 	opt_add_samba_data,
+ 	opt_samba_data_tool,
+ 	opt_trusted_for_delegation,
++	opt_add_service_principal,
++	opt_remove_service_principal,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+@@ -138,6 +140,8 @@ static adcli_tool_desc common_usages[] = {
+ 	{ opt_computer_password_lifetime, "lifetime of the host accounts password in days", },
+ 	{ opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n"
+ 	                              "in the userAccountControl attribute", },
++	{ opt_add_service_principal, "add the given service principal to the account\n" },
++	{ opt_remove_service_principal, "remove the given service principal from the account\n" },
+ 	{ opt_no_password, "don't prompt for or read a password" },
+ 	{ opt_prompt_password, "prompt for a password if necessary" },
+ 	{ opt_stdin_password, "read a password from stdin (until EOF) if\n"
+@@ -289,6 +293,12 @@ parse_option (Option opt,
+ 			adcli_enroll_set_trusted_for_delegation (enroll, false);
+ 		}
+ 		return;
++	case opt_add_service_principal:
++		adcli_enroll_add_service_principal_to_add (enroll, optarg);
++		return;
++	case opt_remove_service_principal:
++		adcli_enroll_add_service_principal_to_remove (enroll, optarg);
++		return;
+ 	case opt_verbose:
+ 		return;
+ 
+@@ -353,6 +363,7 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 		{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
+ 		{ "user-principal", optional_argument, NULL, opt_user_principal },
+ 		{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
++		{ "add-service-principal", required_argument, NULL, opt_add_service_principal },
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
+ 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+@@ -458,6 +469,8 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 		{ "user-principal", optional_argument, NULL, opt_user_principal },
+ 		{ "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime },
+ 		{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
++		{ "add-service-principal", required_argument, NULL, opt_add_service_principal },
++		{ "remove-service-principal", required_argument, NULL, opt_remove_service_principal },
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
+ 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+-- 
+2.14.4
+
diff --git a/SOURCES/0007-tools-add-option-add-samba-data.patch b/SOURCES/0007-tools-add-option-add-samba-data.patch
new file mode 100644
index 0000000..fee1643
--- /dev/null
+++ b/SOURCES/0007-tools-add-option-add-samba-data.patch
@@ -0,0 +1,142 @@
+From b4fccc5b43bb4d24bbd652bec5bff715dd43b883 Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 14:46:00 +0100
+Subject: [PATCH 7/9] tools: add option --add-samba-data
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ doc/adcli.xml      | 30 ++++++++++++++++++++++++++++++
+ library/adenroll.h |  1 +
+ tools/computer.c   | 12 ++++++++++++
+ 3 files changed, 43 insertions(+)
+
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index c54cc1b..fbc6c63 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -292,6 +292,21 @@ Password for Administrator:
+ 			machine account password. This is output in a format that should
+ 			be both human and machine readable.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--add-samba-data</option></term>
++			<listitem><para>After a successful join add the domain
++			SID and the machine account password to the Samba
++			specific databases by calling Samba's
++			<command>net</command> utility.</para>
++
++			<para>Please note that Samba's <command>net</command>
++			requires some settings in <filename>smb.conf</filename>
++			to create the database entries correctly. Most
++			important here is currently the
++			<option>workgroup</option> option, see
++			<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
++			for details.</para></listitem>
++		</varlistentry>
+ 	</variablelist>
+ 
+ </refsect1>
+@@ -382,6 +397,21 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 			about join operation. This is output in a format that should
+ 			be both human and machine readable.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<term><option>--add-samba-data</option></term>
++			<listitem><para>After a successful join add the domain
++			SID and the machine account password to the Samba
++			specific databases by calling Samba's
++			<command>net</command> utility.</para>
++
++			<para>Please note that Samba's <command>net</command>
++			requires some settings in <filename>smb.conf</filename>
++			to create the database entries correctly. Most
++			important here is currently the
++			<option>workgroup</option> option, see
++			<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
++			for details.</para></listitem>
++		</varlistentry>
+ 	</variablelist>
+ 
+ </refsect1>
+diff --git a/library/adenroll.h b/library/adenroll.h
+index 9a107ab..32c9764 100644
+--- a/library/adenroll.h
++++ b/library/adenroll.h
+@@ -30,6 +30,7 @@ typedef enum {
+ 	ADCLI_ENROLL_NO_KEYTAB = 1 << 1,
+ 	ADCLI_ENROLL_ALLOW_OVERWRITE = 1 << 2,
+ 	ADCLI_ENROLL_PASSWORD_VALID = 1 << 3,
++	ADCLI_ENROLL_ADD_SAMBA_DATA = 1 << 3,
+ } adcli_enroll_flags;
+ 
+ typedef struct _adcli_enroll adcli_enroll;
+diff --git a/tools/computer.c b/tools/computer.c
+index a3d0f03..fc646f2 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -106,6 +106,7 @@ typedef enum {
+ 	opt_os_service_pack,
+ 	opt_user_principal,
+ 	opt_computer_password_lifetime,
++	opt_add_samba_data,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+@@ -142,6 +143,8 @@ static adcli_tool_desc common_usages[] = {
+ 	                     "a successful join" },
+ 	{ opt_show_password, "show computer account password after after a\n"
+ 	                     "successful join" },
++	{ opt_add_samba_data, "add domain SID and computer account password\n"
++	                      "to the Samba specific configuration database" },
+ 	{ opt_verbose, "show verbose progress and failure messages", },
+ 	{ 0 },
+ };
+@@ -269,6 +272,7 @@ parse_option (Option opt,
+ 	case opt_show_details:
+ 	case opt_show_password:
+ 	case opt_one_time_password:
++	case opt_add_samba_data:
+ 		assert (0 && "not reached");
+ 		break;
+ 	}
+@@ -326,6 +330,7 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 		{ "user-principal", optional_argument, NULL, opt_user_principal },
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
++		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+ 		{ "verbose", no_argument, NULL, opt_verbose },
+ 		{ "help", no_argument, NULL, 'h' },
+ 		{ 0 },
+@@ -352,6 +357,9 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 		case opt_show_password:
+ 			show_password = 1;
+ 			break;
++		case opt_add_samba_data:
++			flags |= ADCLI_ENROLL_ADD_SAMBA_DATA;
++			break;
+ 		case 'h':
+ 		case '?':
+ 		case ':':
+@@ -425,6 +433,7 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 		{ "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime },
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
++		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+ 		{ "verbose", no_argument, NULL, opt_verbose },
+ 		{ "help", no_argument, NULL, 'h' },
+ 		{ 0 },
+@@ -447,6 +456,9 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 		case opt_show_password:
+ 			show_password = 1;
+ 			break;
++		case opt_add_samba_data:
++			flags |= ADCLI_ENROLL_ADD_SAMBA_DATA;
++			break;
+ 		case 'h':
+ 		case '?':
+ 		case ':':
+-- 
+2.14.4
+
diff --git a/SOURCES/0008-tools-store-Samba-data-if-requested.patch b/SOURCES/0008-tools-store-Samba-data-if-requested.patch
new file mode 100644
index 0000000..c7d3227
--- /dev/null
+++ b/SOURCES/0008-tools-store-Samba-data-if-requested.patch
@@ -0,0 +1,75 @@
+From 4d46d295458286e4a268f37ea900e58177ac903c Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Tue, 30 Jan 2018 18:24:15 +0100
+Subject: [PATCH 8/9] tools: store Samba data if requested
+
+Use Samba's net utility to add the machine account password and the
+domain SID to the Samba configuration.
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ library/adenroll.c | 39 +++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 39 insertions(+)
+
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 40c3920..6b1aae5 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -1533,6 +1533,36 @@ update_keytab_for_principals (adcli_enroll *enroll)
+ 	return ADCLI_SUCCESS;
+ }
+ 
++static adcli_result
++update_samba_data (adcli_enroll *enroll)
++{
++	int ret;
++	char *argv_pw[] = { "/usr/bin/net", "changesecretpw", "-i", "-f", NULL };
++	char *argv_sid[] = { "/usr/bin/net", "setdomainsid", NULL, NULL };
++
++	_adcli_info ("Trying to set Samba secret.\n");
++	ret = _adcli_call_external_program (argv_pw[0], argv_pw,
++	                                    enroll->computer_password, NULL, NULL);
++	if (ret != ADCLI_SUCCESS) {
++		_adcli_err ("Failed to set Samba computer account password.\n");
++	}
++
++	argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
++	if (argv_sid[2] == NULL) {
++		_adcli_err ("Domain SID not available.\n");
++	} else {
++		_adcli_info ("Trying to set domain SID %s for Samba.\n",
++		             argv_sid[2]);
++		ret = _adcli_call_external_program (argv_sid[0], argv_sid,
++		                                    NULL, NULL, NULL);
++		if (ret != ADCLI_SUCCESS) {
++			_adcli_err ("Failed to set Samba domain SID.\n");
++		}
++	}
++
++	return ret;
++}
++
+ static void
+ enroll_clear_state (adcli_enroll *enroll)
+ {
+@@ -1687,6 +1717,15 @@ enroll_join_or_update_tasks (adcli_enroll *enroll,
+ 	update_computer_account (enroll);
+ 	update_service_principals (enroll);
+ 
++	if ( (flags & ADCLI_ENROLL_ADD_SAMBA_DATA) && ! (flags & ADCLI_ENROLL_PASSWORD_VALID)) {
++		res = update_samba_data (enroll);
++		if (res != ADCLI_SUCCESS) {
++			_adcli_info ("Failed to add Samba specific data, smbd "
++			             "or winbindd might not work as "
++			             "expected.\n");
++		}
++	}
++
+ 	if (flags & ADCLI_ENROLL_NO_KEYTAB)
+ 		return ADCLI_SUCCESS;
+ 
+-- 
+2.14.4
+
diff --git a/SOURCES/0009-make-Samba-data-tool-configurable.patch b/SOURCES/0009-make-Samba-data-tool-configurable.patch
new file mode 100644
index 0000000..209b591
--- /dev/null
+++ b/SOURCES/0009-make-Samba-data-tool-configurable.patch
@@ -0,0 +1,292 @@
+From c0784106a839c2686e01c75472bae2e7d9071c8b Mon Sep 17 00:00:00 2001
+From: Sumit Bose <sbose@redhat.com>
+Date: Thu, 1 Feb 2018 14:26:22 +0100
+Subject: [PATCH 9/9] make Samba data tool configurable
+
+Allow to specify an alternative path to Samba's net utility at configure
+time and at run time.
+
+https://bugs.freedesktop.org/show_bug.cgi?id=100118
+
+Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
+---
+ configure.ac                    | 13 ++++++++++++
+ doc/adcli.xml                   | 21 ++++++++++++++++++-
+ doc/samba_data_tool_path.xml.in |  1 +
+ library/adenroll.c              | 46 ++++++++++++++++++++++++++++++++++-------
+ library/adenroll.h              |  5 +++++
+ tools/computer.c                | 16 ++++++++++++++
+ 7 files changed, 95 insertions(+), 8 deletions(-)
+ create mode 100644 doc/samba_data_tool_path.xml.in
+
+diff --git a/configure.ac b/configure.ac
+index fe86638..68877c7 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -291,6 +291,18 @@ else
+ 	AC_DEFINE_UNQUOTED(BIN_ECHO, "$BIN_ECHO", [path to echo, used in unit test])
+ fi
+ 
++AC_MSG_CHECKING([where is Samba's net utility])
++AC_ARG_WITH([samba_data_tool],
++              AC_HELP_STRING([--with-samba-data-tool=/path],
++              [Path to Samba's net utility]),
++              [],
++              [with_samba_data_tool=/usr/bin/net])
++AC_MSG_RESULT([$with_samba_data_tool])
++
++AC_DEFINE_UNQUOTED(SAMBA_DATA_TOOL, "$with_samba_data_tool",
++                   [Path to Samba's net utility])
++
++AC_SUBST(SAMBA_DATA_TOOL, [$with_samba_data_tool])
+ # ---------------------------------------------------------------------
+ 
+ ADCLI_LT_RELEASE=$ADCLI_CURRENT:$ADCLI_REVISION:$ADCLI_AGE
+@@ -300,6 +312,7 @@ AC_CONFIG_FILES([Makefile
+ 	build/Makefile
+ 	doc/Makefile
+ 	doc/version.xml
++	doc/samba_data_tool_path.xml
+ 	library/Makefile
+ 	tools/Makefile
+ ])
+diff --git a/doc/adcli.xml b/doc/adcli.xml
+index fbc6c63..c2b7760 100644
+--- a/doc/adcli.xml
++++ b/doc/adcli.xml
+@@ -1,6 +1,9 @@
+ <?xml version='1.0'?>
+ <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
+-	"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
++	"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
++[
++	<!ENTITY samba_data_tool SYSTEM "samba_data_tool_path.xml">
++]>
+ 
+ <refentry id="adcli">
+ 
+@@ -307,6 +310,14 @@ Password for Administrator:
+ 			<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ 			for details.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<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
++			be used to specific an alternative location with the
++			help of an absolute path.</para></listitem>
++		</varlistentry>
+ 	</variablelist>
+ 
+ </refsect1>
+@@ -412,6 +423,14 @@ $ adcli update --login-ccache=/tmp/krbcc_123
+ 			<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ 			for details.</para></listitem>
+ 		</varlistentry>
++		<varlistentry>
++			<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
++			be used to specific an alternative location with the
++			help of an absolute path.</para></listitem>
++		</varlistentry>
+ 	</variablelist>
+ 
+ </refsect1>
+diff --git a/doc/samba_data_tool_path.xml.in b/doc/samba_data_tool_path.xml.in
+new file mode 100644
+index 0000000..a667c57
+--- /dev/null
++++ b/doc/samba_data_tool_path.xml.in
+@@ -0,0 +1 @@
++@SAMBA_DATA_TOOL@
+diff --git a/library/adenroll.c b/library/adenroll.c
+index 6b1aae5..d64c2c0 100644
+--- a/library/adenroll.c
++++ b/library/adenroll.c
+@@ -42,6 +42,10 @@
+ #include <stdio.h>
+ #include <unistd.h>
+ 
++#ifndef SAMBA_DATA_TOOL
++#define SAMBA_DATA_TOOL "/usr/bin/net"
++#endif
++
+ static krb5_enctype v60_later_enctypes[] = {
+ 	ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+ 	ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+@@ -100,6 +104,7 @@ struct _adcli_enroll {
+ 	int keytab_enctypes_explicit;
+ 	unsigned int computer_password_lifetime;
+ 	int computer_password_lifetime_explicit;
++	char *samba_data_tool;
+ };
+ 
+ static adcli_result
+@@ -1537,26 +1542,33 @@ static adcli_result
+ update_samba_data (adcli_enroll *enroll)
+ {
+ 	int ret;
+-	char *argv_pw[] = { "/usr/bin/net", "changesecretpw", "-i", "-f", NULL };
+-	char *argv_sid[] = { "/usr/bin/net", "setdomainsid", NULL, NULL };
++	char *argv_pw[] = { NULL, "changesecretpw", "-i", "-f", NULL };
++	char *argv_sid[] = { NULL, "setdomainsid", NULL, NULL };
++
++	argv_pw[0] = (char *) adcli_enroll_get_samba_data_tool (enroll);
++	if (argv_pw[0] ==NULL) {
++		_adcli_err ("Samba data tool not available.");
++		return ADCLI_ERR_FAIL;
++	}
++	argv_sid[0] = argv_pw[0];
+ 
+-	_adcli_info ("Trying to set Samba secret.\n");
++	_adcli_info ("Trying to set Samba secret.");
+ 	ret = _adcli_call_external_program (argv_pw[0], argv_pw,
+ 	                                    enroll->computer_password, NULL, NULL);
+ 	if (ret != ADCLI_SUCCESS) {
+-		_adcli_err ("Failed to set Samba computer account password.\n");
++		_adcli_err ("Failed to set Samba computer account password.");
+ 	}
+ 
+ 	argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
+ 	if (argv_sid[2] == NULL) {
+-		_adcli_err ("Domain SID not available.\n");
++		_adcli_err ("Domain SID not available.");
+ 	} else {
+-		_adcli_info ("Trying to set domain SID %s for Samba.\n",
++		_adcli_info ("Trying to set domain SID %s for Samba.",
+ 		             argv_sid[2]);
+ 		ret = _adcli_call_external_program (argv_sid[0], argv_sid,
+ 		                                    NULL, NULL, NULL);
+ 		if (ret != ADCLI_SUCCESS) {
+-			_adcli_err ("Failed to set Samba domain SID.\n");
++			_adcli_err ("Failed to set Samba domain SID.");
+ 		}
+ 	}
+ 
+@@ -1951,6 +1963,9 @@ adcli_enroll_new (adcli_conn *conn)
+ 	enroll->os_name = strdup (value);
+ 	return_val_if_fail (enroll->os_name != NULL, NULL);
+ 
++	enroll->samba_data_tool = strdup (SAMBA_DATA_TOOL);
++	return_val_if_fail (enroll->samba_data_tool != NULL, NULL);
++
+ 	return enroll;
+ }
+ 
+@@ -1978,6 +1993,7 @@ enroll_free (adcli_enroll *enroll)
+ 	free (enroll->os_name);
+ 	free (enroll->os_version);
+ 	free (enroll->os_service_pack);
++	free (enroll->samba_data_tool);
+ 
+ 	free (enroll->user_principal);
+ 	_adcli_strv_free (enroll->service_names);
+@@ -2343,3 +2359,19 @@ adcli_enroll_set_computer_password_lifetime (adcli_enroll *enroll,
+ 
+ 	enroll->computer_password_lifetime_explicit = 1;
+ }
++
++void
++adcli_enroll_set_samba_data_tool (adcli_enroll *enroll, const char *value)
++{
++	return_if_fail (enroll != NULL);
++	if (value != NULL && value[0] != '\0') {
++		_adcli_str_set (&enroll->samba_data_tool, value);
++	}
++}
++
++const char *
++adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
++{
++	return_val_if_fail (enroll != NULL, NULL);
++	return enroll->samba_data_tool;
++}
+diff --git a/library/adenroll.h b/library/adenroll.h
+index 32c9764..31ca0bc 100644
+--- a/library/adenroll.h
++++ b/library/adenroll.h
+@@ -141,4 +141,9 @@ const char *       adcli_enroll_get_os_service_pack     (adcli_enroll *enroll);
+ void               adcli_enroll_set_os_service_pack     (adcli_enroll *enroll,
+                                                          const char *value);
+ 
++void               adcli_enroll_set_samba_data_tool     (adcli_enroll *enroll,
++                                                         const char *value);
++
++const char *       adcli_enroll_get_samba_data_tool     (adcli_enroll *enroll);
++
+ #endif /* ADENROLL_H_ */
+diff --git a/tools/computer.c b/tools/computer.c
+index fc646f2..f86548b 100644
+--- a/tools/computer.c
++++ b/tools/computer.c
+@@ -30,6 +30,7 @@
+ #include <err.h>
+ #include <stdio.h>
+ #include <errno.h>
++#include <unistd.h>
+ 
+ static void
+ dump_details (adcli_conn *conn,
+@@ -107,6 +108,7 @@ typedef enum {
+ 	opt_user_principal,
+ 	opt_computer_password_lifetime,
+ 	opt_add_samba_data,
++	opt_samba_data_tool,
+ } Option;
+ 
+ static adcli_tool_desc common_usages[] = {
+@@ -145,6 +147,7 @@ static adcli_tool_desc common_usages[] = {
+ 	                     "successful join" },
+ 	{ opt_add_samba_data, "add domain SID and computer account password\n"
+ 	                      "to the Samba specific configuration database" },
++	{ opt_samba_data_tool, "Absolute path to the tool used for add-samba-data" },
+ 	{ opt_verbose, "show verbose progress and failure messages", },
+ 	{ 0 },
+ };
+@@ -160,6 +163,7 @@ parse_option (Option opt,
+ 	static int stdin_password = 0;
+ 	char *endptr;
+ 	unsigned int lifetime;
++	int ret;
+ 
+ 	switch (opt) {
+ 	case opt_login_ccache:
+@@ -265,6 +269,16 @@ parse_option (Option opt,
+ 
+ 		adcli_enroll_set_computer_password_lifetime (enroll, lifetime);
+ 		return;
++	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));
++		} else {
++			adcli_enroll_set_samba_data_tool (enroll, optarg);
++		}
++		return;
+ 	case opt_verbose:
+ 		return;
+ 
+@@ -331,6 +345,7 @@ adcli_tool_computer_join (adcli_conn *conn,
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
+ 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
++		{ "samba-data-tool", no_argument, NULL, opt_samba_data_tool },
+ 		{ "verbose", no_argument, NULL, opt_verbose },
+ 		{ "help", no_argument, NULL, 'h' },
+ 		{ 0 },
+@@ -434,6 +449,7 @@ adcli_tool_computer_update (adcli_conn *conn,
+ 		{ "show-details", no_argument, NULL, opt_show_details },
+ 		{ "show-password", no_argument, NULL, opt_show_password },
+ 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
++		{ "samba-data-tool", no_argument, NULL, opt_samba_data_tool },
+ 		{ "verbose", no_argument, NULL, opt_verbose },
+ 		{ "help", no_argument, NULL, 'h' },
+ 		{ 0 },
+-- 
+2.14.4
+
diff --git a/SPECS/adcli.spec b/SPECS/adcli.spec
index c191b55..138c688 100644
--- a/SPECS/adcli.spec
+++ b/SPECS/adcli.spec
@@ -1,6 +1,6 @@
 Name:		adcli
 Version:	0.8.1
-Release:	4%{?dist}
+Release:	6%{?dist}
 Summary:	Active Directory enrollment
 License:	LGPLv2+
 URL:		http://cgit.freedesktop.org/realmd/adcli
@@ -17,8 +17,37 @@ Patch9:         0002-doc-explain-that-all-credential-cache-types-are-supp.patch
 Patch10:        0003-library-add-adcli_conn_is_writeable.patch
 Patch11:        0004-Handle-kvno-increment-for-RODCs.patch
 
+Patch12:        0001-Fix-memory-leak-in-test_check_nt_time_string_lifetim.patch
+Patch13:        0002-library-add-_adcli_bin_sid_to_str.patch
+Patch14:        0003-library-add-_adcli_call_external_program.patch
+Patch15:        0004-library-add-_adcli_ldap_parse_sid.patch
+Patch16:        0005-library-add-lookup_domain_sid.patch
+Patch17:        0006-library-add-adcli_conn_get_domain_sid.patch
+Patch18:        0007-tools-add-option-add-samba-data.patch
+Patch19:        0008-tools-store-Samba-data-if-requested.patch
+Patch20:        0009-make-Samba-data-tool-configurable.patch
+
+Patch21:        0001-Add-trusted-for-delegation-option.patch
+Patch22:        0002-Only-update-attributes-given-on-the-command-line.patch
+Patch23:        0003-update-allow-to-add-service-names.patch
+Patch24:        0004-Calculate-enctypes-in-a-separate-function.patch
+Patch25:        0005-join-add-all-attributes-while-creating-computer-obje.patch
+Patch26:        0006-util-add-_adcli_strv_remove_unsorted.patch
+Patch27:        0007-Add-add-service-principal-and-remove-service-princip.patch
+Patch28:        0001-adcli_conn_is_writeable-do-not-crash-id-domain_disco.patch
+
+# Additional fixes for rhbz#1593240
+Patch29:        0001-fix-typo-in-flag-value.patch
+Patch30:        0002-_adcli_call_external_program-silence-noisy-debug-mes.patch
+
+# rhbz#1608212
+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
 
 BuildRequires:	intltool pkgconfig
+BuildRequires:	libtool
 BuildRequires:	gettext-devel
 BuildRequires:	krb5-devel
 BuildRequires:	openldap-devel
@@ -50,8 +79,30 @@ standard LDAP and Kerberos calls.
 %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
 
 %build
+autoreconf --force --install --verbose
 %configure --disable-static --disable-silent-rules
 make %{?_smp_mflags}
 
@@ -75,6 +126,18 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
 %doc %{_mandir}/*/*
 
 %changelog
+* Tue Aug 14 2018 Sumit Bose <sbose@redhat.com> - 0.8.1-6
+- Couldn't set service principals on computer account [#1608212]
+- additional fix #1547014 and #1593240
+
+* Tue Jun 19 2018 Sumit Bose <sbose@redhat.com> - 0.8.1-5
+- enable "Trust this computer for delegation to any service (Kerberos only)" [#1538730]
+- realm join fails with Insufficient permissions [#1542354]
+- adcli update option cannot add principals for computer object [#1545568]
+- adcli refuses to add service principals [#1547013]
+- [RFE] Support adding SPN of a different host [#1547014]
+- adcli segfaults during AD join RHEL 7.5 [#1575554]
+
 * Thu Nov 02 2017 Sumit Bose <sbose@redhat.com> - 0.8.1-4
 - adcli doesn't update kvno while joining system to AD domain (RODC) [#1471021]
 - adcli_tool_computer_delete description spelling [#1450179]