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

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