Sumit Bose 461678
From ee71c4c0614a504b4472bf64a24fc3c18c6b9987 Mon Sep 17 00:00:00 2001
Sumit Bose 461678
From: Sumit Bose <sbose@redhat.com>
Sumit Bose 461678
Date: Thu, 14 Jun 2018 16:49:26 +0200
Sumit Bose 461678
Subject: [PATCH 22/23] Add add-service-principal and remove-service-principal
Sumit Bose 461678
 options
Sumit Bose 461678
Sumit Bose 461678
Currently it is only possible to specific a service name for service
Sumit Bose 461678
principals but not to set the full service principal. This is e.g.
Sumit Bose 461678
needed if there is a service running on a host which should be reachable
Sumit Bose 461678
by a different DNS name as well.
Sumit Bose 461678
Sumit Bose 461678
With this patch service principal can be added and removed by specifying
Sumit Bose 461678
the full name.
Sumit Bose 461678
Sumit Bose 461678
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1547014
Sumit Bose 461678
---
Sumit Bose 461678
 doc/adcli.xml      |  21 ++++++++
Sumit Bose 461678
 library/adenroll.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++--
Sumit Bose 461678
 library/adenroll.h |   8 +++
Sumit Bose 461678
 library/adldap.c   |  16 ++++--
Sumit Bose 461678
 tools/computer.c   |  13 +++++
Sumit Bose 461678
 5 files changed, 189 insertions(+), 8 deletions(-)
Sumit Bose 461678
Sumit Bose 461678
diff --git a/doc/adcli.xml b/doc/adcli.xml
Sumit Bose 461678
index b246190..83b6981 100644
Sumit Bose 461678
--- a/doc/adcli.xml
Sumit Bose 461678
+++ b/doc/adcli.xml
Sumit Bose 461678
@@ -290,6 +290,14 @@ Password for Administrator:
Sumit Bose 461678
 			not allow that Kerberos tickets can be forwarded to the
Sumit Bose 461678
 			host.</para></listitem>
Sumit Bose 461678
 		</varlistentry>
Sumit Bose 461678
+		<varlistentry>
Sumit Bose 461678
+			<term><option>--add-service-principal=<parameter>service/hostname</parameter></option></term>
Sumit Bose 461678
+			<listitem><para>Add a service principal name. In
Sumit Bose 461678
+			contrast to the <option>--service-name</option> the
Sumit Bose 461678
+			hostname part can be specified as well in case the
Sumit Bose 461678
+			service should be accessible with a different host
Sumit Bose 461678
+			name as well.</para></listitem>
Sumit Bose 461678
+		</varlistentry>
Sumit Bose 461678
 		<varlistentry>
Sumit Bose 461678
 			<term><option>--show-details</option></term>
Sumit Bose 461678
 			<listitem><para>After a successful join print out information
Sumit Bose 461678
@@ -416,6 +424,19 @@ $ adcli update --login-ccache=/tmp/krbcc_123
Sumit Bose 461678
 			not allow that Kerberos tickets can be forwarded to the
Sumit Bose 461678
 			host.</para></listitem>
Sumit Bose 461678
 		</varlistentry>
Sumit Bose 461678
+		<varlistentry>
Sumit Bose 461678
+			<term><option>--add-service-principal=<parameter>service/hostname</parameter></option></term>
Sumit Bose 461678
+			<listitem><para>Add a service principal name. In
Sumit Bose 461678
+			contrast to the <option>--service-name</option> the
Sumit Bose 461678
+			hostname part can be specified as well in case the
Sumit Bose 461678
+			service should be accessible with a different host
Sumit Bose 461678
+			name as well.</para></listitem>
Sumit Bose 461678
+		</varlistentry>
Sumit Bose 461678
+		<varlistentry>
Sumit Bose 461678
+			<term><option>--remove-service-principal=<parameter>service/hostname</parameter></option></term>
Sumit Bose 461678
+			<listitem><para>Remove a service principal name from
Sumit Bose 461678
+			the keytab and the AD host object.</para></listitem>
Sumit Bose 461678
+		</varlistentry>
Sumit Bose 461678
 		<varlistentry>
