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

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