Blame SOURCES/0001-Find-NetBIOS-name-in-keytab-while-leaving.patch

4d12ff
From d0d36965cce7a9bdff77c20ce9c9c1252b8c827c Mon Sep 17 00:00:00 2001
4d12ff
From: Sumit Bose <sbose@redhat.com>
4d12ff
Date: Thu, 31 May 2018 16:16:08 +0200
4d12ff
Subject: [PATCH] Find NetBIOS name in keytab while leaving
4d12ff
4d12ff
If realmd is used with Samba as membership software, i.e. Samba's net
4d12ff
utility, the NetBIOS name must be known when leaving a domain. The most
4d12ff
reliable way to find it is by searching the keytab for NAME$@REALM type
4d12ff
entries and use the NAME as the NetBIOS name.
4d12ff
4d12ff
Related to https://bugzilla.redhat.com/show_bug.cgi?id=1370457
4d12ff
---
4d12ff
 service/realm-kerberos.c     | 64 ++++++++++++++++++++++++++++++++++++++++++++
4d12ff
 service/realm-kerberos.h     |  2 ++
4d12ff
 service/realm-samba-enroll.c | 13 ++++++---
4d12ff
 3 files changed, 76 insertions(+), 3 deletions(-)
4d12ff
4d12ff
diff --git a/service/realm-kerberos.c b/service/realm-kerberos.c
4d12ff
index 54d1ed7..d6d109f 100644
4d12ff
--- a/service/realm-kerberos.c
4d12ff
+++ b/service/realm-kerberos.c
4d12ff
@@ -1130,3 +1130,67 @@ realm_kerberos_flush_keytab (const gchar *realm_name,
4d12ff
 	return ret;
4d12ff
 
4d12ff
 }