Sumit Bose 461678
 			<term><option>--show-details</option></term>
Sumit Bose 461678
 			<listitem><para>After a successful join print out information
Sumit Bose 461678
diff --git a/library/adenroll.c b/library/adenroll.c
Sumit Bose 461678
index b508caf..c4ba537 100644
Sumit Bose 461678
--- a/library/adenroll.c
Sumit Bose 461678
+++ b/library/adenroll.c
Sumit Bose 461678
@@ -95,6 +95,9 @@ struct _adcli_enroll {
Sumit Bose 461678
 	char **service_principals;
Sumit Bose 461678
 	int service_principals_explicit;
Sumit Bose 461678
 
Sumit Bose 461678
+	char **service_principals_to_add;
Sumit Bose 461678
+	char **service_principals_to_remove;
Sumit Bose 461678
+
Sumit Bose 461678
 	char *user_principal;
Sumit Bose 461678
 	int user_princpal_generate;
Sumit Bose 461678
 
Sumit Bose 461678
@@ -332,6 +335,43 @@ add_service_names_to_service_principals (adcli_enroll *enroll)
Sumit Bose 461678
 	return ADCLI_SUCCESS;
Sumit Bose 461678
 }
Sumit Bose 461678
 
Sumit Bose 461678
+static adcli_result
Sumit Bose 461678
+add_and_remove_service_principals (adcli_enroll *enroll)
Sumit Bose 461678
+{
Sumit Bose 461678
+	int length = 0;
Sumit Bose 461678
+	size_t c;
Sumit Bose 461678
+	const char **list;
Sumit Bose 461678
+
Sumit Bose 461678
+	if (enroll->service_principals != NULL) {
Sumit Bose 461678
+		length = seq_count (enroll->service_principals);
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	list = adcli_enroll_get_service_principals_to_add (enroll);
Sumit Bose 461678
+	if (list != NULL) {
Sumit Bose 461678
+		for (c = 0; list[c] != NULL; c++) {
Sumit Bose 461678
+			enroll->service_principals = _adcli_strv_add (enroll->service_principals,
Sumit Bose 461678
+			                                              strdup (list[c]),
Sumit Bose 461678
+			                                              &length);
Sumit Bose 461678
+			if (enroll->service_principals == NULL) {
Sumit Bose 461678
+				return ADCLI_ERR_UNEXPECTED;
Sumit Bose 461678
+			}
Sumit Bose 461678
+		}
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	list = adcli_enroll_get_service_principals_to_remove (enroll);
Sumit Bose 461678
+	if (list != NULL) {
Sumit Bose 461678
+		for (c = 0; list[c] != NULL; c++) {
Sumit Bose 461678
+			/* enroll->service_principals typically refects the
Sumit Bose 461678
+			 * order of the principal in the keytabm so it is not
Sumit Bose 461678
+			 * ordered. */
Sumit Bose 461678
+			_adcli_strv_remove_unsorted (enroll->service_principals,
Sumit Bose 461678
+			                             list[c], &length);
Sumit Bose 461678
+		}
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	return ADCLI_SUCCESS;
Sumit Bose 461678
+}
Sumit Bose 461678
+
Sumit Bose 461678
 static adcli_result
Sumit Bose 461678
 ensure_service_principals (adcli_result res,
Sumit Bose 461678
                            adcli_enroll *enroll)
Sumit Bose 461678
@@ -343,10 +383,14 @@ ensure_service_principals (adcli_result res,
Sumit Bose 461678
 
Sumit Bose 461678
 	if (!enroll->service_principals) {
Sumit Bose 461678
 		assert (enroll->service_names != NULL);
Sumit Bose 461678
-		return add_service_names_to_service_principals (enroll);
Sumit Bose 461678
+		res = add_service_names_to_service_principals (enroll);
Sumit Bose 461678
 	}
Sumit Bose 461678
 
Sumit Bose 461678
-	return ADCLI_SUCCESS;
Sumit Bose 461678
+	if (res == ADCLI_SUCCESS) {
Sumit Bose 461678
+		res = add_and_remove_service_principals (enroll);
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	return res;
Sumit Bose 461678
 }
Sumit Bose 461678
 
Sumit Bose 461678
 static adcli_result
Sumit Bose 461678
@@ -1593,6 +1637,39 @@ free_principal_salts (krb5_context k5,
Sumit Bose 461678
 	free (salts);
Sumit Bose 461678
 }
Sumit Bose 461678
 
Sumit Bose 461678
+static adcli_result
Sumit Bose 461678
+remove_principal_from_keytab (adcli_enroll *enroll,
Sumit Bose 461678
+                              krb5_context k5,
Sumit Bose 461678
+                              const char *principal_name)
Sumit Bose 461678
+{
Sumit Bose 461678
+	krb5_error_code code;
Sumit Bose 461678
+	krb5_principal principal;
Sumit Bose 461678
+	match_principal_kvno closure;
Sumit Bose 461678
+
Sumit Bose 461678
+	code = krb5_parse_name (k5, principal_name, &principal);
Sumit Bose 461678
+	if (code != 0) {
Sumit Bose 461678
+		_adcli_err ("Couldn't parse principal: %s: %s",
Sumit Bose 461678
+		            principal_name, krb5_get_error_message (k5, code));
Sumit Bose 461678
+		return ADCLI_ERR_FAIL;
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	closure.kvno = enroll->kvno;
Sumit Bose 461678
+	closure.principal = principal;
Sumit Bose 461678
+	closure.matched = 0;
Sumit Bose 461678
+
Sumit Bose 461678
+	code = _adcli_krb5_keytab_clear (k5, enroll->keytab,
Sumit Bose 461678
+	                                 match_principal_and_kvno, &closure);
Sumit Bose 461678
+	krb5_free_principal (k5, principal);
Sumit Bose 461678
+
Sumit Bose 461678
+	if (code != 0) {
Sumit Bose 461678
+		_adcli_err ("Couldn't update keytab: %s: %s",
Sumit Bose 461678
+		            enroll->keytab_name, krb5_get_error_message (k5, code));
Sumit Bose 461678
+		return ADCLI_ERR_FAIL;
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	return ADCLI_SUCCESS;
Sumit Bose 461678
+}
Sumit Bose 461678
+
Sumit Bose 461678
 static adcli_result
Sumit Bose 461678
 add_principal_to_keytab (adcli_enroll *enroll,
Sumit Bose 461678
                          krb5_context k5,
Sumit Bose 461678
@@ -1702,6 +1779,17 @@ update_keytab_for_principals (adcli_enroll *enroll,
Sumit Bose 461678
 			return res;
Sumit Bose 461678
 	}
Sumit Bose 461678
 
Sumit Bose 461678
+	if (enroll->service_principals_to_remove != NULL) {
Sumit Bose 461678
+		for (i = 0; enroll->service_principals_to_remove[i] != NULL; i++) {
Sumit Bose 461678
+			res = remove_principal_from_keytab (enroll, k5,
Sumit Bose 461678
+			                                    enroll->service_principals_to_remove[i]);
Sumit Bose 461678
+			if (res != ADCLI_SUCCESS) {
Sumit Bose 461678
+				_adcli_warn ("Failed to remove %s from keytab.",
Sumit Bose 461678
+				             enroll->service_principals_to_remove[i]);
Sumit Bose 461678
+			}
Sumit Bose 461678
+		}
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
 	return ADCLI_SUCCESS;
Sumit Bose 461678
 }
Sumit Bose 461678
 
Sumit Bose 461678
@@ -2029,8 +2117,11 @@ adcli_enroll_update (adcli_enroll *enroll,
Sumit Bose 461678
 	if (_adcli_check_nt_time_string_lifetime (value,
Sumit Bose 461678
 	                adcli_enroll_get_computer_password_lifetime (enroll))) {
Sumit Bose 461678
 		/* Do not update keytab if neither new service principals have
Sumit Bose 461678
-                 * to be added nor the user principal has to be changed. */
Sumit Bose 461678
-		if (enroll->service_names == NULL && (enroll->user_principal == NULL || enroll->user_princpal_generate)) {
Sumit Bose 461678
+                 * to be added or deleted nor the user principal has to be changed. */
Sumit Bose 461678
+		if (enroll->service_names == NULL
Sumit Bose 461678
+		              && (enroll->user_principal == NULL || enroll->user_princpal_generate)
Sumit Bose 461678
+		              && enroll->service_principals_to_add == NULL
Sumit Bose 461678
+		              && enroll->service_principals_to_remove == NULL) {
Sumit Bose 461678
 			flags |= ADCLI_ENROLL_NO_KEYTAB;
Sumit Bose 461678
 		}
Sumit Bose 461678
 		flags |= ADCLI_ENROLL_PASSWORD_VALID;
Sumit Bose 461678
@@ -2581,3 +2672,43 @@ adcli_enroll_set_trusted_for_delegation (adcli_enroll *enroll,
Sumit Bose 461678
 	enroll->trusted_for_delegation = value;
Sumit Bose 461678
 	enroll->trusted_for_delegation_explicit = 1;
Sumit Bose 461678
 }
Sumit Bose 461678
+
Sumit Bose 461678
+const char **
Sumit Bose 461678
+adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll)
Sumit Bose 461678
+{
Sumit Bose 461678
+	return_val_if_fail (enroll != NULL, NULL);
Sumit Bose 461678
+
Sumit Bose 461678
+	return (const char **)enroll->service_principals_to_add;
Sumit Bose 461678
+}
Sumit Bose 461678
+
Sumit Bose 461678
+void
Sumit Bose 461678
+adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
Sumit Bose 461678
+                                           const char *value)
Sumit Bose 461678
+{
Sumit Bose 461678
+	return_if_fail (enroll != NULL);
Sumit Bose 461678
+	return_if_fail (value != NULL);
Sumit Bose 461678
+
Sumit Bose 461678
+	enroll->service_principals_to_add = _adcli_strv_add (enroll->service_principals_to_add,
Sumit Bose 461678
+							    strdup (value), NULL);
Sumit Bose 461678
+	return_if_fail (enroll->service_principals_to_add != NULL);
Sumit Bose 461678
+}
Sumit Bose 461678
+
Sumit Bose 461678
+const char **
Sumit Bose 461678
+adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll)
Sumit Bose 461678
+{
Sumit Bose 461678
+	return_val_if_fail (enroll != NULL, NULL);
Sumit Bose 461678
+
Sumit Bose 461678
+	return (const char **)enroll->service_principals_to_remove;
Sumit Bose 461678
+}
Sumit Bose 461678
+
Sumit Bose 461678
+void
Sumit Bose 461678
+adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
Sumit Bose 461678
+                                              const char *value)
Sumit Bose 461678
+{
Sumit Bose 461678
+	return_if_fail (enroll != NULL);
Sumit Bose 461678
+	return_if_fail (value != NULL);
Sumit Bose 461678
+
Sumit Bose 461678
+	enroll->service_principals_to_remove = _adcli_strv_add (enroll->service_principals_to_remove,
Sumit Bose 461678
+							    strdup (value), NULL);
Sumit Bose 461678
+	return_if_fail (enroll->service_principals_to_remove != NULL);
Sumit Bose 461678
+}
Sumit Bose 461678
diff --git a/library/adenroll.h b/library/adenroll.h
Sumit Bose 461678
index be2ca18..f87dffa 100644
Sumit Bose 461678
--- a/library/adenroll.h
Sumit Bose 461678
+++ b/library/adenroll.h
Sumit Bose 461678
@@ -98,6 +98,14 @@ const char **      adcli_enroll_get_service_principals  (adcli_enroll *enroll);
Sumit Bose 461678
 void               adcli_enroll_set_service_principals  (adcli_enroll *enroll,
Sumit Bose 461678
                                                          const char **value);
Sumit Bose 461678
 
Sumit Bose 461678
+const char **      adcli_enroll_get_service_principals_to_add (adcli_enroll *enroll);
Sumit Bose 461678
+void               adcli_enroll_add_service_principal_to_add (adcli_enroll *enroll,
Sumit Bose 461678
+                                                              const char *value);
Sumit Bose 461678
+
Sumit Bose 461678
+const char **      adcli_enroll_get_service_principals_to_remove (adcli_enroll *enroll);
Sumit Bose 461678
+void               adcli_enroll_add_service_principal_to_remove (adcli_enroll *enroll,
Sumit Bose 461678
+                                                                 const char *value);
Sumit Bose 461678
+
Sumit Bose 461678
 const char *       adcli_enroll_get_user_principal      (adcli_enroll *enroll);
Sumit Bose 461678
 
Sumit Bose 461678
 void               adcli_enroll_set_user_principal      (adcli_enroll *enroll,
Sumit Bose 461678
diff --git a/library/adldap.c b/library/adldap.c
Sumit Bose 461678
index 07dc373..d93efb7 100644
Sumit Bose 461678
--- a/library/adldap.c
Sumit Bose 461678
+++ b/library/adldap.c
Sumit Bose 461678
@@ -210,16 +210,24 @@ _adcli_ldap_have_in_mod (LDAPMod *mod,
Sumit Bose 461678
 	struct berval *vals;
Sumit Bose 461678
 	struct berval **pvals;
Sumit Bose 461678
 	int count = 0;
Sumit Bose 461678
+	int count_have = 0;
Sumit Bose 461678
 	int i;
Sumit Bose 461678
 	int ret;
Sumit Bose 461678
 
Sumit Bose 461678
-	/* Already in berval format, just compare */
Sumit Bose 461678
-	if (mod->mod_op & LDAP_MOD_BVALUES)
Sumit Bose 461678
-		return _adcli_ldap_have_vals (mod->mod_vals.modv_bvals, have);
Sumit Bose 461678
-
Sumit Bose 461678
 	/* Count number of values */
Sumit Bose 461678
 	for (i = 0; mod->mod_vals.modv_strvals[i] != 0; i++)
Sumit Bose 461678
 		count++;
Sumit Bose 461678
+	for (i = 0; have[i] != 0; i++)
Sumit Bose 461678
+		count_have++;
Sumit Bose 461678
+
Sumit Bose 461678
+	/* If numbers different something has to be added or removed */
Sumit Bose 461678
+	if (count != count_have) {
Sumit Bose 461678
+		return 0;
Sumit Bose 461678
+	}
Sumit Bose 461678
+
Sumit Bose 461678
+	/* Already in berval format, just compare */
Sumit Bose 461678
+	if (mod->mod_op & LDAP_MOD_BVALUES)
Sumit Bose 461678
+		return _adcli_ldap_have_vals (mod->mod_vals.modv_bvals, have);
Sumit Bose 461678
 
Sumit Bose 461678
 	vals = malloc (sizeof (struct berval) * (count + 1));
Sumit Bose 461678
 	pvals = malloc (sizeof (struct berval *) * (count + 1));
Sumit Bose 461678
diff --git a/tools/computer.c b/tools/computer.c
Sumit Bose 461678
index b905fd1..377d449 100644
Sumit Bose 461678
--- a/tools/computer.c
Sumit Bose 461678
+++ b/tools/computer.c
Sumit Bose 461678
@@ -110,6 +110,8 @@ typedef enum {
Sumit Bose 461678
 	opt_add_samba_data,
Sumit Bose 461678
 	opt_samba_data_tool,
Sumit Bose 461678
 	opt_trusted_for_delegation,
Sumit Bose 461678
+	opt_add_service_principal,
Sumit Bose 461678
+	opt_remove_service_principal,
Sumit Bose 461678
 } Option;
Sumit Bose 461678
 
Sumit Bose 461678
 static adcli_tool_desc common_usages[] = {
Sumit Bose 461678
@@ -138,6 +140,8 @@ static adcli_tool_desc common_usages[] = {
Sumit Bose 461678
 	{ opt_computer_password_lifetime, "lifetime of the host accounts password in days", },
Sumit Bose 461678
 	{ opt_trusted_for_delegation, "set/unset the TRUSTED_FOR_DELEGATION flag\n"
Sumit Bose 461678
 	                              "in the userAccountControl attribute", },
Sumit Bose 461678
+	{ opt_add_service_principal, "add the given service principal to the account\n" },
Sumit Bose 461678
+	{ opt_remove_service_principal, "remove the given service principal from the account\n" },
Sumit Bose 461678
 	{ opt_no_password, "don't prompt for or read a password" },
Sumit Bose 461678
 	{ opt_prompt_password, "prompt for a password if necessary" },
Sumit Bose 461678
 	{ opt_stdin_password, "read a password from stdin (until EOF) if\n"
Sumit Bose 461678
@@ -289,6 +293,12 @@ parse_option (Option opt,
Sumit Bose 461678
 			adcli_enroll_set_trusted_for_delegation (enroll, false);
Sumit Bose 461678
 		}
Sumit Bose 461678
 		return;
Sumit Bose 461678
+	case opt_add_service_principal:
Sumit Bose 461678
+		adcli_enroll_add_service_principal_to_add (enroll, optarg);
Sumit Bose 461678
+		return;
Sumit Bose 461678
+	case opt_remove_service_principal:
Sumit Bose 461678
+		adcli_enroll_add_service_principal_to_remove (enroll, optarg);
Sumit Bose 461678
+		return;
Sumit Bose 461678
 	case opt_verbose:
Sumit Bose 461678
 		return;
Sumit Bose 461678
 
Sumit Bose 461678
@@ -353,6 +363,7 @@ adcli_tool_computer_join (adcli_conn *conn,
Sumit Bose 461678
 		{ "os-service-pack", optional_argument, NULL, opt_os_service_pack },
Sumit Bose 461678
 		{ "user-principal", optional_argument, NULL, opt_user_principal },
Sumit Bose 461678
 		{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
Sumit Bose 461678
+		{ "add-service-principal", required_argument, NULL, opt_add_service_principal },
Sumit Bose 461678
 		{ "show-details", no_argument, NULL, opt_show_details },
Sumit Bose 461678
 		{ "show-password", no_argument, NULL, opt_show_password },
Sumit Bose 461678
 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
Sumit Bose 461678
@@ -458,6 +469,8 @@ adcli_tool_computer_update (adcli_conn *conn,
Sumit Bose 461678
 		{ "user-principal", optional_argument, NULL, opt_user_principal },
Sumit Bose 461678
 		{ "computer-password-lifetime", optional_argument, NULL, opt_computer_password_lifetime },
Sumit Bose 461678
 		{ "trusted-for-delegation", required_argument, NULL, opt_trusted_for_delegation },
Sumit Bose 461678
+		{ "add-service-principal", required_argument, NULL, opt_add_service_principal },
Sumit Bose 461678
+		{ "remove-service-principal", required_argument, NULL, opt_remove_service_principal },
Sumit Bose 461678
 		{ "show-details", no_argument, NULL, opt_show_details },
Sumit Bose 461678
 		{ "show-password", no_argument, NULL, opt_show_password },
Sumit Bose 461678
 		{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
Sumit Bose 461678
-- 
Sumit Bose 461678
2.14.4
Sumit Bose 461678