From e2d7ca7f0822bb5cb17867a71754324616afe98b Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Thu, 11 Apr 2013 13:05:40 +0200 Subject: [PATCH] Cleanup passing around of credentials during join/leave operations * Only one pair of virtual methods on RealmKerberosMembership per join/remove * A single struct for credentials: RealmCredential * Less copying of credentails, and simply refing the struct * Remove the owner flags and have them simply be a field in the credential https://bugs.freedesktop.org/show_bug.cgi?id=63434 --- service/Makefile.am | 1 + service/realm-adcli-enroll.c | 119 ++++------ service/realm-adcli-enroll.h | 36 +-- service/realm-credential.c | 325 ++++++++++++++++++++++++++ service/realm-credential.h | 80 +++++++ service/realm-example.c | 71 +++--- service/realm-kerberos-membership.c | 66 ------ service/realm-kerberos-membership.h | 84 +------ service/realm-kerberos.c | 448 ++++++++---------------------------- service/realm-kerberos.h | 8 - service/realm-samba-enroll.c | 113 ++++----- service/realm-samba-enroll.h | 26 +-- service/realm-samba.c | 156 ++++++------- service/realm-sssd-ad.c | 409 ++++++++------------------------ service/realm-sssd-ipa.c | 327 ++++++++++++-------------- 15 files changed, 959 insertions(+), 1310 deletions(-) create mode 100644 service/realm-credential.c create mode 100644 service/realm-credential.h diff --git a/service/Makefile.am b/service/Makefile.am index 3f7ffa0..6c441fb 100644 --- a/service/Makefile.am +++ b/service/Makefile.am @@ -22,6 +22,7 @@ realmd_SOURCES = \ realm-adcli-enroll.c realm-adcli-enroll.h \ realm-all-provider.c realm-all-provider.h \ realm-command.c realm-command.h \ + realm-credential.c realm-credential.h \ realm-daemon.c realm-daemon.h \ realm-diagnostics.c realm-diagnostics.h \ realm-discovery.c realm-discovery.h \ diff --git a/service/realm-adcli-enroll.c b/service/realm-adcli-enroll.c index 11c3779..6a60560 100644 --- a/service/realm-adcli-enroll.c +++ b/service/realm-adcli-enroll.c @@ -68,25 +68,23 @@ on_join_process (GObject *source, g_object_unref (async); } -static void -begin_join_process (GBytes *input, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data, - ...) G_GNUC_NULL_TERMINATED; - -static void -begin_join_process (GBytes *input, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data, - ...) +void +realm_adcli_enroll_join_async (const gchar *realm, + RealmCredential *cred, + const gchar *computer_ou, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { gchar *environ[] = { "LANG=C", NULL }; GSimpleAsyncResult *async; + GBytes *input = NULL; GPtrArray *args; gchar *arg; - va_list va; + + g_return_if_fail (cred != NULL); + g_return_if_fail (realm != NULL); + g_return_if_fail (invocation != NULL); async = g_simple_async_result_new (NULL, callback, user_data, realm_adcli_enroll_join_finish); @@ -98,13 +96,40 @@ begin_join_process (GBytes *input, g_ptr_array_add (args, "join"); g_ptr_array_add (args, "--verbose"); g_ptr_array_add (args, "--show-details"); + g_ptr_array_add (args, "--domain"); + g_ptr_array_add (args, (gpointer)realm); - va_start (va, user_data); - do { - arg = va_arg (va, gchar *); + if (computer_ou) { + g_ptr_array_add (args, "--computer-ou"); + g_ptr_array_add (args, (gpointer)computer_ou); + } + + switch (cred->type) { + case REALM_CREDENTIAL_AUTOMATIC: + g_ptr_array_add (args, "--login-type"); + g_ptr_array_add (args, "computer"); + g_ptr_array_add (args, "--no-password"); + break; + case REALM_CREDENTIAL_CCACHE: + g_ptr_array_add (args, "--login-type"); + g_ptr_array_add (args, "user"); + arg = g_strdup_printf ("--login-ccache=%s", cred->x.ccache.file); g_ptr_array_add (args, arg); - } while (arg != NULL); - va_end (va); + break; + case REALM_CREDENTIAL_PASSWORD: + input = realm_command_build_password_line (cred->x.password.value); + g_ptr_array_add (args, "--login-type"); + g_ptr_array_add (args, "user"); + g_ptr_array_add (args, "--login-user"); + g_ptr_array_add (args, cred->x.password.name); + break; + case REALM_CREDENTIAL_SECRET: + input = realm_command_build_password_line (cred->x.secret.value); + g_ptr_array_add (args, "--login-type"); + g_ptr_array_add (args, "computer"); + g_ptr_array_add (args, "--stdin-password"); + break; + } g_ptr_array_add (args, NULL); @@ -114,60 +139,10 @@ begin_join_process (GBytes *input, g_ptr_array_free (args, TRUE); g_object_unref (async); -} - -void -realm_adcli_enroll_join_ccache_async (const gchar *realm, - const gchar *ccache_file, - const gchar *computer_ou, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - char *ccache_arg; - - /* Since this is an optional adcli argument it requires the equals */ - ccache_arg = g_strdup_printf ("--login-ccache=%s", ccache_file); - - begin_join_process (NULL, invocation, callback, user_data, - "--domain", realm, - "--login-type", "user", - ccache_arg, "--no-password", - computer_ou ? "--computer-ou": NULL, computer_ou, - NULL); - free (ccache_arg); -} - -void -realm_adcli_enroll_join_automatic_async (const gchar *realm, - const gchar *computer_ou, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - begin_join_process (NULL, invocation, callback, user_data, - "--domain", realm, - "--login-type", "computer", - "--no-password", - computer_ou ? "--computer-ou": NULL, computer_ou, - NULL); -} - -void -realm_adcli_enroll_join_otp_async (const gchar *realm, - GBytes *secret, - const gchar *computer_ou, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - begin_join_process (secret, invocation, callback, user_data, - "--domain", realm, - "--login-type", "computer", - "--stdin-password", - computer_ou ? "--computer-ou": NULL, computer_ou, - NULL); + if (input) + g_bytes_unref (input); + free (arg); } gboolean diff --git a/service/realm-adcli-enroll.h b/service/realm-adcli-enroll.h index 7dafc5e..3075506 100644 --- a/service/realm-adcli-enroll.h +++ b/service/realm-adcli-enroll.h @@ -17,36 +17,24 @@ #ifndef __REALM_ADCLI_ENROLL_H__ #define __REALM_ADCLI_ENROLL_H__ +#include "realm-credential.h" + #include #include G_BEGIN_DECLS -void realm_adcli_enroll_join_automatic_async (const gchar *realm, - const gchar *computer_ou, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - - -void realm_adcli_enroll_join_otp_async (const gchar *realm, - GBytes *secret, - const gchar *computer_ou, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - -void realm_adcli_enroll_join_ccache_async (const gchar *realm, - const gchar *ccache_file, - const gchar *computer_ou, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean realm_adcli_enroll_join_finish (GAsyncResult *result, - gchar **workgroup, - GError **error); +void realm_adcli_enroll_join_async (const gchar *realm, + RealmCredential *cred, + const gchar *computer_ou, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean realm_adcli_enroll_join_finish (GAsyncResult *result, + gchar **workgroup, + GError **error); G_END_DECLS diff --git a/service/realm-credential.c b/service/realm-credential.c new file mode 100644 index 0000000..8b2d506 --- /dev/null +++ b/service/realm-credential.c @@ -0,0 +1,325 @@ +/* realmd -- Realm configuration service + * + * Copyright 2012 Red Hat Inc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Author: Stef Walter + */ + +#include "config.h" + +#include + +#include "realm-credential.h" +#include "realm-daemon.h" +#include "realm-errors.h" + +#include +#include +#include + +static gchar * +write_ccache_file (GVariant *ccache, + GError **error) +{ + const gchar *directory; + gchar *filename; + const guchar *data; + gsize length; + gint fd; + int res; + + data = g_variant_get_fixed_array (ccache, &length, 1); + g_return_val_if_fail (length > 0, NULL); + + directory = g_get_tmp_dir (); + filename = g_build_filename (directory, "realm-ad-kerberos-XXXXXX", NULL); + + fd = g_mkstemp_full (filename, O_WRONLY, 0600); + if (fd < 0) { + g_warning ("couldn't open temporary file in %s directory for kerberos cache: %s", + directory, g_strerror (errno)); + g_set_error (error, REALM_ERROR, REALM_ERROR_INTERNAL, + "Problem writing out the kerberos cache data"); + g_free (filename); + return NULL; + } + + while (length > 0) { + res = write (fd, data, length); + if (res <= 0) { + if (errno == EAGAIN && errno == EINTR) + continue; + g_warning ("couldn't write kerberos cache to file %s: %s", + directory, g_strerror (errno)); + g_set_error (error, REALM_ERROR, REALM_ERROR_INTERNAL, + "Problem writing out the kerberos cache data"); + break; + } else { + length -= res; + data += res; + } + } + + if (length != 0) { + g_free (filename); + return NULL; + } + + return filename; +} + +static gboolean +parse_ccache (RealmCredential *cred, + GVariant *contents, + GError **error) +{ + gsize length; + + if (!g_variant_is_of_type (contents, G_VARIANT_TYPE ("ay"))) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Credential cache argument is of wrong DBus type"); + return FALSE; + } + + g_variant_get_fixed_array (contents, &length, 1); + if (length == 0) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Invalid zero length credential cache argument"); + return FALSE; + } + + cred->x.ccache.file = write_ccache_file (contents, error); + if (cred->x.ccache.file == NULL) + return FALSE; + + cred->type = REALM_CREDENTIAL_CCACHE; + return TRUE; +} + +static gboolean +parse_password (RealmCredential *cred, + GVariant *contents, + GError **error) +{ + const gchar *password; + + if (!g_variant_is_of_type (contents, G_VARIANT_TYPE ("(ss)"))) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Password credentials are of wrong DBus type"); + return FALSE; + } + + g_variant_get (contents, "(s&s)", &cred->x.password.name, &password); + cred->x.password.value = g_bytes_new_with_free_func (password, strlen (password), + (GDestroyNotify)g_variant_unref, + g_variant_ref (contents)); + + cred->type = REALM_CREDENTIAL_PASSWORD; + return TRUE; +} + +static gboolean +parse_secret (RealmCredential *cred, + GVariant *contents, + GError **error) +{ + gconstpointer data; + gsize length; + + if (!g_variant_is_of_type (contents, G_VARIANT_TYPE ("ay"))) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Secret credentials are of wrong DBus type"); + return FALSE; + } + + data = g_variant_get_fixed_array (contents, &length, 1); + cred->x.secret.value = g_bytes_new_with_free_func (data, length, + (GDestroyNotify)g_variant_unref, + g_variant_ref (contents)); + + cred->type = REALM_CREDENTIAL_SECRET; + return TRUE; +} + +static gboolean +parse_automatic (RealmCredential *cred, + GVariant *contents, + GError **error) +{ + cred->type = REALM_CREDENTIAL_AUTOMATIC; + return TRUE; +} + +RealmCredential * +realm_credential_parse (GVariant *input, + GError **error) +{ + RealmCredential *cred; + GVariant *outer; + GVariant *contents; + const char *owner, *type; + gboolean ret = TRUE; + + g_return_val_if_fail (input != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + cred = g_new0 (RealmCredential, 1); + cred->refs = 1; + + g_variant_get (input, "(&s&s@v)", &type, &owner, &outer); + + if (g_str_equal (owner, "administrator")) { + cred->owner = REALM_CREDENTIAL_OWNER_ADMIN; + } else if (g_str_equal (owner, "user")) { + cred->owner = REALM_CREDENTIAL_OWNER_USER; + } else if (g_str_equal (owner, "computer")) { + cred->owner = REALM_CREDENTIAL_OWNER_COMPUTER; + } else if (g_str_equal (owner, "none")) { + cred->owner = REALM_CREDENTIAL_OWNER_NONE; + } else { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Credential cache argument has invalid or unsupported owner"); + ret = FALSE; + } + + contents = g_variant_get_variant (outer); + g_variant_unref (outer); + + if (!ret) { + /* skip */; + } else if (g_str_equal (type, "ccache")) { + ret = parse_ccache (cred, contents, error); + } else if (g_str_equal (type, "password")) { + ret = parse_password (cred, contents, error); + } else if (g_str_equal (type, "secret")) { + ret = parse_secret (cred, contents, error); + } else if (g_str_equal (type, "automatic")) { + ret = parse_automatic (cred, contents, error); + } else { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Invalid or unsupported credential type"); + ret = FALSE; + } + + if (!ret) { + realm_credential_unref (cred); + cred = NULL; + } + + g_variant_unref (contents); + return cred; +} + +RealmCredential * +realm_credential_ref (RealmCredential *cred) +{ + g_return_val_if_fail (cred != NULL, NULL); + g_return_val_if_fail (cred->refs > 0, NULL); + + cred->refs++; + return cred; +} + +void +realm_credential_unref (RealmCredential *cred) +{ + g_return_if_fail (cred != NULL); + g_return_if_fail (cred->refs > 0); + + cred->refs--; + if (cred->refs > 0) + return; + + switch (cred->type) { + case REALM_CREDENTIAL_AUTOMATIC: + break; + case REALM_CREDENTIAL_CCACHE: + realm_credential_ccache_delete_and_free (cred->x.ccache.file); + break; + case REALM_CREDENTIAL_SECRET: + g_bytes_unref (cred->x.secret.value); + break; + case REALM_CREDENTIAL_PASSWORD: + g_free (cred->x.password.name); + g_bytes_unref (cred->x.password.value); + break; + } + + g_free (cred); +} + +void +realm_credential_ccache_delete_and_free (gchar *ccache_file) +{ + g_return_if_fail (ccache_file != NULL); + + if (!realm_daemon_has_debug_flag () && g_unlink (ccache_file) < 0) { + g_warning ("couldn't remove kerberos cache file: %s: %s", + ccache_file, g_strerror (errno)); + } + g_free (ccache_file); +} + +GVariant * +realm_credential_build_supported (const RealmCredential *creds) +{ + GPtrArray *elements; + GVariant *tuple[2]; + const gchar *string; + GVariant *supported; + + elements = g_ptr_array_new (); + + while (creds->type) { + if (creds->owner & REALM_CREDENTIAL_OWNER_ADMIN) + string = "administrator"; + else if (creds->owner & REALM_CREDENTIAL_OWNER_USER) + string = "user"; + else if (creds->owner & REALM_CREDENTIAL_OWNER_COMPUTER) + string = "computer"; + else if (creds->owner & REALM_CREDENTIAL_OWNER_NONE) + string = "none"; + else + g_return_val_if_reached (NULL); + + tuple[1] = g_variant_new_string (string); + + switch (creds->type) { + case REALM_CREDENTIAL_CCACHE: + string = "ccache"; + break; + case REALM_CREDENTIAL_PASSWORD: + string = "password"; + break; + case REALM_CREDENTIAL_SECRET: + string = "secret"; + break; + case REALM_CREDENTIAL_AUTOMATIC: + string = "automatic"; + break; + default: + g_return_val_if_reached (NULL); + break; + } + + tuple[0] = g_variant_new_string (string); + + g_ptr_array_add (elements, g_variant_new_tuple (tuple, 2)); + creds++; + } + + supported = g_variant_new_array (G_VARIANT_TYPE ("(ss)"), + (GVariant *const *)elements->pdata, + elements->len); + + g_ptr_array_free (elements, TRUE); + g_variant_ref_sink (supported); + return supported; +} diff --git a/service/realm-credential.h b/service/realm-credential.h new file mode 100644 index 0000000..77b0bfa --- /dev/null +++ b/service/realm-credential.h @@ -0,0 +1,80 @@ +/* realmd -- Realm configuration service + * + * Copyright 2012 Red Hat Inc + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * See the included COPYING file for more information. + * + * Author: Stef Walter + */ + +#include "config.h" + +#ifndef __REALM_CREDENTIAL_H__ +#define __REALM_CREDENTIAL_H__ + +#include + +#include + +G_BEGIN_DECLS + +typedef enum { + REALM_CREDENTIAL_OWNER_ADMIN = 1 << 1, + REALM_CREDENTIAL_OWNER_USER = 1 << 2, + REALM_CREDENTIAL_OWNER_COMPUTER = 1 << 3, + REALM_CREDENTIAL_OWNER_NONE = 1 << 4, +} RealmCredentialOwner; + +typedef enum { + REALM_CREDENTIAL_CCACHE = 1, + REALM_CREDENTIAL_PASSWORD, + REALM_CREDENTIAL_SECRET, + REALM_CREDENTIAL_AUTOMATIC +} RealmCredentialType; + +typedef struct { + RealmCredentialType type; + RealmCredentialOwner owner; + + /* + * Sometimes these structures are allocated statically. The following + * fieelds should not be used in that case, nor should the structure + * be passed to any realm_credential_xxx() function. + */ + int refs; + union { + struct { + gchar *file; + } ccache; + struct { + gchar *name; + GBytes *value; + } password; + struct { + GBytes *value; + } secret; + struct { + int unused; + } automatic; + } x; +} RealmCredential; + +RealmCredential * realm_credential_parse (GVariant *variant, + GError **error); + +RealmCredential * realm_credential_ref (RealmCredential *cred); + +void realm_credential_unref (RealmCredential *cred); + +void realm_credential_ccache_delete_and_free (gchar *ccache_file); + +GVariant * realm_credential_build_supported (const RealmCredential *creds); + +G_END_DECLS + +#endif /* __REALM_CREDENTIAL_H__ */ diff --git a/service/realm-example.c b/service/realm-example.c index 701ca95..cbeffd2 100644 --- a/service/realm-example.c +++ b/service/realm-example.c @@ -58,7 +58,6 @@ static void realm_example_constructed (GObject *obj) { RealmKerberos *kerberos = REALM_KERBEROS (obj); - GVariant *supported; G_OBJECT_CLASS (realm_example_parent_class)->constructed (obj); @@ -67,23 +66,6 @@ realm_example_constructed (GObject *obj) REALM_DBUS_OPTION_CLIENT_SOFTWARE, REALM_DBUS_IDENTIFIER_EXAMPLE, NULL); - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - 0); - - g_variant_ref_sink (supported); - realm_kerberos_set_supported_join_creds (kerberos, supported); - g_variant_unref (supported); - - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_AUTOMATIC, REALM_KERBEROS_OWNER_NONE, - 0); - - g_variant_ref_sink (supported); - realm_kerberos_set_supported_leave_creds (kerberos, supported); - g_variant_unref (supported); - realm_kerberos_set_login_policy (kerberos, REALM_KERBEROS_ALLOW_ANY_LOGIN); } @@ -165,8 +147,7 @@ on_join_sleep_done (GObject *source, static void realm_example_join_async (RealmKerberosMembership *membership, - const gchar *name, - GBytes *password, + RealmCredential *cred, RealmKerberosFlags flags, GVariant *options, GDBusMethodInvocation *invocation, @@ -179,6 +160,8 @@ realm_example_join_async (RealmKerberosMembership *membership, GError *error = NULL; const gchar *realm_name; + g_return_if_fail (cred->type == REALM_CREDENTIAL_PASSWORD); + realm_name = realm_kerberos_get_name (kerberos); async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, realm_example_join_async); @@ -193,7 +176,8 @@ realm_example_join_async (RealmKerberosMembership *membership, g_simple_async_result_take_error (async, error); g_simple_async_result_complete_in_idle (async); - } else if (!match_admin_and_password (self->config, realm_name, name, password)) { + } else if (!match_admin_and_password (self->config, realm_name, + cred->x.password.name, cred->x.password.value)) { g_simple_async_result_set_error (async, REALM_ERROR, REALM_ERROR_AUTH_FAILED, _("Admin name or password is not valid")); g_simple_async_result_complete_in_idle (async); @@ -326,6 +310,28 @@ realm_example_leave_automatic_async (RealmKerberosMembership *membership, } static void +realm_example_leave_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) +{ + switch (cred->type) { + case REALM_CREDENTIAL_AUTOMATIC: + realm_example_leave_automatic_async (membership, flags, options, invocation, callback, user_data); + break; + case REALM_CREDENTIAL_PASSWORD: + realm_example_leave_password_async (membership, cred->x.password.name, cred->x.password.value, + flags, options, invocation, callback, user_data); + break; + default: + g_return_if_reached (); + } +} + +static void realm_example_logins_async (RealmKerberos *realm, GDBusMethodInvocation *invocation, RealmKerberosLoginPolicy login_policy, @@ -502,11 +508,24 @@ realm_example_class_init (RealmExampleClass *klass) static void realm_example_kerberos_membership_iface (RealmKerberosMembershipIface *iface) { - iface->enroll_password_async = realm_example_join_async; - iface->enroll_finish = realm_example_membership_generic_finish; - iface->unenroll_password_async = realm_example_leave_password_async; - iface->unenroll_automatic_async = realm_example_leave_automatic_async; - iface->unenroll_finish = realm_example_membership_generic_finish; + static const RealmCredential join_creds[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN }, + { 0, } + }; + + static const RealmCredential leave_creds[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN }, + { REALM_CREDENTIAL_AUTOMATIC, REALM_CREDENTIAL_OWNER_NONE }, + { 0, } + }; + + iface->join_async = realm_example_join_async; + iface->join_finish = realm_example_membership_generic_finish; + iface->join_creds_supported = join_creds; + + iface->leave_async = realm_example_leave_async; + iface->leave_finish = realm_example_membership_generic_finish; + iface->leave_creds_supported = leave_creds; } RealmKerberos * diff --git a/service/realm-kerberos-membership.c b/service/realm-kerberos-membership.c index cc640cb..2e332e3 100644 --- a/service/realm-kerberos-membership.c +++ b/service/realm-kerberos-membership.c @@ -24,69 +24,3 @@ realm_kerberos_membership_default_init (RealmKerberosMembershipIface *iface) { } - -GVariant * -realm_kerberos_membership_build_supported (RealmKerberosCredential cred_type, - RealmKerberosFlags cred_owner, - ...) -{ - GPtrArray *elements; - GVariant *tuple[2]; - const gchar *string; - GVariant *supported; - va_list va; - - va_start (va, cred_owner); - elements = g_ptr_array_new (); - - while (cred_type != 0) { - if (cred_owner & REALM_KERBEROS_OWNER_ADMIN) - string = "administrator"; - else if (cred_owner & REALM_KERBEROS_OWNER_USER) - string = "user"; - else if (cred_owner & REALM_KERBEROS_OWNER_COMPUTER) - string = "computer"; - else if (cred_owner & REALM_KERBEROS_OWNER_NONE) - string = "none"; - else - g_assert_not_reached (); - - tuple[1] = g_variant_new_string (string); - - switch (cred_type) { - case REALM_KERBEROS_CREDENTIAL_CCACHE: - string = "ccache"; - break; - case REALM_KERBEROS_CREDENTIAL_PASSWORD: - string = "password"; - break; - case REALM_KERBEROS_CREDENTIAL_SECRET: - string = "secret"; - break; - case REALM_KERBEROS_CREDENTIAL_AUTOMATIC: - string = "automatic"; - break; - default: - g_assert_not_reached (); - break; - } - - tuple[0] = g_variant_new_string (string); - - g_ptr_array_add (elements, g_variant_new_tuple (tuple, 2)); - - cred_type = va_arg (va, RealmKerberosCredential); - if (cred_type != 0) - cred_owner = va_arg (va, RealmKerberosFlags); - } - - va_end (va); - - supported = g_variant_new_array (G_VARIANT_TYPE ("(ss)"), - (GVariant *const *)elements->pdata, - elements->len); - - g_ptr_array_free (elements, TRUE); - g_variant_ref_sink (supported); - return supported; -} diff --git a/service/realm-kerberos-membership.h b/service/realm-kerberos-membership.h index 427d99a..40e4607 100644 --- a/service/realm-kerberos-membership.h +++ b/service/realm-kerberos-membership.h @@ -21,31 +21,15 @@ #include +#include "realm-credential.h" #include "realm-dbus-generated.h" G_BEGIN_DECLS typedef enum { - REALM_KERBEROS_OWNER_ADMIN = 1 << 1, - REALM_KERBEROS_OWNER_USER = 1 << 2, - REALM_KERBEROS_OWNER_COMPUTER = 1 << 3, - REALM_KERBEROS_OWNER_NONE = 1 << 4, REALM_KERBEROS_ASSUME_PACKAGES = 1 << 5, } RealmKerberosFlags; -#define REALM_KERBEROS_OWNER_MASK \ - (REALM_KERBEROS_OWNER_ADMIN | \ - REALM_KERBEROS_OWNER_USER | \ - REALM_KERBEROS_OWNER_COMPUTER | \ - REALM_KERBEROS_OWNER_NONE) - -typedef enum { - REALM_KERBEROS_CREDENTIAL_CCACHE = 1, - REALM_KERBEROS_CREDENTIAL_PASSWORD, - REALM_KERBEROS_CREDENTIAL_SECRET, - REALM_KERBEROS_CREDENTIAL_AUTOMATIC -} RealmKerberosCredential; - #define REALM_TYPE_KERBEROS_MEMBERSHIP (realm_kerberos_membership_get_type ()) #define REALM_KERBEROS_MEMBERSHIP(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), REALM_TYPE_KERBEROS_MEMBERSHIP, RealmKerberosMembership)) #define REALM_IS_KERBEROS_MEMBERSHIP(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), REALM_TYPE_KERBEROS_MEMBERSHIP)) @@ -57,85 +41,37 @@ typedef struct _RealmKerberosMembershipIface RealmKerberosMembershipIface; struct _RealmKerberosMembershipIface { GTypeInterface parent_iface; - void (* enroll_password_async) (RealmKerberosMembership *realm, - const char *name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - - void (* enroll_ccache_async) (RealmKerberosMembership *realm, - const gchar *ccache_file, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - - void (* enroll_secret_async) (RealmKerberosMembership *realm, - GBytes *secret, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - - void (* enroll_automatic_async) (RealmKerberosMembership *realm, + void (* join_async) (RealmKerberosMembership *realm, + RealmCredential *cred, RealmKerberosFlags flags, GVariant *options, GDBusMethodInvocation *invocation, GAsyncReadyCallback callback, gpointer user_data); - gboolean (* enroll_finish) (RealmKerberosMembership *realm, + gboolean (* join_finish) (RealmKerberosMembership *realm, GAsyncResult *result, GError **error); - void (* unenroll_password_async) (RealmKerberosMembership *realm, - const char *name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - - void (* unenroll_ccache_async) (RealmKerberosMembership *realm, - const gchar *ccache_file, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - - void (* unenroll_secret_async) (RealmKerberosMembership *realm, - GBytes *secret, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); + const RealmCredential *join_creds_supported; - void (* unenroll_automatic_async) (RealmKerberosMembership *realm, + void (* leave_async) (RealmKerberosMembership *realm, + RealmCredential *cred, RealmKerberosFlags flags, GVariant *options, GDBusMethodInvocation *invocation, GAsyncReadyCallback callback, gpointer user_data); - gboolean (* unenroll_finish) (RealmKerberosMembership *realm, + gboolean (* leave_finish) (RealmKerberosMembership *realm, GAsyncResult *result, GError **error); + + const RealmCredential *leave_creds_supported; }; GType realm_kerberos_membership_get_type (void) G_GNUC_CONST; -GVariant * realm_kerberos_membership_build_supported (RealmKerberosCredential cred_type, - RealmKerberosFlags cred_owner, - ...); - G_END_DECLS #endif /* __REALM_KERBEROS_MEMBERSHIP_H__ */ diff --git a/service/realm-kerberos.c b/service/realm-kerberos.c index 0023d84..a8ce7e5 100644 --- a/service/realm-kerberos.c +++ b/service/realm-kerberos.c @@ -15,6 +15,7 @@ #include "config.h" #include "realm-command.h" +#include "realm-credential.h" #include "realm-daemon.h" #include "realm-dbus-constants.h" #include "realm-dbus-generated.h" @@ -79,7 +80,7 @@ G_DEFINE_TYPE (RealmKerberos, realm_kerberos, G_TYPE_DBUS_OBJECT_SKELETON); typedef struct { RealmKerberos *self; GDBusMethodInvocation *invocation; - gchar *ccache_file; + RealmCredential *cred; } MethodClosure; static MethodClosure * @@ -97,8 +98,8 @@ method_closure_free (MethodClosure *closure) { g_object_unref (closure->self); g_object_unref (closure->invocation); - if (closure->ccache_file) - realm_keberos_ccache_delete_and_free (closure->ccache_file); + if (closure->cred) + realm_credential_unref (closure->cred); g_slice_free (MethodClosure, closure); } @@ -159,11 +160,11 @@ on_enroll_complete (GObject *source, GError *error = NULL; iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (closure->self); - g_return_if_fail (iface->unenroll_finish != NULL); + g_return_if_fail (iface->join_finish != NULL); cancellable = realm_invocation_get_cancellable (closure->invocation); if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) - (iface->enroll_finish) (REALM_KERBEROS_MEMBERSHIP (closure->self), result, &error); + (iface->join_finish) (REALM_KERBEROS_MEMBERSHIP (closure->self), result, &error); if (error != NULL) { enroll_method_reply (closure->invocation, error); @@ -217,11 +218,11 @@ on_unenroll_complete (GObject *source, GError *error = NULL; iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (closure->self); - g_return_if_fail (iface->unenroll_finish != NULL); + g_return_if_fail (iface->leave_finish != NULL); cancellable = realm_invocation_get_cancellable (closure->invocation); if (!g_cancellable_set_error_if_cancelled (cancellable, &error)) - (iface->unenroll_finish) (REALM_KERBEROS_MEMBERSHIP (closure->self), result, &error); + (iface->leave_finish) (REALM_KERBEROS_MEMBERSHIP (closure->self), result, &error); unenroll_method_reply (closure->invocation, error); @@ -229,214 +230,85 @@ on_unenroll_complete (GObject *source, method_closure_free (closure); } -static gchar * -write_ccache_file (GVariant *ccache, - GError **error) +static gboolean +is_credential_supported (RealmKerberosMembershipIface *iface, + RealmCredential *cred, + gboolean join, + GError **error) { - const gchar *directory; - gchar *filename; - const guchar *data; - gsize length; - gint fd; - int res; - - data = g_variant_get_fixed_array (ccache, &length, 1); - g_return_val_if_fail (length > 0, NULL); - - directory = g_get_tmp_dir (); - filename = g_build_filename (directory, "realm-ad-kerberos-XXXXXX", NULL); - - fd = g_mkstemp_full (filename, O_WRONLY, 0600); - if (fd < 0) { - g_warning ("couldn't open temporary file in %s directory for kerberos cache: %s", - directory, g_strerror (errno)); - g_set_error (error, REALM_ERROR, REALM_ERROR_INTERNAL, - "Problem writing out the kerberos cache data"); - g_free (filename); - return NULL; - } + const RealmCredential *supported; + const char *message; + gboolean found = FALSE; + gint i; - while (length > 0) { - res = write (fd, data, length); - if (res <= 0) { - if (errno == EAGAIN && errno == EINTR) - continue; - g_warning ("couldn't write kerberos cache to file %s: %s", - directory, g_strerror (errno)); - g_set_error (error, REALM_ERROR, REALM_ERROR_INTERNAL, - "Problem writing out the kerberos cache data"); - break; - } else { - length -= res; - data += res; + supported = join ? iface->join_creds_supported : iface->leave_creds_supported; + if (supported) { + for (i = 0; supported[i].type != 0; i++) { + if (cred->type == supported[i].type) { + found = TRUE; + break; + } } } - if (length != 0) { - g_free (filename); - return NULL; + if (found) + return TRUE; + + switch (cred->type) { + case REALM_CREDENTIAL_AUTOMATIC: + message = join ? _("Joining this realm without credentials is not supported") : + _("Leaving this realm without credentials is not supported"); + break; + case REALM_CREDENTIAL_CCACHE: + message = join ? _("Joining this realm using a credential cache is not supported") : + _("Leaving this realm using a credential cache is not supported"); + break; + case REALM_CREDENTIAL_SECRET: + message = join ? _("Joining this realm using a secret is not supported") : + _("Unenrolling this realm using a secret is not supported"); + break; + case REALM_CREDENTIAL_PASSWORD: + message = join ? _("Enrolling this realm using a password is not supported") : + _("Unenrolling this realm using a password is not supported"); + break; } - return filename; + g_set_error_literal (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, message); + return FALSE; } static void -enroll_or_unenroll_with_ccache (RealmKerberos *self, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GVariant *ccache, - gboolean enroll) +join_or_leave (RealmKerberos *self, + GVariant *credential, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + gboolean join) { RealmKerberosMembershipIface *iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (self); + RealmCredential *cred; MethodClosure *method; - gchar *ccache_file; - GError *error; + GError *error = NULL; - if ((enroll && iface && iface->enroll_ccache_async == NULL) || - (!enroll && iface && iface->unenroll_ccache_async == NULL)) { + if ((join && iface && iface->join_async == NULL) || + (!join && iface && iface->leave_async == NULL)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, - enroll ? - _("Enrolling this realm using a credential cache is not supported") : - _("Unenrolling this realm using a credential cache is not supported")); + join ? _("Joining this realm is not supported") : + _("Leaving this realm is not supported")); return; } - if (!realm_invocation_lock_daemon (invocation)) { - g_dbus_method_invocation_return_error (invocation, REALM_ERROR, REALM_ERROR_BUSY, - _("Already running another action")); - return; - } - - ccache_file = write_ccache_file (ccache, &error); - if (ccache_file == NULL) { - enroll_method_reply (invocation, error); + cred = realm_credential_parse (credential, &error); + if (error != NULL) { + g_dbus_method_invocation_return_gerror (invocation, error); g_error_free (error); return; } - method = method_closure_new (self, invocation); - method->ccache_file = ccache_file; - - if (enroll) { - g_return_if_fail (iface->enroll_finish != NULL); - (iface->enroll_ccache_async) (REALM_KERBEROS_MEMBERSHIP (self), ccache_file, flags, - options, invocation, on_enroll_complete, method); - } else { - g_return_if_fail (iface->unenroll_finish != NULL); - (iface->unenroll_ccache_async) (REALM_KERBEROS_MEMBERSHIP (self), ccache_file, flags, - options, invocation, on_unenroll_complete, method); - } -} - -static void -enroll_or_unenroll_with_secret (RealmKerberos *self, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GVariant *secret, - gboolean enroll) -{ - RealmKerberosMembershipIface *iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (self); - const guchar *data; - GBytes *bytes; - gsize length; - - if ((enroll && iface && iface->enroll_secret_async == NULL) || - (!enroll && iface && iface->unenroll_secret_async == NULL)) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, - enroll ? - _("Enrolling this realm using a secret is not supported") : - _("Unenrolling this realm using a secret is not supported")); - return; - } - - if (!realm_invocation_lock_daemon (invocation)) { - g_dbus_method_invocation_return_error (invocation, REALM_ERROR, REALM_ERROR_BUSY, - _("Already running another action")); - return; - } - - data = g_variant_get_fixed_array (secret, &length, 1); - bytes = g_bytes_new_with_free_func (data, length, - (GDestroyNotify)g_variant_unref, - g_variant_ref (secret)); - - if (enroll) { - g_return_if_fail (iface->enroll_finish != NULL); - (iface->enroll_secret_async) (REALM_KERBEROS_MEMBERSHIP (self), bytes, flags, options, invocation, - on_enroll_complete, method_closure_new (self, invocation)); - } else { - g_return_if_fail (iface->unenroll_finish != NULL); - (iface->unenroll_secret_async) (REALM_KERBEROS_MEMBERSHIP (self), bytes, flags, options, invocation, - on_unenroll_complete, method_closure_new (self, invocation)); - } - - g_bytes_unref (bytes); -} - -static void -enroll_or_unenroll_with_password (RealmKerberos *self, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GVariant *creds, - gboolean enroll) -{ - RealmKerberosMembershipIface *iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (self); - const gchar *name; - const gchar *password; - GBytes *bytes; - - if ((enroll && iface && iface->enroll_password_async == NULL) || - (!enroll && iface && iface->unenroll_password_async == NULL)) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, - enroll ? - _("Enrolling this realm using a password is not supported") : - _("Unenrolling this realm using a password is not supported")); - return; - } - - if (!realm_invocation_lock_daemon (invocation)) { - g_dbus_method_invocation_return_error (invocation, REALM_ERROR, REALM_ERROR_BUSY, - _("Already running another action")); - return; - } - - g_variant_get (creds, "(&s&s)", &name, &password); - bytes = g_bytes_new_with_free_func (password, strlen (password), - (GDestroyNotify)g_variant_unref, - g_variant_ref (creds)); - - if (enroll) { - g_return_if_fail (iface->enroll_finish != NULL); - (iface->enroll_password_async) (REALM_KERBEROS_MEMBERSHIP (self), name, bytes, flags, options, invocation, - on_enroll_complete, method_closure_new (self, invocation)); - - } else { - g_return_if_fail (iface->unenroll_finish != NULL); - (iface->unenroll_password_async) (REALM_KERBEROS_MEMBERSHIP (self), name, bytes, flags, options, invocation, - on_unenroll_complete, method_closure_new (self, invocation)); - } - - g_bytes_unref (bytes); -} - -static void -enroll_or_unenroll_with_automatic (RealmKerberos *self, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - gboolean enroll) -{ - RealmKerberosMembershipIface *iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (self); - - if ((enroll && iface && iface->enroll_automatic_async == NULL) || - (!enroll && iface && iface->unenroll_automatic_async == NULL)) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, - enroll ? - _("Enrolling this realm without credentials is not supported") : - _("Unenrolling this realm without credentials is not supported")); + if (!is_credential_supported (iface, cred, join, &error)) { + g_dbus_method_invocation_return_gerror (invocation, error); + realm_credential_unref (cred); + g_error_free (error); return; } @@ -446,93 +318,18 @@ enroll_or_unenroll_with_automatic (RealmKerberos *self, return; } - if (enroll) { - g_return_if_fail (iface->enroll_finish != NULL); - (iface->enroll_automatic_async) (REALM_KERBEROS_MEMBERSHIP (self), flags, options, invocation, - on_enroll_complete, method_closure_new (self, invocation)); - } else { - g_return_if_fail (iface->enroll_finish != NULL); - (iface->unenroll_automatic_async) (REALM_KERBEROS_MEMBERSHIP (self), flags, options, invocation, - on_unenroll_complete, method_closure_new (self, invocation)); - } -} - -static gboolean -validate_and_parse_credentials (GDBusMethodInvocation *invocation, - GVariant *input, - RealmKerberosFlags *flags, - RealmKerberosCredential *cred_type, - GVariant **creds) -{ - GVariant *outer; - const char *owner, *type; - gsize length; - - g_variant_get (input, "(&s&s@v)", &type, &owner, &outer); - - if (g_str_equal (owner, "administrator")) { - *flags |= REALM_KERBEROS_OWNER_ADMIN; - } else if (g_str_equal (owner, "user")) { - *flags |= REALM_KERBEROS_OWNER_USER; - } else if (g_str_equal (owner, "computer")) { - *flags |= REALM_KERBEROS_OWNER_COMPUTER; - } else if (g_str_equal (owner, "none")) { - *flags |= REALM_KERBEROS_OWNER_NONE; - } else { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "Credential cache argument has invalid or unsupported owner"); - return FALSE; - } - - *creds = g_variant_get_variant (outer); - g_variant_unref (outer); - - if (g_str_equal (type, "ccache")) { - if (g_variant_is_of_type (*creds, G_VARIANT_TYPE ("ay"))) { - g_variant_get_fixed_array (*creds, &length, 1); - if (length == 0) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - _("Invalid zero length credential cache argument")); - } else { - *cred_type = REALM_KERBEROS_CREDENTIAL_CCACHE; - return TRUE; - } - } else { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "Credential cache argument is of wrong DBus type"); - } - - } else if (g_str_equal (type, "password")) { - if (g_variant_is_of_type (*creds, G_VARIANT_TYPE ("(ss)"))) { - *cred_type = REALM_KERBEROS_CREDENTIAL_PASSWORD; - return TRUE; - } else { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "Password credentials are of wrong DBus type"); - } - - } else if (g_str_equal (type, "secret")) { - if (g_variant_is_of_type (*creds, G_VARIANT_TYPE ("ay"))) { - *cred_type = REALM_KERBEROS_CREDENTIAL_SECRET; - return TRUE; - } else { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "Secret credentials are of wrong DBus type"); - } - - } else if (g_str_equal (type, "automatic")) { - *cred_type = REALM_KERBEROS_CREDENTIAL_AUTOMATIC; - return TRUE; + method = method_closure_new (self, invocation); + method->cred = cred; + if (join) { + g_return_if_fail (iface->join_finish != NULL); + (iface->join_async) (REALM_KERBEROS_MEMBERSHIP (self), cred, flags, + options, invocation, on_enroll_complete, method); } else { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "Invalid or unsupported credential type"); + g_return_if_fail (iface->leave_finish != NULL); + (iface->leave_async) (REALM_KERBEROS_MEMBERSHIP (self), cred, flags, + options, invocation, on_unenroll_complete, method); } - - /* Parsing failed */ - g_variant_unref (*creds); - *creds = NULL; - return FALSE; } static gboolean @@ -545,14 +342,9 @@ handle_join (RealmDbusKerberosMembership *membership, RealmKerberos *self = REALM_KERBEROS (user_data); gchar hostname[HOST_NAME_MAX + 1]; RealmKerberosFlags flags = 0; - GVariant *creds; - RealmKerberosCredential cred_type; gboolean assume = FALSE; gint ret; - if (!validate_and_parse_credentials (invocation, credentials, &flags, &cred_type, &creds)) - return TRUE; - /* Check the host name */ ret = gethostname (hostname, sizeof (hostname)); if (ret < 0 || g_ascii_strcasecmp (hostname, "localhost") == 0 || @@ -565,24 +357,7 @@ handle_join (RealmDbusKerberosMembership *membership, if (g_variant_lookup (options, REALM_DBUS_OPTION_ASSUME_PACKAGES, "b", &assume) && assume) flags |= REALM_KERBEROS_ASSUME_PACKAGES; - switch (cred_type) { - case REALM_KERBEROS_CREDENTIAL_CCACHE: - enroll_or_unenroll_with_ccache (self, flags, options, invocation, creds, TRUE); - break; - case REALM_KERBEROS_CREDENTIAL_PASSWORD: - enroll_or_unenroll_with_password (self, flags, options, invocation, creds, TRUE); - break; - case REALM_KERBEROS_CREDENTIAL_SECRET: - enroll_or_unenroll_with_secret (self, flags, options, invocation, creds, TRUE); - break; - case REALM_KERBEROS_CREDENTIAL_AUTOMATIC: - enroll_or_unenroll_with_automatic (self, flags, options, invocation, TRUE); - break; - default: - g_assert_not_reached (); - } - - g_variant_unref (creds); + join_or_leave (self, credentials, flags, options, invocation, TRUE); return TRUE; } @@ -595,9 +370,7 @@ handle_leave (RealmDbusKerberosMembership *membership, { RealmKerberos *self = REALM_KERBEROS (user_data); RealmKerberosFlags flags = 0; - GVariant *creds; const gchar *computer_ou; - RealmKerberosCredential cred_type; if (g_variant_lookup (options, REALM_DBUS_OPTION_COMPUTER_OU, "&s", &computer_ou)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, @@ -605,27 +378,7 @@ handle_leave (RealmDbusKerberosMembership *membership, return TRUE; } - if (!validate_and_parse_credentials (invocation, credentials, &flags, &cred_type, &creds)) - return TRUE; - - switch (cred_type) { - case REALM_KERBEROS_CREDENTIAL_CCACHE: - enroll_or_unenroll_with_ccache (self, flags, options, invocation, creds, FALSE); - break; - case REALM_KERBEROS_CREDENTIAL_PASSWORD: - enroll_or_unenroll_with_password (self, flags, options, invocation, creds, FALSE); - break; - case REALM_KERBEROS_CREDENTIAL_SECRET: - enroll_or_unenroll_with_secret (self, flags, options, invocation, creds, FALSE); - break; - case REALM_KERBEROS_CREDENTIAL_AUTOMATIC: - enroll_or_unenroll_with_automatic (self, flags, options, invocation, FALSE); - break; - default: - g_assert_not_reached (); - } - - g_variant_unref (creds); + join_or_leave (self, credentials, flags, options, invocation, FALSE); return TRUE; } @@ -635,10 +388,13 @@ handle_deconfigure (RealmDbusRealm *realm, GVariant *options, gpointer user_data) { - RealmKerberos *self = REALM_KERBEROS (user_data); + GVariant *credential; + + credential = g_variant_new ("(ss@v)", "automatic", "none", + g_variant_new_variant (g_variant_new_string (""))); + join_or_leave (REALM_KERBEROS (user_data), credential, 0, options, invocation, FALSE); + g_variant_unref (credential); - enroll_or_unenroll_with_automatic (self, REALM_KERBEROS_OWNER_COMPUTER, - options, invocation, FALSE); return TRUE; } @@ -770,8 +526,10 @@ realm_kerberos_init (RealmKerberos *self) static void realm_kerberos_constructed (GObject *obj) { + RealmKerberosMembershipIface *iface; RealmKerberos *self = REALM_KERBEROS (obj); const gchar *supported_interfaces[3]; + GVariant *supported; const gchar *name; G_OBJECT_CLASS (realm_kerberos_parent_class)->constructed (obj); @@ -784,6 +542,14 @@ realm_kerberos_constructed (GObject *obj) G_CALLBACK (handle_leave), self); g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (self), G_DBUS_INTERFACE_SKELETON (self->pv->membership_iface)); + + iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (self); + supported = realm_credential_build_supported (iface->join_creds_supported); + realm_dbus_kerberos_membership_set_supported_join_credentials (self->pv->membership_iface, supported); + + iface = REALM_KERBEROS_MEMBERSHIP_GET_IFACE (self); + supported = realm_credential_build_supported (iface->leave_creds_supported); + realm_dbus_kerberos_membership_set_supported_leave_credentials (self->pv->membership_iface, supported); } supported_interfaces[0] = REALM_DBUS_KERBEROS_INTERFACE; @@ -981,7 +747,7 @@ kinit_closure_free (gpointer data) g_free (kinit->principal); g_bytes_unref (kinit->password); g_free (kinit->enctypes); - realm_keberos_ccache_delete_and_free (kinit->ccache_file); + realm_credential_ccache_delete_and_free (kinit->ccache_file); g_slice_free (KinitClosure, kinit); } @@ -1200,16 +966,6 @@ realm_kerberos_kinit_ccache_finish (RealmKerberos *self, return filename; } -void -realm_keberos_ccache_delete_and_free (gchar *ccache_file) -{ - if (!realm_daemon_has_debug_flag () && g_unlink (ccache_file) < 0) { - g_warning ("couldn't remove kerberos cache file: %s: %s", - ccache_file, g_strerror (errno)); - } - g_free (ccache_file); -} - const gchar * realm_kerberos_get_name (RealmKerberos *self) { @@ -1250,24 +1006,6 @@ realm_kerberos_set_suggested_admin (RealmKerberos *self, } void -realm_kerberos_set_supported_join_creds (RealmKerberos *self, - GVariant *value) -{ - g_return_if_fail (REALM_IS_KERBEROS (self)); - g_return_if_fail (self->pv->membership_iface != NULL); - realm_dbus_kerberos_membership_set_supported_join_credentials (self->pv->membership_iface, value); -} - -void -realm_kerberos_set_supported_leave_creds (RealmKerberos *self, - GVariant *value) -{ - g_return_if_fail (REALM_IS_KERBEROS (self)); - g_return_if_fail (self->pv->membership_iface != NULL); - realm_dbus_kerberos_membership_set_supported_leave_credentials (self->pv->membership_iface, value); -} - -void realm_kerberos_set_permitted_logins (RealmKerberos *self, const gchar **value) { diff --git a/service/realm-kerberos.h b/service/realm-kerberos.h index 10cce4d..3a9d339 100644 --- a/service/realm-kerberos.h +++ b/service/realm-kerberos.h @@ -93,8 +93,6 @@ gchar * realm_kerberos_kinit_ccache_finish (RealmKerberos *self, GAsyncResult *result, GError **error); -void realm_keberos_ccache_delete_and_free (gchar *ccache_file); - gboolean realm_kerberos_flush_keytab (const gchar *realm_name, GError **error); @@ -111,12 +109,6 @@ void realm_kerberos_set_domain_name (RealmKerberos *s void realm_kerberos_set_suggested_admin (RealmKerberos *self, const gchar *value); -void realm_kerberos_set_supported_join_creds (RealmKerberos *self, - GVariant *value); - -void realm_kerberos_set_supported_leave_creds (RealmKerberos *self, - GVariant *value); - void realm_kerberos_set_permitted_logins (RealmKerberos *self, const gchar **value); diff --git a/service/realm-samba-enroll.c b/service/realm-samba-enroll.c index f4a7c81..d2b0c23 100644 --- a/service/realm-samba-enroll.c +++ b/service/realm-samba-enroll.c @@ -436,62 +436,42 @@ begin_join (GSimpleAsyncResult *async, } void -realm_samba_enroll_join_password_async (const gchar *realm, - const gchar *user_name, - GBytes *password, - const gchar *computer_ou, - GHashTable *discovery, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +realm_samba_enroll_join_async (const gchar *realm, + RealmCredential *cred, + const gchar *computer_ou, + GHashTable *discovery, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { GSimpleAsyncResult *async; JoinClosure *join; g_return_if_fail (realm != NULL); - g_return_if_fail (user_name != NULL); - g_return_if_fail (password != NULL); + g_return_if_fail (cred != NULL); async = g_simple_async_result_new (NULL, callback, user_data, realm_samba_enroll_join_finish); join = join_closure_init (async, realm, invocation); - join->password_input = realm_command_build_password_line (password); - join->user_name = g_strdup (user_name); - - begin_join (async, join, realm, computer_ou, discovery); - - g_object_unref (async); -} - -void -realm_samba_enroll_join_ccache_async (const gchar *realm, - const gchar *ccache_file, - const gchar *computer_ou, - GHashTable *discovery, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - JoinClosure *join; - - g_return_if_fail (realm != NULL); - g_return_if_fail (ccache_file != NULL); - - async = g_simple_async_result_new (NULL, callback, user_data, - realm_samba_enroll_join_finish); - - join = join_closure_init (async, realm, invocation); - join->envvar = g_strdup_printf ("KRB5CCNAME=%s", ccache_file); + switch (cred->type) { + case REALM_CREDENTIAL_PASSWORD: + join->password_input = realm_command_build_password_line (cred->x.password.value); + join->user_name = g_strdup (cred->x.password.name); + break; + case REALM_CREDENTIAL_CCACHE: + join->envvar = g_strdup_printf ("KRB5CCNAME=%s", cred->x.ccache.file); + break; + default: + g_return_if_reached (); + } begin_join (async, join, realm, computer_ou, discovery); g_object_unref (async); } - gboolean realm_samba_enroll_join_finish (GAsyncResult *result, GHashTable **settings, @@ -536,12 +516,11 @@ on_leave_complete (GObject *source, } void -realm_samba_enroll_leave_password_async (const gchar *realm, - const gchar *user_name, - GBytes *password, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +realm_samba_enroll_leave_async (const gchar *realm, + RealmCredential *cred, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { GSimpleAsyncResult *async; JoinClosure *join; @@ -550,35 +529,25 @@ realm_samba_enroll_leave_password_async (const gchar *realm, realm_samba_enroll_leave_finish); join = join_closure_init (async, realm, invocation); - join->password_input = realm_command_build_password_line (password); - join->user_name = g_strdup (user_name); - - begin_net_process (join, join->password_input, - on_leave_complete, g_object_ref (async), - "-U", join->user_name, "ads", "leave", NULL); - - g_object_unref (async); -} -void -realm_samba_enroll_leave_ccache_async (const gchar *realm, - const gchar *ccache_file, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - JoinClosure *join; - - async = g_simple_async_result_new (NULL, callback, user_data, - realm_samba_enroll_leave_finish); - - join = join_closure_init (async, realm, invocation); - join->envvar = g_strdup_printf ("KRB5CCNAME=%s", ccache_file); + switch (cred->type) { + case REALM_CREDENTIAL_PASSWORD: + join->password_input = realm_command_build_password_line (cred->x.password.value); + join->user_name = g_strdup (cred->x.password.name); + begin_net_process (join, join->password_input, + on_leave_complete, g_object_ref (async), + "-U", join->user_name, "ads", "leave", NULL); + break; + case REALM_CREDENTIAL_CCACHE: + join->envvar = g_strdup_printf ("KRB5CCNAME=%s", cred->x.ccache.file); + begin_net_process (join, join->password_input, + on_leave_complete, g_object_ref (async), + "-k", "ads", "leave", NULL); + break; + default: + g_return_if_reached (); + } - begin_net_process (join, join->password_input, - on_leave_complete, g_object_ref (async), - "-k", "ads", "leave", NULL); g_object_unref (async); } diff --git a/service/realm-samba-enroll.h b/service/realm-samba-enroll.h index 4d52fd6..3605f4f 100644 --- a/service/realm-samba-enroll.h +++ b/service/realm-samba-enroll.h @@ -17,23 +17,16 @@ #ifndef __REALM_SAMBA_ENROLL_H__ #define __REALM_SAMBA_ENROLL_H__ +#include "realm-credential.h" + #include #include G_BEGIN_DECLS -void realm_samba_enroll_join_password_async (const gchar *realm, - const gchar *user_name, - GBytes *password, - const gchar *computer_ou, - GHashTable *discovery, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - -void realm_samba_enroll_join_ccache_async (const gchar *realm, - const gchar *ccache_file, +void realm_samba_enroll_join_async (const gchar *realm, + RealmCredential *cred, const gchar *computer_ou, GHashTable *discovery, GDBusMethodInvocation *invocation, @@ -44,15 +37,8 @@ gboolean realm_samba_enroll_join_finish (GAsyncResult *result GHashTable **settings, GError **error); -void realm_samba_enroll_leave_password_async (const gchar *realm, - const gchar *user_name, - GBytes *password, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data); - -void realm_samba_enroll_leave_ccache_async (const gchar *realm, - const gchar *ccache_file, +void realm_samba_enroll_leave_async (const gchar *realm, + RealmCredential *cred, GDBusMethodInvocation *invocation, GAsyncReadyCallback callback, gpointer user_data); diff --git a/service/realm-samba.c b/service/realm-samba.c index 1a21856..89eaa03 100644 --- a/service/realm-samba.c +++ b/service/realm-samba.c @@ -78,7 +78,6 @@ static void realm_samba_constructed (GObject *obj) { RealmKerberos *kerberos = REALM_KERBEROS (obj); - GVariant *supported; G_OBJECT_CLASS (realm_samba_parent_class)->constructed (obj); @@ -87,20 +86,6 @@ realm_samba_constructed (GObject *obj) REALM_DBUS_OPTION_CLIENT_SOFTWARE, REALM_DBUS_IDENTIFIER_WINBIND, NULL); - /* - * Each line is a combination of owner and what kind of credentials are supported, - * same for enroll/leave. We can't accept a ccache, because samba3 needs - * to have credentials limited to RC4. - */ - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_USER, - 0); - g_variant_ref_sink (supported); - realm_kerberos_set_supported_join_creds (kerberos, supported); - realm_kerberos_set_supported_leave_creds (kerberos, supported); - g_variant_unref (supported); - realm_kerberos_set_suggested_admin (kerberos, "Administrator"); realm_kerberos_set_login_policy (kerberos, REALM_KERBEROS_ALLOW_ANY_LOGIN); realm_kerberos_set_required_package_sets (kerberos, SAMBA_PACKAGES); @@ -156,8 +141,7 @@ typedef struct { GDBusMethodInvocation *invocation; gchar *computer_ou; gchar *realm_name; - gchar *user_name; - GBytes *password; + RealmCredential *cred; } EnrollClosure; static void @@ -166,8 +150,7 @@ enroll_closure_free (gpointer data) EnrollClosure *enroll = data; g_free (enroll->realm_name); g_free (enroll->computer_ou); - g_free (enroll->user_name); - g_bytes_unref (enroll->password); + realm_credential_unref (enroll->cred); g_object_unref (enroll->invocation); g_slice_free (EnrollClosure, enroll); } @@ -245,9 +228,9 @@ on_install_do_join (GObject *source, realm_packages_install_finish (result, &error); if (error == NULL) { - realm_samba_enroll_join_password_async (enroll->realm_name, enroll->user_name, enroll->password, - enroll->computer_ou, realm_kerberos_get_discovery (kerberos), - enroll->invocation, on_join_do_winbind, g_object_ref (res)); + realm_samba_enroll_join_async (enroll->realm_name, enroll->cred, + enroll->computer_ou, realm_kerberos_get_discovery (kerberos), + enroll->invocation, on_join_do_winbind, g_object_ref (res)); } else { g_simple_async_result_take_error (res, error); @@ -277,14 +260,13 @@ validate_membership_options (GVariant *options, } static void -realm_samba_enroll_async (RealmKerberosMembership *membership, - const gchar *name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +realm_samba_join_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { RealmKerberos *realm = REALM_KERBEROS (membership); RealmSamba *self = REALM_SAMBA (realm); @@ -295,13 +277,12 @@ realm_samba_enroll_async (RealmKerberosMembership *membership, gchar *enrolled; res = g_simple_async_result_new (G_OBJECT (realm), callback, user_data, - realm_samba_enroll_async); + realm_samba_join_async); enroll = g_slice_new0 (EnrollClosure); enroll->realm_name = g_strdup (realm_kerberos_get_realm_name (realm)); enroll->invocation = g_object_ref (invocation); enroll->computer_ou = realm_kerberos_calculate_join_computer_ou (realm, options); - enroll->user_name = g_strdup (name); - enroll->password = g_bytes_ref (password); + enroll->cred = realm_credential_ref (cred); g_simple_async_result_set_op_res_gpointer (res, enroll, enroll_closure_free); /* Make sure not already enrolled in a realm */ @@ -415,21 +396,24 @@ on_leave_do_deconfigure (GObject *source, g_object_unref (res); } -static GSimpleAsyncResult * -setup_leave (RealmSamba *self, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +static void +realm_samba_leave_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { - LeaveClosure *leave; + RealmSamba *self = REALM_SAMBA (membership); GSimpleAsyncResult *async; + LeaveClosure *leave; const gchar *realm_name; gchar *enrolled; realm_name = realm_kerberos_get_realm_name (REALM_KERBEROS (self)); - async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, setup_leave); + async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, realm_samba_leave_async); leave = g_slice_new0 (LeaveClosure); leave->realm_name = g_strdup (realm_name); leave->invocation = g_object_ref (invocation); @@ -442,54 +426,23 @@ setup_leave (RealmSamba *self, _("Not currently joined to this domain")); g_simple_async_result_complete_in_idle (async); g_object_unref (async); - return NULL; - - } - - return async; -} - -static void -realm_samba_leave_password_async (RealmKerberosMembership *membership, - const gchar *name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmSamba *self = REALM_SAMBA (membership); - GSimpleAsyncResult *async; - LeaveClosure *leave; - - async = setup_leave (self, options, invocation, callback, user_data); - if (async == NULL) return; + } - leave = g_simple_async_result_get_op_res_gpointer (async); - realm_samba_enroll_leave_password_async (leave->realm_name, name, password, - leave->invocation, on_leave_do_deconfigure, - g_object_ref (async)); - g_object_unref (async); -} - -static void -realm_samba_leave_automatic_async (RealmKerberosMembership *membership, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmSamba *self = REALM_SAMBA (membership); - GSimpleAsyncResult *async; - - async = setup_leave (self, options, invocation, callback, user_data); - if (async == NULL) - return; + switch (cred->type) { + case REALM_CREDENTIAL_PASSWORD: + leave = g_simple_async_result_get_op_res_gpointer (async); + realm_samba_enroll_leave_async (leave->realm_name, cred, + leave->invocation, on_leave_do_deconfigure, + g_object_ref (async)); + break; + case REALM_CREDENTIAL_AUTOMATIC: + leave_deconfigure_begin (self, async); + break; + default: + g_return_if_reached (); + } - leave_deconfigure_begin (self, async); g_object_unref (async); } @@ -710,11 +663,32 @@ realm_samba_class_init (RealmSambaClass *klass) static void realm_samba_kerberos_membership_iface (RealmKerberosMembershipIface *iface) { - iface->enroll_password_async = realm_samba_enroll_async; - iface->enroll_finish = realm_samba_membership_generic_finish; - iface->unenroll_password_async = realm_samba_leave_password_async; - iface->unenroll_automatic_async = realm_samba_leave_automatic_async; - iface->unenroll_finish = realm_samba_membership_generic_finish; + /* + * Each line is a combination of owner and what kind of credentials are supported, + * same for enroll/leave. We can't accept a ccache, because samba3 needs + * to have credentials limited to RC4. + */ + + static const RealmCredential join_supported[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN }, + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_USER }, + { 0, }, + }; + + static const RealmCredential leave_supported[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN }, + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_USER }, + { REALM_CREDENTIAL_AUTOMATIC, REALM_CREDENTIAL_OWNER_NONE }, + { 0, }, + }; + + iface->join_async = realm_samba_join_async; + iface->join_finish = realm_samba_membership_generic_finish; + iface->join_creds_supported = join_supported; + + iface->leave_async = realm_samba_leave_async; + iface->leave_finish = realm_samba_membership_generic_finish; + iface->leave_creds_supported = leave_supported; } RealmKerberos * diff --git a/service/realm-sssd-ad.c b/service/realm-sssd-ad.c index f8efe13..2912cc9 100644 --- a/service/realm-sssd-ad.c +++ b/service/realm-sssd-ad.c @@ -81,7 +81,6 @@ static void realm_sssd_ad_constructed (GObject *obj) { RealmKerberos *kerberos = REALM_KERBEROS (obj); - GVariant *supported; G_OBJECT_CLASS (realm_sssd_ad_parent_class)->constructed (obj); @@ -90,29 +89,6 @@ realm_sssd_ad_constructed (GObject *obj) REALM_DBUS_OPTION_CLIENT_SOFTWARE, REALM_DBUS_IDENTIFIER_SSSD, NULL); - /* - * Each line is a combination of owner and what kind of credentials are supported, - * same for enroll/leave. We can't accept a ccache with samba because of certain - * corner cases. However we do accept ccache for an admin user, and then we use - * adcli with that ccache. - */ - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_USER, - REALM_KERBEROS_CREDENTIAL_CCACHE, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_AUTOMATIC, REALM_KERBEROS_OWNER_NONE, - REALM_KERBEROS_CREDENTIAL_SECRET, REALM_KERBEROS_OWNER_NONE, - 0); - realm_kerberos_set_supported_join_creds (kerberos, supported); - - /* For leave, we don't support one-time-password (ie: secret/none) */ - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_CCACHE, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_AUTOMATIC, REALM_KERBEROS_OWNER_NONE, - 0); - realm_kerberos_set_supported_leave_creds (kerberos, supported); - realm_kerberos_set_suggested_admin (kerberos, "Administrator"); realm_kerberos_set_login_policy (kerberos, REALM_KERBEROS_ALLOW_REALM_LOGINS); realm_kerberos_set_required_package_sets (kerberos, ALL_PACKAGES); @@ -120,20 +96,11 @@ realm_sssd_ad_constructed (GObject *obj) typedef struct { GDBusMethodInvocation *invocation; - RealmKerberosCredential cred_type; + RealmCredential *cred; gchar *computer_ou; gchar *realm_name; gboolean use_adcli; const gchar **packages; - - /* Used for adcli enroll */ - gboolean automatic; - GBytes *one_time_password; - gchar *ccache_file; - - /* Used for samba enroll */ - gchar *user_name; - GBytes *user_password; } JoinClosure; static void @@ -142,12 +109,8 @@ join_closure_free (gpointer data) JoinClosure *join = data; g_free (join->realm_name); g_object_unref (join->invocation); - if (join->ccache_file) - realm_keberos_ccache_delete_and_free (join->ccache_file); + realm_credential_unref (join->cred); g_free (join->computer_ou); - g_free (join->user_name); - g_bytes_unref (join->user_password); - g_bytes_unref (join->one_time_password); g_slice_free (JoinClosure, join); } @@ -264,7 +227,7 @@ on_join_do_sssd (GObject *source, if (join->use_adcli) { if (!realm_adcli_enroll_join_finish (result, &workgroup, &error)) { workgroup = NULL; - if (join->automatic && + if (join->cred->type == REALM_CREDENTIAL_AUTOMATIC && g_error_matches (error, REALM_ERROR, REALM_ERROR_AUTH_FAILED)) { g_clear_error (&error); g_set_error (&error, REALM_ERROR, REALM_ERROR_AUTH_FAILED, @@ -314,38 +277,20 @@ on_install_do_join (GObject *source, realm_packages_install_finish (result, &error); if (error == NULL) { - if (join->use_adcli && join->one_time_password) { - realm_adcli_enroll_join_otp_async (join->realm_name, - join->one_time_password, - join->computer_ou, - join->invocation, - on_join_do_sssd, - g_object_ref (async)); - - } else if (join->use_adcli && join->ccache_file) { - realm_adcli_enroll_join_ccache_async (join->realm_name, - join->ccache_file, - join->computer_ou, - join->invocation, - on_join_do_sssd, - g_object_ref (async)); - - } else if (join->use_adcli) { - g_assert (join->automatic); - realm_adcli_enroll_join_automatic_async (join->realm_name, - join->computer_ou, - join->invocation, - on_join_do_sssd, - g_object_ref (async)); - + if (join->use_adcli) { + realm_adcli_enroll_join_async (join->realm_name, + join->cred, + join->computer_ou, + join->invocation, + on_join_do_sssd, + g_object_ref (async)); } else { - g_assert (join->user_name != NULL); - g_assert (join->user_password != NULL); - realm_samba_enroll_join_password_async (join->realm_name, join->user_name, - join->user_password, join->computer_ou, - realm_kerberos_get_discovery (kerberos), - join->invocation, on_join_do_sssd, - g_object_ref (async)); + realm_samba_enroll_join_async (join->realm_name, + join->cred, + join->computer_ou, + realm_kerberos_get_discovery (kerberos), + join->invocation, on_join_do_sssd, + g_object_ref (async)); } } else { @@ -357,32 +302,9 @@ on_install_do_join (GObject *source, g_object_unref (async); } -static void -on_kinit_do_install (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); - JoinClosure *join = g_simple_async_result_get_op_res_gpointer (async); - GError *error = NULL; - - join->ccache_file = realm_kerberos_kinit_ccache_finish (REALM_KERBEROS (source), result, &error); - if (error == NULL) { - realm_packages_install_async (join->packages, join->invocation, - on_install_do_join, g_object_ref (async)); - - } else { - g_simple_async_result_take_error (async, error); - g_simple_async_result_complete (async); - } - - g_object_unref (async); -} - static gboolean parse_join_options (JoinClosure *join, - RealmKerberosCredential cred_type, - RealmKerberosFlags owner, + RealmCredential *cred, GVariant *options, GError **error) { @@ -404,8 +326,8 @@ parse_join_options (JoinClosure *join, * If we are enrolling with a one time password, or automatically, use * adcli. Samba doesn't support computer passwords or using reset accounts. */ - if ((cred_type == REALM_KERBEROS_CREDENTIAL_SECRET && owner == REALM_KERBEROS_OWNER_NONE) || - (cred_type == REALM_KERBEROS_CREDENTIAL_AUTOMATIC && owner == REALM_KERBEROS_OWNER_NONE)) { + if ((cred->type == REALM_CREDENTIAL_SECRET && cred->owner == REALM_CREDENTIAL_OWNER_NONE) || + (cred->type == REALM_CREDENTIAL_AUTOMATIC && cred->owner == REALM_CREDENTIAL_OWNER_NONE)) { if (!software) software = REALM_DBUS_IDENTIFIER_ADCLI; if (!g_str_equal (software, REALM_DBUS_IDENTIFIER_ADCLI)) { @@ -419,7 +341,7 @@ parse_join_options (JoinClosure *join, * If we are enrolling with a user password, then we have to use samba, * adcli only supports admin passwords. */ - } else if (cred_type == REALM_KERBEROS_CREDENTIAL_PASSWORD && owner == REALM_KERBEROS_OWNER_USER) { + } else if (cred->type == REALM_CREDENTIAL_PASSWORD && cred->owner == REALM_CREDENTIAL_OWNER_USER) { if (!software) software = REALM_DBUS_IDENTIFIER_SAMBA; if (!g_str_equal (software, REALM_DBUS_IDENTIFIER_SAMBA)) { @@ -434,7 +356,7 @@ parse_join_options (JoinClosure *join, * There have been some strange corner case problems when using samba with * a ccache. */ - } else if (cred_type == REALM_KERBEROS_CREDENTIAL_CCACHE) { + } else if (cred->type == REALM_CREDENTIAL_CCACHE) { if (!software) software = REALM_DBUS_IDENTIFIER_ADCLI; @@ -443,7 +365,7 @@ parse_join_options (JoinClosure *join, * samba. But since adcli is pretty immature at this point, we use samba * by default. */ - } else if (cred_type == REALM_KERBEROS_CREDENTIAL_PASSWORD && owner == REALM_KERBEROS_OWNER_ADMIN) { + } else if (cred->type == REALM_CREDENTIAL_PASSWORD && cred->owner == REALM_CREDENTIAL_OWNER_ADMIN) { if (!software) software = REALM_DBUS_IDENTIFIER_SAMBA; @@ -467,14 +389,14 @@ parse_join_options (JoinClosure *join, return TRUE; } -static GSimpleAsyncResult * -prepare_join_async_result (RealmKerberosMembership *membership, - RealmKerberosCredential cred_type, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +static void +realm_sssd_ad_join_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { RealmKerberos *realm = REALM_KERBEROS (membership); RealmSssd *sssd = REALM_SSSD (realm); @@ -487,7 +409,7 @@ prepare_join_async_result (RealmKerberosMembership *membership, join->realm_name = g_strdup (realm_kerberos_get_realm_name (realm)); join->invocation = g_object_ref (invocation); join->computer_ou = realm_kerberos_calculate_join_computer_ou (realm, options); - join->cred_type = cred_type; + join->cred = realm_credential_ref (cred); g_simple_async_result_set_op_res_gpointer (async, join, join_closure_free); /* Make sure not already enrolled in a realm */ @@ -501,7 +423,7 @@ prepare_join_async_result (RealmKerberosMembership *membership, _("A domain with this name is already configured")); g_simple_async_result_complete_in_idle (async); - } else if (!parse_join_options (join, cred_type, flags & REALM_KERBEROS_OWNER_MASK, options, &error)) { + } else if (!parse_join_options (join, cred, options, &error)) { g_simple_async_result_take_error (async, error); g_simple_async_result_complete_in_idle (async); @@ -509,127 +431,16 @@ prepare_join_async_result (RealmKerberosMembership *membership, } else { if (flags & REALM_KERBEROS_ASSUME_PACKAGES) join->packages = NO_PACKAGES; - return async; - } - - /* Had an error */ - g_object_unref (async); - return NULL; -} - -static void -realm_sssd_ad_join_automatic_async (RealmKerberosMembership *membership, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - JoinClosure *join; - - async = prepare_join_async_result (membership, REALM_KERBEROS_CREDENTIAL_AUTOMATIC, - flags, options, invocation, callback, user_data); - - if (async) { - join = g_simple_async_result_get_op_res_gpointer (async); - join->automatic = TRUE; - realm_packages_install_async (join->packages, join->invocation, - on_install_do_join, g_object_ref (async)); - g_object_unref (async); - } -} - -static void -realm_sssd_ad_join_secret_async (RealmKerberosMembership *membership, - GBytes *secret, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - JoinClosure *join; - - async = prepare_join_async_result (membership, REALM_KERBEROS_CREDENTIAL_SECRET, - flags, options, invocation, callback, user_data); - - if (async) { - join = g_simple_async_result_get_op_res_gpointer (async); - join->one_time_password = g_bytes_ref (secret); - realm_packages_install_async (join->packages, join->invocation, - on_install_do_join, g_object_ref (async)); - g_object_unref (async); - } -} - -static void -realm_sssd_ad_join_password_async (RealmKerberosMembership *membership, - const gchar *user_name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - JoinClosure *join; - - async = prepare_join_async_result (membership, REALM_KERBEROS_CREDENTIAL_PASSWORD, - flags, options, invocation, callback, user_data); - - if (async) { - join = g_simple_async_result_get_op_res_gpointer (async); - - if (join->use_adcli) { - realm_kerberos_kinit_ccache_async (REALM_KERBEROS (membership), - user_name, password, NULL, - invocation, on_kinit_do_install, - g_object_ref (async)); - } else { - join->user_name = g_strdup (user_name); - join->user_password = g_bytes_ref (password); - realm_packages_install_async (join->packages, join->invocation, - on_install_do_join, g_object_ref (async)); - } - - g_object_unref (async); - } -} - -static void -realm_sssd_ad_join_ccache_async (RealmKerberosMembership *membership, - const gchar *ccache_file, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - JoinClosure *join; - - async = prepare_join_async_result (membership, REALM_KERBEROS_CREDENTIAL_CCACHE, - flags, options, invocation, callback, user_data); - - if (async) { - join = g_simple_async_result_get_op_res_gpointer (async); - - join->ccache_file = g_strdup (ccache_file); realm_packages_install_async (join->packages, join->invocation, on_install_do_join, g_object_ref (async)); - - g_object_unref (async); } + g_object_unref (async); } typedef struct { GDBusMethodInvocation *invocation; gchar *realm_name; - gchar *ccache_file; } LeaveClosure; static void @@ -637,8 +448,6 @@ leave_closure_free (gpointer data) { LeaveClosure *leave = data; g_free (leave->realm_name); - if (leave->ccache_file) - realm_keberos_ccache_delete_and_free (leave->ccache_file); g_object_unref (leave->invocation); g_slice_free (LeaveClosure, leave); } @@ -666,16 +475,21 @@ on_leave_do_deconfigure (GObject *source, g_object_unref (res); } -static GSimpleAsyncResult * -setup_leave (RealmSssdAd *self, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +static void +realm_sssd_ad_leave_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { + RealmSssdAd *self = REALM_SSSD_AD (membership); GSimpleAsyncResult *async; + LeaveClosure *leave; - async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, setup_leave); + async = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + realm_sssd_ad_leave_async); /* Check that enrolled in this realm */ if (!realm_sssd_get_config_section (REALM_SSSD (self))) { @@ -683,85 +497,26 @@ setup_leave (RealmSssdAd *self, _("Not currently joined to this domain")); g_simple_async_result_complete_in_idle (async); g_object_unref (async); - return NULL; - } - - return async; -} - -static void -realm_sssd_ad_leave_password_async (RealmKerberosMembership *membership, - const gchar *user_name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmSssdAd *self = REALM_SSSD_AD (membership); - GSimpleAsyncResult *async; - LeaveClosure *leave; - - async = setup_leave (self, options, invocation, callback, user_data); - if (async == NULL) - return; - - leave = g_slice_new0 (LeaveClosure); - leave->realm_name = g_strdup (realm_kerberos_get_realm_name (REALM_KERBEROS (self))); - leave->invocation = g_object_ref (invocation); - g_simple_async_result_set_op_res_gpointer (async, leave, leave_closure_free); - - realm_samba_enroll_leave_password_async (leave->realm_name, user_name, password, - leave->invocation, on_leave_do_deconfigure, - g_object_ref (async)); - g_object_unref (async); -} - -static void -realm_sssd_ad_leave_ccache_async (RealmKerberosMembership *membership, - const gchar *ccache_file, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmSssdAd *self = REALM_SSSD_AD (membership); - GSimpleAsyncResult *async; - LeaveClosure *leave; - - async = setup_leave (self, options, invocation, callback, user_data); - if (async == NULL) return; + } - leave = g_slice_new0 (LeaveClosure); - leave->realm_name = g_strdup (realm_kerberos_get_realm_name (REALM_KERBEROS (self))); - leave->invocation = g_object_ref (invocation); - g_simple_async_result_set_op_res_gpointer (async, leave, leave_closure_free); - - realm_samba_enroll_leave_ccache_async (leave->realm_name, ccache_file, - leave->invocation, on_leave_do_deconfigure, - g_object_ref (async)); - g_object_unref (async); -} - -static void -realm_sssd_ad_leave_automatic_async (RealmKerberosMembership *membership, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmSssdAd *self = REALM_SSSD_AD (membership); - GSimpleAsyncResult *async; - - async = setup_leave (self, options, invocation, callback, user_data); - if (async == NULL) - return; + switch (cred->type) { + case REALM_CREDENTIAL_AUTOMATIC: + realm_sssd_deconfigure_domain_tail (REALM_SSSD (self), async, invocation); + break; + case REALM_CREDENTIAL_CCACHE: + case REALM_CREDENTIAL_PASSWORD: + leave = g_slice_new0 (LeaveClosure); + leave->realm_name = g_strdup (realm_kerberos_get_realm_name (REALM_KERBEROS (self))); + leave->invocation = g_object_ref (invocation); + g_simple_async_result_set_op_res_gpointer (async, leave, leave_closure_free); + realm_samba_enroll_leave_async (leave->realm_name, cred, invocation, + on_leave_do_deconfigure, g_object_ref (async)); + break; + default: + g_return_if_reached (); + } - realm_sssd_deconfigure_domain_tail (REALM_SSSD (self), async, invocation); g_object_unref (async); } @@ -791,13 +546,35 @@ realm_sssd_ad_class_init (RealmSssdAdClass *klass) static void realm_sssd_ad_kerberos_membership_iface (RealmKerberosMembershipIface *iface) { - iface->enroll_automatic_async = realm_sssd_ad_join_automatic_async; - iface->enroll_password_async = realm_sssd_ad_join_password_async; - iface->enroll_secret_async = realm_sssd_ad_join_secret_async; - iface->enroll_ccache_async = realm_sssd_ad_join_ccache_async; - iface->enroll_finish = realm_sssd_ad_generic_finish; - iface->unenroll_automatic_async = realm_sssd_ad_leave_automatic_async; - iface->unenroll_password_async = realm_sssd_ad_leave_password_async; - iface->unenroll_ccache_async = realm_sssd_ad_leave_ccache_async; - iface->unenroll_finish = realm_sssd_ad_generic_finish; + /* + * Each line is a combination of owner and what kind of credentials are supported, + * same for enroll/leave. We can't accept a ccache with samba because of certain + * corner cases. However we do accept ccache for an admin user, and then we use + * adcli with that ccache. + */ + + static const RealmCredential join_supported[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN, }, + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_USER, }, + { REALM_CREDENTIAL_CCACHE, REALM_CREDENTIAL_OWNER_ADMIN, }, + { REALM_CREDENTIAL_AUTOMATIC, REALM_CREDENTIAL_OWNER_NONE, }, + { REALM_CREDENTIAL_SECRET, REALM_CREDENTIAL_OWNER_NONE, }, + { 0, }, + }; + + /* For leave, we don't support one-time-password (ie: secret/none) */ + static const RealmCredential leave_supported[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN, }, + { REALM_CREDENTIAL_CCACHE, REALM_CREDENTIAL_OWNER_ADMIN, }, + { REALM_CREDENTIAL_AUTOMATIC, REALM_CREDENTIAL_OWNER_NONE, }, + { 0, }, + }; + + iface->join_async = realm_sssd_ad_join_async; + iface->join_finish = realm_sssd_ad_generic_finish; + iface->join_creds_supported = join_supported; + + iface->leave_async = realm_sssd_ad_leave_async; + iface->leave_finish = realm_sssd_ad_generic_finish; + iface->leave_creds_supported = leave_supported; } diff --git a/service/realm-sssd-ipa.c b/service/realm-sssd-ipa.c index 86149bd..391a977 100644 --- a/service/realm-sssd-ipa.c +++ b/service/realm-sssd-ipa.c @@ -71,7 +71,6 @@ static void realm_sssd_ipa_constructed (GObject *obj) { RealmKerberos *kerberos = REALM_KERBEROS (obj); - GVariant *supported; G_OBJECT_CLASS (realm_sssd_ipa_parent_class)->constructed (obj); @@ -80,24 +79,6 @@ realm_sssd_ipa_constructed (GObject *obj) REALM_DBUS_OPTION_CLIENT_SOFTWARE, REALM_DBUS_IDENTIFIER_SSSD, NULL); - /* - * NOTE: The ipa-client-install service requires that we pass a password directly - * to the process, and not a ccache. It also accepts a one time password. - */ - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_SECRET, REALM_KERBEROS_OWNER_NONE, - 0); - - realm_kerberos_set_supported_join_creds (kerberos, supported); - - supported = realm_kerberos_membership_build_supported ( - REALM_KERBEROS_CREDENTIAL_PASSWORD, REALM_KERBEROS_OWNER_ADMIN, - REALM_KERBEROS_CREDENTIAL_AUTOMATIC, REALM_KERBEROS_OWNER_NONE, - 0); - - realm_kerberos_set_supported_leave_creds (kerberos, supported); - realm_kerberos_set_suggested_admin (kerberos, "admin"); realm_kerberos_set_required_package_sets (kerberos, IPA_PACKAGES); } @@ -116,7 +97,7 @@ realm_sssd_ipa_class_init (RealmSssdIpaClass *klass) typedef struct { GDBusMethodInvocation *invocation; - gchar **argv; + GPtrArray *argv; GBytes *input; } EnrollClosure; @@ -125,7 +106,8 @@ enroll_closure_free (gpointer data) { EnrollClosure *enroll = data; g_object_unref (enroll->invocation); - g_strfreev (enroll->argv); + if (enroll->argv) + g_ptr_array_unref (enroll->argv); g_bytes_unref (enroll->input); g_slice_free (EnrollClosure, enroll); } @@ -252,7 +234,7 @@ on_install_do_join (GObject *source, realm_packages_install_finish (result, &error); if (error == NULL) { - realm_command_runv_async (enroll->argv, (gchar **)env, + realm_command_runv_async ((gchar **)enroll->argv->pdata, (gchar **)env, enroll->input, enroll->invocation, on_ipa_client_do_restart, g_object_ref (async)); } else { @@ -263,15 +245,38 @@ on_install_do_join (GObject *source, g_object_unref (async); } +static char * +secret_to_password (GBytes *secret) +{ + gconstpointer data; + gsize length; + + /* + * In theory the password could be binary with embedded nulls. + * We don't support that. And we assume that we don't need to + * check for that here, because such a password will be wrong, + * and ipa-client-install will simply fail to join the domain. + */ + + data = g_bytes_get_data (secret, &length); + return g_strndup (data, length); +} + +static void +push_arg (GPtrArray *argv, + const gchar *value) +{ + g_ptr_array_add (argv, strdup (value)); +} + static void -join_ipa_async (RealmKerberosMembership *membership, - const gchar **argv, - GBytes *input, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +realm_sssd_ipa_join_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { RealmKerberos *realm = REALM_KERBEROS (membership); RealmSssd *sssd = REALM_SSSD (realm); @@ -281,13 +286,12 @@ join_ipa_async (RealmKerberosMembership *membership, const gchar *computer_ou; const gchar *software; const gchar **packages; + GPtrArray *argv; domain_name = realm_kerberos_get_name (realm); async = g_simple_async_result_new (G_OBJECT (realm), callback, user_data, NULL); enroll = g_slice_new0 (EnrollClosure); - enroll->input = input ? g_bytes_ref (input) : NULL; - enroll->argv = g_strdupv ((gchar **)argv); enroll->invocation = g_object_ref (invocation); g_simple_async_result_set_op_res_gpointer (async, enroll, enroll_closure_free); @@ -316,6 +320,46 @@ join_ipa_async (RealmKerberosMembership *membership, packages = IPA_PACKAGES; if (flags & REALM_KERBEROS_ASSUME_PACKAGES) packages = NO_PACKAGES; + + argv = g_ptr_array_new (); + push_arg (argv, realm_settings_string ("paths", "ipa-client-install")); + push_arg (argv, "--domain"); + push_arg (argv, realm_kerberos_get_name (realm)); + push_arg (argv, "--realm"); + push_arg (argv, realm_kerberos_get_realm_name (realm)); + push_arg (argv, "--mkhomedir"); + push_arg (argv, "--no-ntp"); + push_arg (argv, "--enable-dns-updates"); + push_arg (argv, "--unattended"); + + switch (cred->type) { + case REALM_CREDENTIAL_SECRET: + /* + * TODO: Allow passing the password other than command line. + * + * ipa-client-install won't let us pass a password into a prompt + * when used with --unattended. We need --unattended since we can't + * handle arbitrary prompts. So pass the one time password on + * the command line. It's just a one time password, so in the short + * term this should be okay. + */ + + push_arg (argv, "--password"); + g_ptr_array_add (argv, secret_to_password (cred->x.secret.value)); + break; + case REALM_CREDENTIAL_PASSWORD: + enroll->input = realm_command_build_password_line (cred->x.password.value); + push_arg (argv, "--principal"); + push_arg (argv, cred->x.password.name); + push_arg (argv, "-W"); + break; + default: + g_return_if_reached (); + } + + g_ptr_array_add (argv, NULL); + enroll->argv = argv; + realm_packages_install_async (packages, invocation, on_install_do_join, g_object_ref (async)); } @@ -324,99 +368,6 @@ join_ipa_async (RealmKerberosMembership *membership, } static void -realm_sssd_ipa_enroll_password_async (RealmKerberosMembership *membership, - const gchar *name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmKerberos *realm = REALM_KERBEROS (membership); - GBytes *input; - - const gchar *argv[] = { - realm_settings_string ("paths", "ipa-client-install"), - "--domain", realm_kerberos_get_name (realm), - "--realm", realm_kerberos_get_realm_name (realm), - "--principal", name, - "-W", - "--mkhomedir", - "--no-ntp", - "--enable-dns-updates", - "--unattended", - NULL, - }; - - input = realm_command_build_password_line (password); - - join_ipa_async (membership, argv, input, flags, options, - invocation, callback, user_data); - - g_bytes_unref (input); -} - -static const char * -secret_to_password (GBytes *secret, - gchar **password) -{ - gconstpointer data; - gsize length; - - /* - * In theory the password could be binary with embedded nulls. - * We don't support that. And we assume that we don't need to - * check for that here, because such a password will be wrong, - * and ipa-client-install will simply fail to join the domain. - */ - - data = g_bytes_get_data (secret, &length); - *password = g_strndup (data, length); - return *password; -} - -static void -realm_sssd_ipa_enroll_secret_async (RealmKerberosMembership *membership, - GBytes *secret, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - RealmKerberos *realm = REALM_KERBEROS (membership); - char *password; - - const gchar *argv[] = { - realm_settings_string ("paths", "ipa-client-install"), - "--domain", realm_kerberos_get_name (realm), - "--realm", realm_kerberos_get_realm_name (realm), - "--password", secret_to_password (secret, &password), - "--mkhomedir", - "--no-ntp", - "--enable-dns-updates", - "--unattended", - NULL, - }; - - /* - * TODO: Allow passing the password other than command line. - * - * ipa-client-install won't let us pass a password into a prompt - * when used with --unattended. We need --unattended since we can't - * handle arbitrary prompts. So pass the one time password on - * the command line. It's just a one time password, so in the short - * term this should be okay. - */ - - join_ipa_async (membership, argv, NULL, flags, options, - invocation, callback, user_data); - - g_free (password); -} - -static void on_ipa_client_do_disable (GObject *source, GAsyncResult *result, gpointer user_data) @@ -447,26 +398,43 @@ on_ipa_client_do_disable (GObject *source, } static void -leave_ipa_async (RealmKerberosMembership *membership, - const gchar **argv, - GBytes *input, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) +realm_sssd_ipa_leave_async (RealmKerberosMembership *membership, + RealmCredential *cred, + RealmKerberosFlags flags, + GVariant *options, + GDBusMethodInvocation *invocation, + GAsyncReadyCallback callback, + gpointer user_data) { RealmKerberos *realm = REALM_KERBEROS (membership); RealmSssd *sssd = REALM_SSSD (realm); GSimpleAsyncResult *async; EnrollClosure *enroll; const gchar *computer_ou; + GBytes *input; + const gchar **argv; const gchar *env[] = { "LANG=C", NULL, }; + const gchar *automatic_args[] = { + realm_settings_string ("paths", "ipa-client-install"), + "--uninstall", + "--unattended", + NULL + }; + + const gchar *password_args[] = { + realm_settings_string ("paths", "ipa-client-install"), + "--uninstall", + "--principal", cred->x.password.name, + "-W", + "--unattended", + NULL + }; + async = g_simple_async_result_new (G_OBJECT (realm), callback, user_data, NULL); enroll = g_slice_new0 (EnrollClosure); enroll->invocation = g_object_ref (invocation); @@ -483,59 +451,28 @@ leave_ipa_async (RealmKerberosMembership *membership, g_simple_async_result_complete_in_idle (async); } else { - realm_command_runv_async ((gchar **)argv, (gchar **)env, NULL, invocation, + switch (cred->type) { + case REALM_CREDENTIAL_AUTOMATIC: + argv = automatic_args; + break; + case REALM_CREDENTIAL_PASSWORD: + input = realm_command_build_password_line (cred->x.password.value); + argv = password_args; + break; + default: + g_return_if_reached (); + } + + realm_command_runv_async ((gchar **)argv, (gchar **)env, input, invocation, on_ipa_client_do_disable, g_object_ref (async)); + + if (input) + g_bytes_unref (input); } g_object_unref (async); } -static void -realm_sssd_ipa_leave_password_async (RealmKerberosMembership *membership, - const char *name, - GBytes *password, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GBytes *input; - - const gchar *argv[] = { - realm_settings_string ("paths", "ipa-client-install"), - "--uninstall", - "--principal", name, - "-W", - "--unattended", - NULL - }; - - input = realm_command_build_password_line (password); - leave_ipa_async (membership, argv, input, flags, options, - invocation, callback, user_data); - g_bytes_unref (input); -} - -static void -realm_sssd_ipa_leave_automatic_async (RealmKerberosMembership *membership, - RealmKerberosFlags flags, - GVariant *options, - GDBusMethodInvocation *invocation, - GAsyncReadyCallback callback, - gpointer user_data) -{ - const gchar *argv[] = { - realm_settings_string ("paths", "ipa-client-install"), - "--uninstall", - "--unattended", - NULL - }; - - leave_ipa_async (membership, argv, NULL, flags, options, - invocation, callback, user_data); -} - static gboolean realm_sssd_ipa_generic_finish (RealmKerberosMembership *realm, GAsyncResult *result, @@ -550,10 +487,28 @@ realm_sssd_ipa_generic_finish (RealmKerberosMembership *realm, static void realm_sssd_ipa_kerberos_membership_iface (RealmKerberosMembershipIface *iface) { - iface->enroll_password_async = realm_sssd_ipa_enroll_password_async; - iface->enroll_secret_async = realm_sssd_ipa_enroll_secret_async; - iface->enroll_finish = realm_sssd_ipa_generic_finish; - iface->unenroll_password_async = realm_sssd_ipa_leave_password_async; - iface->unenroll_automatic_async = realm_sssd_ipa_leave_automatic_async; - iface->unenroll_finish = realm_sssd_ipa_generic_finish; + + /* + * NOTE: The ipa-client-install service requires that we pass a password directly + * to the process, and not a ccache. It also accepts a one time password. + */ + static const RealmCredential join_supported[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN }, + { REALM_CREDENTIAL_SECRET, REALM_CREDENTIAL_OWNER_NONE, }, + { 0, } + }; + + static const RealmCredential leave_supported[] = { + { REALM_CREDENTIAL_PASSWORD, REALM_CREDENTIAL_OWNER_ADMIN, }, + { REALM_CREDENTIAL_AUTOMATIC, REALM_CREDENTIAL_OWNER_NONE, }, + { 0, } + }; + + iface->join_async = realm_sssd_ipa_join_async; + iface->join_finish = realm_sssd_ipa_generic_finish; + iface->join_creds_supported = join_supported; + + iface->leave_async = realm_sssd_ipa_leave_async; + iface->leave_finish = realm_sssd_ipa_generic_finish; + iface->leave_creds_supported = leave_supported; } -- 1.8.1.4