4d12ff
+
4d12ff
+gchar *
4d12ff
+realm_kerberos_get_netbios_name_from_keytab (const gchar *realm_name)
4d12ff
+{
4d12ff
+	krb5_error_code code;
4d12ff
+	krb5_keytab keytab = NULL;
4d12ff
+	krb5_context ctx;
4d12ff
+	krb5_kt_cursor cursor = NULL;
4d12ff
+	krb5_keytab_entry entry;
4d12ff
+	krb5_principal realm_princ = NULL;
4d12ff
+	gchar *princ_name = NULL;
4d12ff
+	gchar *netbios_name = NULL;
4d12ff
+	krb5_data *name_data;
4d12ff
+
4d12ff
+	code = krb5_init_context (&ctx;;
4d12ff
+	if (code != 0) {
4d12ff
+		return NULL;
4d12ff
+	}
4d12ff
+
4d12ff
+	princ_name = g_strdup_printf ("user@%s", realm_name);
4d12ff
+	code = krb5_parse_name (ctx, princ_name, &realm_princ);
4d12ff
+	g_free (princ_name);
4d12ff
+
4d12ff
+	if (code == 0) {
4d12ff
+		code = krb5_kt_default (ctx, &keytab);
4d12ff
+	}
4d12ff
+
4d12ff
+	if (code == 0) {
4d12ff
+		code = krb5_kt_start_seq_get (ctx, keytab, &cursor);
4d12ff
+	}
4d12ff
+
4d12ff
+	if (code == 0) {
4d12ff
+		while (!krb5_kt_next_entry (ctx, keytab, &entry, &cursor) && netbios_name == NULL) {
4d12ff
+			if (krb5_realm_compare (ctx, realm_princ, entry.principal)) {
4d12ff
+				name_data = krb5_princ_component (ctx, entry.principal, 0);
4d12ff
+				if (name_data != NULL
4d12ff
+				                && name_data->length > 0
4d12ff
+				                && name_data->data[name_data->length - 1] == '$') {
4d12ff
+					netbios_name = g_strndup (name_data->data, name_data->length - 1);
4d12ff
+					if (netbios_name == NULL) {
4d12ff
+						code = krb5_kt_free_entry (ctx, &entry);
4d12ff
+						warn_if_krb5_failed (ctx, code);
4d12ff
+						break;
4d12ff
+					}
4d12ff
+				}
4d12ff
+			}
4d12ff
+			code = krb5_kt_free_entry (ctx, &entry);
4d12ff
+			warn_if_krb5_failed (ctx, code);
4d12ff
+		}
4d12ff
+	}
4d12ff
+
4d12ff
+	code = krb5_kt_end_seq_get (ctx, keytab, &cursor);
4d12ff
+	warn_if_krb5_failed (ctx, code);
4d12ff
+
4d12ff
+	code = krb5_kt_close (ctx, keytab);
4d12ff
+	warn_if_krb5_failed (ctx, code);
4d12ff
+
4d12ff
+	krb5_free_principal (ctx, realm_princ);
4d12ff
+
4d12ff
+	krb5_free_context (ctx);
4d12ff
+
4d12ff
+	return netbios_name;
4d12ff
+
4d12ff
+}
4d12ff
diff --git a/service/realm-kerberos.h b/service/realm-kerberos.h
4d12ff
index 0447e4d..58cfe07 100644
4d12ff
--- a/service/realm-kerberos.h
4d12ff
+++ b/service/realm-kerberos.h
4d12ff
@@ -88,6 +88,8 @@ gchar *             realm_kerberos_format_login          (RealmKerberos *self,
4d12ff
 gboolean            realm_kerberos_flush_keytab                (const gchar *realm_name,
4d12ff
                                                                 GError **error);
4d12ff
 
4d12ff
+gchar *             realm_kerberos_get_netbios_name_from_keytab (const gchar *realm_name);
4d12ff
+
4d12ff
 const gchar *       realm_kerberos_get_name                    (RealmKerberos *self);
4d12ff
 
4d12ff
 const gchar *       realm_kerberos_get_realm_name              (RealmKerberos *self);
4d12ff
diff --git a/service/realm-samba-enroll.c b/service/realm-samba-enroll.c
4d12ff
index 76e7b79..03f56d0 100644
4d12ff
--- a/service/realm-samba-enroll.c
4d12ff
+++ b/service/realm-samba-enroll.c
4d12ff
@@ -85,7 +85,8 @@ static JoinClosure *
4d12ff
 join_closure_init (GTask *task,
4d12ff
                    RealmDisco *disco,
4d12ff
                    GVariant *options,
4d12ff
-                   GDBusMethodInvocation *invocation)
4d12ff
+                   GDBusMethodInvocation *invocation,
4d12ff
+                   gboolean do_join)
4d12ff
 {
4d12ff
 	JoinClosure *join;
4d12ff
 	gchar *workgroup;
4d12ff
@@ -106,6 +107,12 @@ join_closure_init (GTask *task,
4d12ff
 	else if (disco->explicit_netbios)
4d12ff
 		authid = disco->explicit_netbios;
4d12ff
 
4d12ff
+	/* try to get the NetBIOS name from the keytab as last option while
4d12ff
+	 * leaving the domain */
4d12ff
+	if (authid == NULL && !do_join) {
4d12ff
+		authid = realm_kerberos_get_netbios_name_from_keytab(disco->kerberos_realm);
4d12ff
+	}
4d12ff
+
4d12ff
 	join->config = realm_ini_config_new (REALM_INI_NO_WATCH | REALM_INI_PRIVATE);
4d12ff
 	realm_ini_config_set (join->config, REALM_SAMBA_CONFIG_GLOBAL,
4d12ff
 	                      "security", "ads",
4d12ff
@@ -393,7 +400,7 @@ realm_samba_enroll_join_async (RealmDisco *disco,
4d12ff
 	g_return_if_fail (cred != NULL);
4d12ff
 
4d12ff
 	task = g_task_new (NULL, NULL, callback, user_data);
4d12ff
-	join = join_closure_init (task, disco, options, invocation);
4d12ff
+	join = join_closure_init (task, disco, options, invocation, TRUE);
4d12ff
 	explicit_computer_name = realm_options_computer_name (options, disco->domain_name);
4d12ff
 	if (explicit_computer_name != NULL) {
4d12ff
 		realm_diagnostics_info (invocation, "Joining using a manual netbios name: %s",
4d12ff
@@ -462,7 +469,7 @@ realm_samba_enroll_leave_async (RealmDisco *disco,
4d12ff
 	JoinClosure *join;
4d12ff
 
4d12ff
 	task = g_task_new (NULL, NULL, callback, user_data);
4d12ff
-	join = join_closure_init (task, disco, options, invocation);
4d12ff
+	join = join_closure_init (task, disco, options, invocation, FALSE);
4d12ff
 
4d12ff
 	switch (cred->type) {
4d12ff
 	case REALM_CREDENTIAL_PASSWORD:
4d12ff
-- 
4d12ff
2.14.4
4d12ff