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

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