From e05fb7b3e36c052baf0dd607ddeb22c0a2b5cbde Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:47:04 +0200 Subject: Adding upstream version 43.2. Signed-off-by: Daniel Baumann --- .../pages/account/um-realm-manager.c | 878 +++++++++++++++++++++ 1 file changed, 878 insertions(+) create mode 100644 gnome-initial-setup/pages/account/um-realm-manager.c (limited to 'gnome-initial-setup/pages/account/um-realm-manager.c') diff --git a/gnome-initial-setup/pages/account/um-realm-manager.c b/gnome-initial-setup/pages/account/um-realm-manager.c new file mode 100644 index 0000000..bc4fd33 --- /dev/null +++ b/gnome-initial-setup/pages/account/um-realm-manager.c @@ -0,0 +1,878 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2009-2012 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: Matthias Clasen + * Stef Walter + */ + +#include "config.h" + +#include "um-realm-manager.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + + +struct _UmRealmManager { + UmRealmObjectManagerClient parent; + UmRealmProvider *provider; +}; + +typedef struct { + UmRealmProviderProxyClass parent_class; +} UmRealmManagerClass; + +enum { + REALM_ADDED, + NUM_SIGNALS, +}; + +static gint signals[NUM_SIGNALS] = { 0, }; + +G_DEFINE_TYPE (UmRealmManager, um_realm_manager, UM_REALM_TYPE_OBJECT_MANAGER_CLIENT); + +GQuark +um_realm_error_get_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("um-realm-error"); + return quark; +} + +static gboolean +is_realm_with_kerberos_and_membership (gpointer object) +{ + GDBusInterface *interface; + + if (!G_IS_DBUS_OBJECT (object)) + return FALSE; + + interface = g_dbus_object_get_interface (object, "org.freedesktop.realmd.Kerberos"); + if (interface == NULL) + return FALSE; + g_object_unref (interface); + + interface = g_dbus_object_get_interface (object, "org.freedesktop.realmd.KerberosMembership"); + if (interface == NULL) + return FALSE; + g_object_unref (interface); + + return TRUE; +} + +static void +on_interface_added (GDBusObjectManager *manager, + GDBusObject *object, + GDBusInterface *interface) +{ + g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (interface), G_MAXINT); +} + +static void +on_object_added (GDBusObjectManager *manager, + GDBusObject *object, + gpointer user_data) +{ + GList *interfaces, *l; + + interfaces = g_dbus_object_get_interfaces (object); + for (l = interfaces; l != NULL; l = g_list_next (l)) + on_interface_added (manager, object, l->data); + g_list_free_full (interfaces, g_object_unref); + + if (is_realm_with_kerberos_and_membership (object)) { + g_debug ("Saw realm: %s", g_dbus_object_get_object_path (object)); + g_signal_emit (user_data, signals[REALM_ADDED], 0, object); + } +} + +static void +um_realm_manager_init (UmRealmManager *self) +{ + g_signal_connect (self, "object-added", G_CALLBACK (on_object_added), self); + g_signal_connect (self, "interface-added", G_CALLBACK (on_interface_added), self); +} + +static void +um_realm_manager_dispose (GObject *obj) +{ + UmRealmManager *self = UM_REALM_MANAGER (obj); + + g_clear_object (&self->provider); + + G_OBJECT_CLASS (um_realm_manager_parent_class)->dispose (obj); +} + +static void +um_realm_manager_class_init (UmRealmManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = um_realm_manager_dispose; + + signals[REALM_ADDED] = g_signal_new ("realm-added", UM_TYPE_REALM_MANAGER, + G_SIGNAL_RUN_FIRST, 0, NULL, NULL, + g_cclosure_marshal_generic, + G_TYPE_NONE, 1, UM_REALM_TYPE_OBJECT); +} + +typedef struct { + GCancellable *cancellable; + UmRealmManager *manager; +} NewClosure; + +static void +new_closure_free (gpointer data) +{ + NewClosure *closure = data; + g_clear_object (&closure->cancellable); + g_clear_object (&closure->manager); + g_slice_free (NewClosure, closure); +} + +static void +on_provider_new (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + NewClosure *closure = g_simple_async_result_get_op_res_gpointer (async); + GError *error = NULL; + UmRealmProvider *provider; + + provider = um_realm_provider_proxy_new_finish (result, &error); + closure->manager->provider = provider; + + if (error == NULL) { + g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (closure->manager->provider), -1); + g_debug ("Created realm manager"); + } else { + g_simple_async_result_take_error (async, error); + } + g_simple_async_result_complete (async); + + g_object_unref (async); +} + +static void +on_manager_new (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + NewClosure *closure = g_simple_async_result_get_op_res_gpointer (async); + GDBusConnection *connection; + GError *error = NULL; + GObject *object; + + object = g_async_initable_new_finish (G_ASYNC_INITABLE (source), result, &error); + if (error == NULL) { + closure->manager = UM_REALM_MANAGER (object); + connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object)); + + g_debug ("Connected to realmd"); + + um_realm_provider_proxy_new (connection, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + "org.freedesktop.realmd", + "/org/freedesktop/realmd", + closure->cancellable, + on_provider_new, g_object_ref (async)); + } else { + g_simple_async_result_take_error (async, error); + g_simple_async_result_complete (async); + } + + g_object_unref (async); +} + +void +um_realm_manager_new (GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *async; + NewClosure *closure; + + g_debug ("Connecting to realmd..."); + + async = g_simple_async_result_new (NULL, callback, user_data, + um_realm_manager_new); + closure = g_slice_new (NewClosure); + closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (async, closure, new_closure_free); + + g_async_initable_new_async (UM_TYPE_REALM_MANAGER, G_PRIORITY_DEFAULT, + cancellable, on_manager_new, g_object_ref (async), + "flags", G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + "name", "org.freedesktop.realmd", + "bus-type", G_BUS_TYPE_SYSTEM, + "object-path", "/org/freedesktop/realmd", + "get-proxy-type-func", um_realm_object_manager_client_get_proxy_type, + NULL); + + g_object_unref (async); +} + +UmRealmManager * +um_realm_manager_new_finish (GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *async; + NewClosure *closure; + + g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, + um_realm_manager_new), NULL); + + async = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (async, error)) + return NULL; + + closure = g_simple_async_result_get_op_res_gpointer (async); + return g_object_ref (closure->manager); +} + +typedef struct { + UmRealmManager *manager; + GCancellable *cancellable; + GList *realms; +} DiscoverClosure; + +static void +discover_closure_free (gpointer data) +{ + DiscoverClosure *discover = data; + g_object_unref (discover->manager); + g_clear_object (&discover->cancellable); + g_list_free_full (discover->realms, g_object_unref); + g_slice_free (DiscoverClosure, discover); +} + +static void +on_provider_discover (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + DiscoverClosure *discover = g_simple_async_result_get_op_res_gpointer (async); + GDBusObject *object; + GError *error = NULL; + gboolean no_membership = FALSE; + gchar **realms; + gint relevance; + gint i; + + um_realm_provider_call_discover_finish (UM_REALM_PROVIDER (source), &relevance, + &realms, result, &error); + if (error == NULL) { + for (i = 0; realms[i]; i++) { + object = g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (discover->manager), realms[i]); + if (object == NULL) { + g_warning ("Realm is not in object manager: %s", realms[i]); + } else { + if (is_realm_with_kerberos_and_membership (object)) { + g_debug ("Discovered realm: %s", realms[i]); + discover->realms = g_list_prepend (discover->realms, object); + } else { + g_debug ("Realm does not support kerberos membership: %s", realms[i]); + no_membership = TRUE; + g_object_unref (object); + } + } + } + g_strfreev (realms); + + if (!discover->realms && no_membership) { + g_simple_async_result_set_error (async, UM_REALM_ERROR, UM_REALM_ERROR_GENERIC, + _("Cannot automatically join this type of domain")); + } + } else { + g_simple_async_result_take_error (async, error); + } + + g_simple_async_result_complete (async); + g_object_unref (async); +} + +void +um_realm_manager_discover (UmRealmManager *self, + const gchar *input, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + DiscoverClosure *discover; + GVariant *options; + + g_return_if_fail (UM_IS_REALM_MANAGER (self)); + g_return_if_fail (input != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + g_debug ("Discovering realms for: %s", input); + + res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, + um_realm_manager_discover); + discover = g_slice_new0 (DiscoverClosure); + discover->manager = g_object_ref (self); + discover->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + g_simple_async_result_set_op_res_gpointer (res, discover, discover_closure_free); + + options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); + + um_realm_provider_call_discover (self->provider, input, options, cancellable, + on_provider_discover, g_object_ref (res)); + + g_object_unref (res); +} + +GList * +um_realm_manager_discover_finish (UmRealmManager *self, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *async; + DiscoverClosure *discover; + GList *realms; + + g_return_val_if_fail (UM_IS_REALM_MANAGER (self), NULL); + g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), + um_realm_manager_discover), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + async = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (async, error)) + return NULL; + + discover = g_simple_async_result_get_op_res_gpointer (async); + if (!discover->realms) { + g_set_error (error, UM_REALM_ERROR, UM_REALM_ERROR_GENERIC, + _("No such domain or realm found")); + return NULL; + } + + realms = g_list_reverse (discover->realms); + discover->realms = NULL; + return realms; +} + +GList * +um_realm_manager_get_realms (UmRealmManager *self) +{ + GList *objects; + GList *realms = NULL; + GList *l; + + g_return_val_if_fail (UM_IS_REALM_MANAGER (self), NULL); + + objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self)); + for (l = objects; l != NULL; l = g_list_next (l)) { + if (is_realm_with_kerberos_and_membership (l->data)) + realms = g_list_prepend (realms, g_object_ref (l->data)); + } + + g_list_free_full (objects, g_object_unref); + return realms; +} + +static void +string_replace (GString *string, + const gchar *find, + const gchar *replace) +{ + const gchar *at; + gssize pos; + + at = strstr (string->str, find); + if (at != NULL) { + pos = at - string->str; + g_string_erase (string, pos, strlen (find)); + g_string_insert (string, pos, replace); + } +} + +gchar * +um_realm_calculate_login (UmRealmCommon *realm, + const gchar *username) +{ + GString *string; + const gchar *const *formats; + gchar *login = NULL; + + formats = um_realm_common_get_login_formats (realm); + if (formats[0] != NULL) { + string = g_string_new (formats[0]); + string_replace (string, "%U", username); + string_replace (string, "%D", um_realm_common_get_name (realm)); + login = g_string_free (string, FALSE); + } + + return login; + +} + +gboolean +um_realm_is_configured (UmRealmObject *realm) +{ + UmRealmCommon *common; + const gchar *configured; + gboolean is = FALSE; + + common = um_realm_object_get_common (realm); + if (common) { + configured = um_realm_common_get_configured (common); + is = configured != NULL && !g_str_equal (configured, ""); + g_object_unref (common); + } + + return is; +} + +static const gchar * +find_supported_credentials (UmRealmKerberosMembership *membership, + const gchar *owner) +{ + const gchar *cred_owner; + const gchar *cred_type; + GVariant *supported; + GVariantIter iter; + + supported = um_realm_kerberos_membership_get_supported_join_credentials (membership); + g_return_val_if_fail (supported != NULL, NULL); + + g_variant_iter_init (&iter, supported); + while (g_variant_iter_loop (&iter, "(&s&s)", &cred_type, &cred_owner)) { + if (g_str_equal (owner, cred_owner)) { + if (g_str_equal (cred_type, "ccache") || + g_str_equal (cred_type, "password")) { + return g_intern_string (cred_type); + } + } + } + + return NULL; +} + +static void +on_realm_join_complete (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data); + + g_debug ("Completed Join() method call"); + + g_simple_async_result_set_op_res_gpointer (async, g_object_ref (result), g_object_unref); + g_simple_async_result_complete_in_idle (async); + g_object_unref (async); +} + +static gboolean +realm_join_as_owner (UmRealmObject *realm, + const gchar *owner, + const gchar *login, + const gchar *password, + GBytes *credentials, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + UmRealmKerberosMembership *membership; + GSimpleAsyncResult *async; + GVariant *contents; + GVariant *options; + GVariant *option; + GVariant *creds; + const gchar *type; + + membership = um_realm_object_get_kerberos_membership (realm); + g_return_val_if_fail (membership != NULL, FALSE); + + type = find_supported_credentials (membership, owner); + if (type == NULL) { + g_debug ("Couldn't find supported credential type for owner: %s", owner); + g_object_unref (membership); + return FALSE; + } + + async = g_simple_async_result_new (G_OBJECT (realm), callback, user_data, + realm_join_as_owner); + + if (g_str_equal (type, "ccache")) { + g_debug ("Using a kerberos credential cache to join the realm"); + contents = g_variant_new_from_data (G_VARIANT_TYPE ("ay"), + g_bytes_get_data (credentials, NULL), + g_bytes_get_size (credentials), + TRUE, (GDestroyNotify)g_bytes_unref, credentials); + + } else if (g_str_equal (type, "password")) { + g_debug ("Using a user/password to join the realm"); + contents = g_variant_new ("(ss)", login, password); + + } else { + g_assert_not_reached (); + } + + creds = g_variant_new ("(ssv)", type, owner, contents); + option = g_variant_new ("{sv}", "manage-system", g_variant_new_boolean (FALSE)); + options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), &option, 1); + + g_debug ("Calling the Join() method with %s credentials", owner); + + um_realm_kerberos_membership_call_join (membership, creds, options, + cancellable, on_realm_join_complete, + g_object_ref (async)); + + g_object_unref (async); + g_object_unref (membership); + + return TRUE; +} + +gboolean +um_realm_join_as_user (UmRealmObject *realm, + const gchar *login, + const gchar *password, + GBytes *credentials, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_val_if_fail (UM_REALM_IS_OBJECT (realm), FALSE); + g_return_val_if_fail (credentials != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (login != NULL, FALSE); + g_return_val_if_fail (password != NULL, FALSE); + g_return_val_if_fail (credentials != NULL, FALSE); + + return realm_join_as_owner (realm, "user", login, password, + credentials, cancellable, callback, user_data); +} + +gboolean +um_realm_join_as_admin (UmRealmObject *realm, + const gchar *login, + const gchar *password, + GBytes *credentials, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_val_if_fail (UM_REALM_IS_OBJECT (realm), FALSE); + g_return_val_if_fail (credentials != NULL, FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (login != NULL, FALSE); + g_return_val_if_fail (password != NULL, FALSE); + g_return_val_if_fail (credentials != NULL, FALSE); + + return realm_join_as_owner (realm, "administrator", login, password, credentials, + cancellable, callback, user_data); +} + +gboolean +um_realm_join_finish (UmRealmObject *realm, + GAsyncResult *result, + GError **error) +{ + UmRealmKerberosMembership *membership; + GError *call_error = NULL; + gchar *dbus_error; + GAsyncResult *async; + + g_return_val_if_fail (UM_REALM_IS_OBJECT (realm), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + membership = um_realm_object_get_kerberos_membership (realm); + g_return_val_if_fail (membership != NULL, FALSE); + + async = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); + um_realm_kerberos_membership_call_join_finish (membership, async, &call_error); + g_object_unref (membership); + + if (call_error == NULL) + return TRUE; + + dbus_error = g_dbus_error_get_remote_error (call_error); + if (dbus_error == NULL) { + g_debug ("Join() failed because of %s", call_error->message); + g_propagate_error (error, call_error); + return FALSE; + } + + g_dbus_error_strip_remote_error (call_error); + + if (g_str_equal (dbus_error, "org.freedesktop.realmd.Error.AuthenticationFailed")) { + g_debug ("Join() failed because of invalid/insufficient credentials"); + g_set_error (error, UM_REALM_ERROR, UM_REALM_ERROR_BAD_LOGIN, + "%s", call_error->message); + g_error_free (call_error); + } else if (g_str_equal (dbus_error, "org.freedesktop.realmd.Error.BadHostname")) { + g_debug ("Join() failed because of invalid/conflicting host name"); + g_set_error (error, UM_REALM_ERROR, UM_REALM_ERROR_BAD_HOSTNAME, + "%s", call_error->message); + g_error_free (call_error); + } else { + g_debug ("Join() failed because of %s", call_error->message); + g_propagate_error (error, call_error); + } + + g_free (dbus_error); + return FALSE; +} + +typedef struct { + gchar *domain; + gchar *realm; + gchar *user; + gchar *password; + GBytes *credentials; +} LoginClosure; + +static void +login_closure_free (gpointer data) +{ + LoginClosure *login = data; + g_free (login->domain); + g_free (login->realm); + g_free (login->user); + g_free (login->password); + g_bytes_unref (login->credentials); + g_slice_free (LoginClosure, login); +} + +static krb5_error_code +login_perform_kinit (krb5_context k5, + const gchar *realm, + const gchar *login, + const gchar *password, + const gchar *filename) +{ + krb5_get_init_creds_opt *opts; + krb5_error_code code; + krb5_principal principal; + krb5_ccache ccache; + krb5_creds creds; + gchar *name; + + name = g_strdup_printf ("%s@%s", login, realm); + code = krb5_parse_name (k5, name, &principal); + + if (code != 0) { + g_debug ("Couldn't parse principal name: %s: %s", + name, krb5_get_error_message (k5, code)); + g_free (name); + return code; + } + + g_debug ("Using principal name to kinit: %s", name); + g_free (name); + + if (filename == NULL) + code = krb5_cc_default (k5, &ccache); + else + code = krb5_cc_resolve (k5, filename, &ccache); + + if (code != 0) { + krb5_free_principal (k5, principal); + g_debug ("Couldn't open credential cache: %s: %s", + filename ? filename : "", + krb5_get_error_message (k5, code)); + return code; + } + + code = krb5_get_init_creds_opt_alloc (k5, &opts); + g_return_val_if_fail (code == 0, code); + + code = krb5_get_init_creds_opt_set_out_ccache (k5, opts, ccache); + g_return_val_if_fail (code == 0, code); + + code = krb5_get_init_creds_password (k5, &creds, principal, + (char *)password, + NULL, 0, 0, NULL, opts); + + krb5_get_init_creds_opt_free (k5, opts); + krb5_cc_close (k5, ccache); + krb5_free_principal (k5, principal); + + if (code == 0) { + g_debug ("kinit succeeded"); + krb5_free_cred_contents (k5, &creds); + } else { + g_debug ("kinit failed: %s", krb5_get_error_message (k5, code)); + } + + return code; +} + +static void +kinit_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + LoginClosure *login = task_data; + krb5_context k5 = NULL; + krb5_error_code code; + GError *error = NULL; + gchar *filename = NULL; + gchar *contents; + gsize length; + gint temp_fd; + + filename = g_build_filename (g_get_user_runtime_dir (), + "um-krb5-creds.XXXXXX", NULL); + temp_fd = g_mkstemp_full (filename, O_RDWR, S_IRUSR | S_IWUSR); + if (temp_fd == -1) { + g_warning ("Couldn't create credential cache file: %s: %s", + filename, g_strerror (errno)); + g_free (filename); + filename = NULL; + } else { + close (temp_fd); + } + + code = krb5_init_context (&k5); + if (code == 0) { + code = login_perform_kinit (k5, login->realm, login->user, + login->password, filename); + } + + switch (code) { + case 0: + if (filename != NULL) { + g_file_get_contents (filename, &contents, &length, &error); + if (error == NULL) { + login->credentials = g_bytes_new_take (contents, length); + g_debug ("Read in credential cache: %s", filename); + } else { + g_warning ("Couldn't read credential cache: %s: %s", + filename, error->message); + g_error_free (error); + } + } + g_task_return_boolean (task, TRUE); + break; + + case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: + case KRB5KDC_ERR_POLICY: + g_task_return_new_error (task, UM_REALM_ERROR, UM_REALM_ERROR_BAD_LOGIN, + _("Cannot log in as %s at the %s domain"), + login->user, login->domain); + break; + case KRB5KDC_ERR_PREAUTH_FAILED: + case KRB5KRB_AP_ERR_BAD_INTEGRITY: + g_task_return_new_error (task, UM_REALM_ERROR, UM_REALM_ERROR_BAD_PASSWORD, + _("Invalid password, please try again")); + break; + case KRB5_PREAUTH_FAILED: + case KRB5KDC_ERR_KEY_EXP: + case KRB5KDC_ERR_CLIENT_REVOKED: + case KRB5KDC_ERR_ETYPE_NOSUPP: + case KRB5_PROG_ETYPE_NOSUPP: + g_task_return_new_error (task, UM_REALM_ERROR, UM_REALM_ERROR_CANNOT_AUTH, + _("Cannot log in as %s at the %s domain"), + login->user, login->domain); + break; + default: + g_task_return_new_error (task, UM_REALM_ERROR, UM_REALM_ERROR_GENERIC, + _("Couldn’t connect to the %s domain: %s"), + login->domain, krb5_get_error_message (k5, code)); + break; + } + + if (filename) { + g_unlink (filename); + g_debug ("Deleted credential cache: %s", filename); + g_free (filename); + } + + if (k5) + krb5_free_context (k5); +} + +void +um_realm_login (UmRealmObject *realm, + const gchar *user, + const gchar *password, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + LoginClosure *login; + UmRealmKerberos *kerberos; + + g_return_if_fail (UM_REALM_IS_OBJECT (realm)); + g_return_if_fail (user != NULL); + g_return_if_fail (password != NULL); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + + kerberos = um_realm_object_get_kerberos (realm); + g_return_if_fail (kerberos != NULL); + + task = g_task_new (realm, cancellable, callback, user_data); + login = g_slice_new0 (LoginClosure); + login->domain = g_strdup (um_realm_kerberos_get_domain_name (kerberos)); + login->realm = g_strdup (um_realm_kerberos_get_realm_name (kerberos)); + login->user = g_strdup (user); + login->password = g_strdup (password); + g_task_set_task_data (task, login, login_closure_free); + + g_task_set_check_cancellable (task, TRUE); + g_task_set_return_on_cancel (task, TRUE); + + g_task_run_in_thread (task, kinit_thread_func); + + g_object_unref (task); + g_object_unref (kerberos); +} + +gboolean +um_realm_login_finish (UmRealmObject *realm, + GAsyncResult *result, + GBytes **credentials, + GError **error) +{ + GTask *task; + LoginClosure *login; + + g_return_val_if_fail (g_task_is_valid (result, realm), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + task = G_TASK (result); + if (!g_task_propagate_boolean (task, error)) + return FALSE; + + login = g_task_get_task_data (task); + if (credentials) { + if (login->credentials) + *credentials = g_bytes_ref (login->credentials); + else + *credentials = NULL; + } + + return TRUE; +} -- cgit v1.2.3