/* * This file is part of Cockpit. * * Copyright (C) 2013 Red Hat, Inc. * * Cockpit 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.1 of the License, or * (at your option) any later version. * * Cockpit 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Cockpit; If not, see . */ #include "config.h" #include "cockpitcreds.h" #include "common/cockpitmemory.h" #include "common/cockpitjson.h" #include #include #include #include #include struct _CockpitCreds { gint refs; gint poisoned; gchar *user; gchar *application; GBytes *password; gchar *rhost; gchar *csrf_token; krb5_context krb5_ctx; krb5_ccache krb5_ccache; gchar *krb5_ccache_name; JsonObject *login_data; GList *bytes; }; G_DEFINE_BOXED_TYPE (CockpitCreds, cockpit_creds, cockpit_creds_ref, cockpit_creds_unref); static void cockpit_creds_free (gpointer data) { CockpitCreds *creds = data; cockpit_creds_poison (creds); g_list_free_full (creds->bytes, (GDestroyNotify)g_bytes_unref); g_free (creds->user); g_free (creds->application); g_free (creds->rhost); g_free (creds->csrf_token); if (creds->krb5_ctx) { if (creds->krb5_ccache) krb5_cc_destroy (creds->krb5_ctx, creds->krb5_ccache); if (creds->krb5_ccache_name) krb5_free_string (creds->krb5_ctx, creds->krb5_ccache_name); krb5_free_context (creds->krb5_ctx); } if (creds->login_data) json_object_unref (creds->login_data); g_free (creds); } /** * cockpit_creds_new: * @application: the application the creds are for * @...: multiple credentials, followed by NULL * * Create a new set of credentials for a user. Each vararg should be * a COCKPIT_CRED_PASSWORD, COCKPIT_CRED_RHOST, or similar constant * followed by the value. * * COCKPIT_CRED_PASSWORD is a GBytes and should contain a null terminated * string with the terminator not included in the count. * * Returns: (transfer full): the new set of credentials. */ CockpitCreds * cockpit_creds_new (const gchar *application, ...) { GBytes *password = NULL; CockpitCreds *creds; const char *type; va_list va; g_return_val_if_fail (application != NULL, NULL); g_return_val_if_fail (!g_str_equal (application, ""), NULL); creds = g_new0 (CockpitCreds, 1); creds->application = g_strdup (application); creds->login_data = NULL; va_start (va, application); for (;;) { type = va_arg (va, const char *); if (type == NULL) break; else if (g_str_equal (type, COCKPIT_CRED_USER)) cockpit_creds_set_user (creds, va_arg (va, const char *)); else if (g_str_equal (type, COCKPIT_CRED_PASSWORD)) password = va_arg (va, GBytes *); else if (g_str_equal (type, COCKPIT_CRED_RHOST)) creds->rhost = g_strdup (va_arg (va, const char *)); else if (g_str_equal (type, COCKPIT_CRED_CSRF_TOKEN)) creds->csrf_token = g_strdup (va_arg (va, const char *)); else g_assert_not_reached (); } va_end (va); if (password) cockpit_creds_set_password (creds, password); creds->refs = 1; creds->poisoned = 0; return creds; } CockpitCreds * cockpit_creds_ref (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); g_atomic_int_inc (&creds->refs); return creds; } void cockpit_creds_unref (gpointer creds) { CockpitCreds *c = creds; g_return_if_fail (creds != NULL); if (g_atomic_int_dec_and_test (&c->refs)) cockpit_creds_free (c); } void cockpit_creds_poison (CockpitCreds *creds) { g_return_if_fail (creds != NULL); g_atomic_int_set (&creds->poisoned, 1); cockpit_creds_set_password (creds, NULL); } const gchar * cockpit_creds_get_user (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); return creds->user; } void cockpit_creds_set_user (CockpitCreds *creds, const gchar *user) { g_return_if_fail (creds != NULL); if (user != creds->user) { g_free (creds->user); creds->user = g_strdup (user); } } const gchar * cockpit_creds_get_application (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); return creds->application; } GBytes * cockpit_creds_get_password (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); if (g_atomic_int_get (&creds->poisoned)) return NULL; return creds->password; } void cockpit_creds_set_password (CockpitCreds *creds, GBytes *password) { gpointer data; gsize length; g_return_if_fail (creds != NULL); if (creds->password) { data = (gpointer)g_bytes_get_data (creds->password, &length); cockpit_memory_clear (data, length); creds->password = NULL; } if (password) { data = (gpointer)g_bytes_get_data (password, &length); g_assert (((gchar *)data)[length] == '\0'); creds->password = g_bytes_ref (password); creds->bytes = g_list_prepend (creds->bytes, creds->password); } } const gchar * cockpit_creds_get_csrf_token (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); return creds->csrf_token; } /** * cockpit_creds_get_login_data * @creds: the credentials * * Get any login data, or NULL * if none present. * * Returns: A JsonObject (transfer none) or NULL */ JsonObject * cockpit_creds_get_login_data (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); return creds->login_data; } void cockpit_creds_set_login_data (CockpitCreds *creds, JsonObject *login_data) { g_return_if_fail (creds != NULL); if (login_data) json_object_ref (login_data); if (creds->login_data) json_object_unref (creds->login_data); creds->login_data = login_data; } /** * cockpit_creds_get_rhost: * @creds: the credentials * * Get the remote host credential, or NULL * if none present. * * Returns: the remote host or NULL */ const gchar * cockpit_creds_get_rhost (CockpitCreds *creds) { g_return_val_if_fail (creds != NULL, NULL); return creds->rhost; } JsonObject * cockpit_creds_to_json (CockpitCreds *creds) { JsonObject *object = NULL; JsonObject *login_data = NULL; object = json_object_new (); json_object_set_string_member (object, "csrf-token", cockpit_creds_get_csrf_token (creds)); login_data = cockpit_creds_get_login_data (creds); if (login_data) json_object_set_object_member (object, "login-data", json_object_ref (login_data)); return object; }