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