aboutsummaryrefslogtreecommitdiff
path: root/src/ka-dialog.c
diff options
context:
space:
mode:
authorGuido Günther <agx@sigxcpu.org>2011-09-26 22:20:52 +0200
committerGuido Günther <agx@sigxcpu.org>2011-09-26 22:20:52 +0200
commit85df09c7a65dab7c54e1e35b0685f8677355710c (patch)
tree49c3d1ae8ceea68ad29185c40403c0add4b68f28 /src/ka-dialog.c
parentNew upstream version 3.0.1 (diff)
downloadkrb5-auth-dialog-85df09c7a65dab7c54e1e35b0685f8677355710c.tar.gz
krb5-auth-dialog-85df09c7a65dab7c54e1e35b0685f8677355710c.tar.bz2
krb5-auth-dialog-85df09c7a65dab7c54e1e35b0685f8677355710c.zip
New upstream version 3.2.0
Diffstat (limited to 'src/ka-dialog.c')
-rw-r--r--src/ka-dialog.c1138
1 files changed, 0 insertions, 1138 deletions
diff --git a/src/ka-dialog.c b/src/ka-dialog.c
deleted file mode 100644
index fffd2fd..0000000
--- a/src/ka-dialog.c
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*
- * Copyright (C) 2004,2005,2006 Red Hat, Inc.
- * Authored by Christopher Aillon <caillon@redhat.com>
- *
- * Copyright (C) 2008,2009,2010 Guido Guenther <agx@sigxcpu.org>
- *
- * 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, 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <time.h>
-#include <krb5.h>
-#include <stdio.h>
-#include <sys/wait.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include <glib/gi18n.h>
-#include <gio/gio.h>
-
-#include "secmem-util.h"
-#include "memory.h"
-
-#include "ka-dialog.h"
-#include "ka-applet-priv.h"
-#include "ka-pwdialog.h"
-#include "ka-dbus.h"
-#include "ka-tools.h"
-#include "ka-tickets.h"
-
-#ifdef ENABLE_NETWORK_MANAGER
-#include <nm-client.h>
-
-#if !defined(NM_CHECK_VERSION)
-#define NM_CHECK_VERSION(x,y,z) 0
-#endif
-#endif
-
-#ifdef HAVE_HX509_ERR_H
-#include <hx509_err.h>
-#endif
-
-static krb5_context kcontext;
-static krb5_principal kprincipal;
-static krb5_timestamp creds_expiry;
-static krb5_timestamp canceled_creds_expiry;
-static gboolean canceled;
-static gboolean invalid_auth;
-static gboolean always_run;
-static gboolean is_online = TRUE;
-
-static int grab_credentials (KaApplet *applet);
-static int ka_renew_credentials (KaApplet *applet);
-static gboolean ka_get_tgt_from_ccache (krb5_context context,
- krb5_creds *creds);
-
-#ifdef ENABLE_NETWORK_MANAGER
-NMClient *nm_client;
-#endif
-
-/* YAY for different Kerberos implementations */
-static int
-get_cred_forwardable (krb5_creds *creds)
-{
-#if defined(HAVE_KRB5_CREDS_TICKET_FLAGS) && defined(TKT_FLG_FORWARDABLE)
- return creds->ticket_flags & TKT_FLG_FORWARDABLE;
-#elif defined(HAVE_KRB5_CREDS_FLAGS_B_FORWARDABLE)
- return creds->flags.b.forwardable;
-#elif defined(HAVE_KRB5_CREDS_FLAGS) && defined(KDC_OPT_FORWARDABLE)
- return creds->flags & KDC_OPT_FORWARDABLE;
-#endif
-}
-
-static int
-get_cred_renewable (krb5_creds *creds)
-{
-#if defined(HAVE_KRB5_CREDS_TICKET_FLAGS) && defined(TKT_FLG_RENEWABLE)
- return creds->ticket_flags & TKT_FLG_RENEWABLE;
-#elif defined(HAVE_KRB5_CREDS_FLAGS_B_RENEWABLE)
- return creds->flags.b.renewable;
-#elif defined(HAVE_KRB5_CREDS_FLAGS) && defined(KDC_OPT_RENEWABLE)
- return creds->flags & KDC_OPT_RENEWABLE;
-#endif
-}
-
-static krb5_error_code
-get_renewed_creds (krb5_context context,
- krb5_creds *creds,
- krb5_principal client,
- krb5_ccache ccache, char *in_tkt_service)
-{
-#ifdef HAVE_KRB5_GET_RENEWED_CREDS
- return krb5_get_renewed_creds (context, creds, client, ccache,
- in_tkt_service);
-#else
- return 1; /* XXX is there something better to return? */
-#endif
-}
-
-static int
-get_cred_proxiable (krb5_creds *creds)
-{
-#if defined(HAVE_KRB5_CREDS_TICKET_FLAGS) && defined(TKT_FLG_PROXIABLE)
- return creds->ticket_flags & TKT_FLG_PROXIABLE;
-#elif defined(HAVE_KRB5_CREDS_FLAGS_B_PROXIABLE)
- return creds->flags.b.proxiable;
-#elif defined(HAVE_KRB5_CREDS_FLAGS) && defined(KDC_OPT_PROXIABLE)
- return creds->flags & KDC_OPT_PROXIABLE;
-#endif
-}
-
-static size_t
-get_principal_realm_length (krb5_principal p)
-{
-#if defined(HAVE_KRB5_PRINCIPAL_REALM_AS_STRING)
- return strlen (p->realm);
-#elif defined(HAVE_KRB5_PRINCIPAL_REALM_AS_DATA)
- return p->realm.length;
-#endif
-}
-
-static const char *
-get_principal_realm_data (krb5_principal p)
-{
-#if defined(HAVE_KRB5_PRINCIPAL_REALM_AS_STRING)
- return p->realm;
-#elif defined(HAVE_KRB5_PRINCIPAL_REALM_AS_DATA)
- return p->realm.data;
-#endif
-}
-
-static void
-ka_krb5_free_error_message (krb5_context context, const char *msg)
-{
-#if defined(HAVE_KRB5_FREE_ERROR_MESSAGE)
- krb5_free_error_message (context, msg);
-#elif defined(HAVE_KRB5_FREE_ERROR_STRING)
- krb5_free_error_string (context, (char *) msg);
-#else
-# error No way to free error string.
-#endif
-}
-
-/*
- * Returns a descriptive error message or kerberos related error
- * returned pointer must be freed using g_free().
- */
-static char *
-ka_get_error_message (krb5_context context, krb5_error_code err)
-{
- char *msg = NULL;
-
-#if defined(HAVE_KRB5_GET_ERROR_MESSAGE)
- const char *krberr;
-
- krberr = krb5_get_error_message (context, err);
- msg = g_strdup (krberr);
- ka_krb5_free_error_message (context, krberr);
-#else
-# error No detailed error message information
-#endif
- if (msg == NULL)
- msg = g_strdup (_("unknown error"));
- return msg;
-}
-
-
-static void
-ka_krb5_cc_clear_mcred (krb5_creds *mcred)
-{
-#if defined HAVE_KRB5_CC_CLEAR_MCRED
- krb5_cc_clear_mcred (mcred);
-#else
- memset (mcred, 0, sizeof (krb5_creds));
-#endif
-}
-
-
-/* ***************************************************************** */
-/* ***************************************************************** */
-
-/* log a kerberos error messge */
-static void
-ka_log_error_message (const char *prefix, krb5_context context,
- krb5_error_code err)
-{
- char *errmsg = ka_get_error_message (context, err);
-
- g_warning ("%s: %s", prefix, errmsg);
- g_free (errmsg);
-}
-
-
-static gboolean
-credentials_expiring_real (KaApplet *applet)
-{
- krb5_creds my_creds;
- krb5_timestamp now;
- gboolean retval = FALSE;
-
- memset (&my_creds, 0, sizeof (my_creds));
- ka_applet_set_tgt_renewable (applet, FALSE);
- if (!ka_get_tgt_from_ccache (kcontext, &my_creds)) {
- creds_expiry = 0;
- retval = TRUE;
- goto out;
- }
-
- /* copy principal from cache if any */
- if (krb5_principal_compare (kcontext, my_creds.client, kprincipal)) {
- krb5_free_principal (kcontext, kprincipal);
- krb5_copy_principal (kcontext, my_creds.client, &kprincipal);
- }
- creds_expiry = my_creds.times.endtime;
- if ((krb5_timeofday (kcontext, &now) == 0) &&
- (now + ka_applet_get_pw_prompt_secs (applet) >
- my_creds.times.endtime))
- retval = TRUE;
-
- /* If our creds are expiring, determine whether they are renewable.
- * If the expiry is already at the renew_till time, don't consider
- * credentials renewable */
- if (retval && get_cred_renewable (&my_creds)
- && my_creds.times.renew_till > now
- && my_creds.times.renew_till > creds_expiry) {
- ka_applet_set_tgt_renewable (applet, TRUE);
- }
-
- out:
- krb5_free_cred_contents (kcontext, &my_creds);
- ka_applet_update_status (applet, creds_expiry);
- return retval;
-}
-
-
-/* time in seconds the tgt will be still valid */
-int
-ka_tgt_valid_seconds ()
-{
- krb5_timestamp now;
-
- if (krb5_timeofday (kcontext, &now))
- return 0;
-
- return (creds_expiry - now);
-}
-
-
-/* return credential cache filename, strip "FILE:" prefix if necessary */
-static const char *
-ka_ccache_filename (void)
-{
- const gchar *name;
-
- name = krb5_cc_default_name (kcontext);
- if (g_str_has_prefix (name, "FILE:"))
- return strchr (name, ':') + 1;
- else if (g_str_has_prefix (name, "SCC:"))
- g_warning ("Cannot monitor sqlite based cache '%s'", name);
- else
- g_warning ("Unsupported cache type for '%s'", name);
- return NULL;
-}
-
-
-static void
-ka_format_time (time_t t, gchar *ts, size_t len)
-{
- g_strlcpy (ts, ctime (&t) + 4, len);
- ts[15] = 0;
-}
-
-
-/* fill in service tickets data */
-gboolean
-ka_get_service_tickets (GtkListStore * tickets)
-{
- krb5_cc_cursor cursor;
- krb5_creds creds;
- krb5_error_code ret;
- GtkTreeIter iter;
- krb5_ccache ccache;
- char *name;
- krb5_timestamp sec;
- gchar start_time[128], end_time[128], end_time_markup[256];
- gboolean retval = FALSE;
-
- gtk_list_store_clear (tickets);
-
- krb5_timeofday (kcontext, &sec);
- ret = krb5_cc_default (kcontext, &ccache);
- g_return_val_if_fail (!ret, FALSE);
-
- ret = krb5_cc_start_seq_get (kcontext, ccache, &cursor);
- if (ret) {
- ka_log_error_message ("krb5_cc_start_seq_get", kcontext, ret);
-
- /* if the file doesn't exist, it's not an error if we can't
- * parse it */
- if (!g_file_test (ka_ccache_filename (), G_FILE_TEST_EXISTS))
- gtk_list_store_append (tickets, &iter);
- gtk_list_store_set (tickets, &iter,
- PRINCIPAL_COLUMN, _("Your ticket cache is currently empty"),
- START_TIME_COLUMN, 0,
- END_TIME_COLUMN, 0,
- FORWARDABLE_COLUMN, FALSE,
- RENEWABLE_COLUMN, FALSE,
- PROXIABLE_COLUMN, FALSE, -1);
- retval = TRUE;
- goto out;
- }
-
- while ((ret = krb5_cc_next_cred (kcontext, ccache, &cursor, &creds)) == 0) {
- gboolean renewable, proxiable, forwardable;
-
- if (creds.times.starttime)
- ka_format_time (creds.times.starttime, start_time,
- sizeof (start_time));
- else
- ka_format_time (creds.times.authtime, start_time,
- sizeof (start_time));
-
- ka_format_time (creds.times.endtime, end_time, sizeof (end_time));
- if (creds.times.endtime > sec)
- strcpy (end_time_markup, end_time);
- else
- g_snprintf (end_time_markup, sizeof (end_time_markup),
- "%s <span foreground=\"red\" style=\"italic\">(%s)</span>",
- end_time, _("Expired"));
-
- forwardable = get_cred_forwardable (&creds);
- renewable = get_cred_renewable (&creds);
- proxiable = get_cred_proxiable (&creds);
-
- ret = krb5_unparse_name (kcontext, creds.server, &name);
- if (!ret) {
- gtk_list_store_append (tickets, &iter);
- gtk_list_store_set (tickets, &iter,
- PRINCIPAL_COLUMN, name,
- START_TIME_COLUMN, start_time,
- END_TIME_COLUMN, end_time_markup,
- FORWARDABLE_COLUMN, forwardable,
- RENEWABLE_COLUMN, renewable,
- PROXIABLE_COLUMN, proxiable, -1);
- free (name);
- } else
- ka_log_error_message ("krb5_unparse_name", kcontext, ret);
- krb5_free_cred_contents (kcontext, &creds);
- }
- if (ret != KRB5_CC_END)
- ka_log_error_message ("krb5_cc_get_next", kcontext, ret);
-
- ret = krb5_cc_end_seq_get (kcontext, ccache, &cursor);
- if (ret)
- ka_log_error_message ("krb5_cc_end_seq_get", kcontext, ret);
-
- retval = TRUE;
- out:
- ret = krb5_cc_close (kcontext, ccache);
- g_return_val_if_fail (!ret, FALSE);
-
- return retval;
-}
-
-
-/* Check for things we have to do while the password dialog is open */
-static gboolean
-krb5_auth_dialog_do_updates (gpointer data)
-{
- KaApplet *applet = KA_APPLET (data);
- KaPwDialog *pwdialog = ka_applet_get_pwdialog (applet);
-
- g_return_val_if_fail (pwdialog != NULL, FALSE);
- /* Update creds_expiry and close the applet if we got the creds by other means (e.g. kinit) */
- if (!credentials_expiring_real (applet))
- ka_pwdialog_hide (pwdialog, FALSE);
-
- /* Update the expiry information in the dialog */
- ka_pwdialog_status_update (pwdialog);
- return TRUE;
-}
-
-
-static krb5_error_code
-auth_dialog_prompter (krb5_context ctx G_GNUC_UNUSED,
- void *data,
- const char *name G_GNUC_UNUSED,
- const char *banner G_GNUC_UNUSED,
- int num_prompts, krb5_prompt prompts[])
-{
- KaApplet *applet = KA_APPLET (data);
- KaPwDialog *pwdialog = ka_applet_get_pwdialog (applet);
- krb5_error_code errcode;
- int i;
-
- errcode = KRB5KRB_ERR_GENERIC;
- canceled = FALSE;
- canceled_creds_expiry = 0;
-
- if (banner && !num_prompts)
- ka_applet_set_msg (applet, banner);
-
- for (i = 0; i < num_prompts; i++) {
- const gchar *password = NULL;
- int password_len = 0;
- int response;
- guint32 source_id;
-
- errcode = KRB5_LIBOS_CANTREADPWD;
-
- source_id =
- g_timeout_add_seconds (5,
- (GSourceFunc) krb5_auth_dialog_do_updates,
- applet);
- ka_pwdialog_setup (pwdialog, (gchar *) prompts[i].prompt,
- invalid_auth);
- response = ka_pwdialog_run (pwdialog);
- switch (response) {
- case GTK_RESPONSE_OK:
- password = ka_pwdialog_get_password (pwdialog);
- password_len = strlen (password);
- break;
- case GTK_RESPONSE_DELETE_EVENT:
- case GTK_RESPONSE_CANCEL:
- canceled = TRUE;
- break;
- case GTK_RESPONSE_NONE:
- break;
- default:
- g_warning ("Unknown Response: %d", response);
- g_assert_not_reached ();
- }
- g_source_remove (source_id);
-
- if (!password)
- goto cleanup;
- if (password_len + 1 > prompts[i].reply->length) {
- g_warning ("Password too long %d/%d", password_len + 1,
- prompts[i].reply->length);
- goto cleanup;
- }
-
- memcpy (prompts[i].reply->data, (char *) password, password_len + 1);
- prompts[i].reply->length = password_len;
- errcode = 0;
- }
- cleanup:
- ka_pwdialog_hide (pwdialog, TRUE);
- /* Reset this, so we know the next time we get a TRUE value, it is accurate. */
- invalid_auth = FALSE;
-
- return errcode;
-}
-
-
-#ifdef ENABLE_NETWORK_MANAGER
-static void
-ka_nm_client_state_changed_cb (NMClient * client,
- GParamSpec *pspec G_GNUC_UNUSED, gpointer data)
-{
- NMState state;
- gboolean *online = (gboolean *) data;
-
- state = nm_client_get_state (client);
- switch (state) {
- case NM_STATE_UNKNOWN:
- case NM_STATE_ASLEEP:
- case NM_STATE_CONNECTING:
- KA_DEBUG ("Network state: %d", state);
- /* do nothing */
- break;
-#if NM_CHECK_VERSION(0,8,992)
- case NM_STATE_DISCONNECTING:
-#endif
- case NM_STATE_DISCONNECTED:
- KA_DEBUG ("Network disconnected");
- *online = FALSE;
- break;
-#if NM_CHECK_VERSION(0,8,992)
- case NM_STATE_CONNECTED_LOCAL:
- case NM_STATE_CONNECTED_SITE:
- case NM_STATE_CONNECTED_GLOBAL:
-#else
- case NM_STATE_CONNECTED:
-#endif
- KA_DEBUG ("Network connected");
- *online = TRUE;
- break;
- }
-}
-#endif
-
-/* credentials expiring timer */
-static gboolean
-credentials_expiring (gpointer *data)
-{
- KaApplet *applet = KA_APPLET (data);
-
- KA_DEBUG ("Checking expiry <%ds", ka_applet_get_pw_prompt_secs (applet));
- if (credentials_expiring_real (applet) && is_online) {
- KA_DEBUG ("Expiry @ %ld", creds_expiry);
-
- if (!ka_renew_credentials (applet))
- KA_DEBUG ("Credentials renewed");
- }
- ka_applet_update_status (applet, creds_expiry);
-
- return TRUE;
-}
-
-
-/* run once, then terminate the timer */
-static gboolean
-credentials_expiring_once (gpointer *data)
-{
- credentials_expiring (data);
- return FALSE;
-}
-
-
-/*
- * set ticket options by looking at krb5.conf and gconf
- */
-static void
-ka_set_ticket_options (KaApplet *applet, krb5_context context,
- krb5_get_init_creds_opt * out,
- const char *pk_userid G_GNUC_UNUSED,
- const char *pk_anchors G_GNUC_UNUSED)
-{
- gboolean flag;
-
-#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS
- krb5_get_init_creds_opt_set_default_flags (context, PACKAGE,
- krb5_principal_get_realm
- (context, kprincipal), out);
-#endif
- g_object_get (applet, "tgt-forwardable", &flag, NULL);
- if (flag)
- krb5_get_init_creds_opt_set_forwardable (out, flag);
- g_object_get (applet, "tgt-proxiable", &flag, NULL);
- if (flag)
- krb5_get_init_creds_opt_set_proxiable (out, flag);
- g_object_get (applet, "tgt-renewable", &flag, NULL);
- if (flag) {
- krb5_deltat r = 3600 * 24 * 30; /* 1 month */
-
- krb5_get_init_creds_opt_set_renew_life (out, r);
- }
-#if ENABLE_PKINIT && HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PA
- /* pkinit optins for MIT Kerberos */
- if (pk_userid && strlen (pk_userid)) {
- KA_DEBUG ("pkinit with '%s'", pk_userid);
- krb5_get_init_creds_opt_set_pa (context, out,
- "X509_user_identity", pk_userid);
- if (pk_anchors && strlen (pk_anchors)) {
- KA_DEBUG ("pkinit anchors '%s'", pk_anchors);
- krb5_get_init_creds_opt_set_pa (context, out,
- "X509_anchors", pk_anchors);
- }
- }
-#endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PA */
-}
-
-
-#if ENABLE_PKINIT && HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PKINIT
-static krb5_error_code
-ka_auth_heimdal_pkinit (KaApplet *applet, krb5_creds *creds,
- const char *pk_userid, const char *pk_anchors)
-{
- krb5_get_init_creds_opt *opts = NULL;
- krb5_error_code retval;
- const char *pkinit_anchors = NULL;
-
- KA_DEBUG ("pkinit with '%s'", pk_userid);
- if (pk_anchors && strlen (pk_anchors)) {
- pkinit_anchors = pk_anchors;
- KA_DEBUG ("pkinit anchors '%s'", pkinit_anchors);
- }
-
- if ((retval = krb5_get_init_creds_opt_alloc (kcontext, &opts)))
- goto out;
-
- ka_set_ticket_options (applet, kcontext, opts, NULL, NULL);
- retval = krb5_get_init_creds_opt_set_pkinit (kcontext, opts, kprincipal, pk_userid, pkinit_anchors, NULL, NULL, 0, /* pk_use_enc_key */
- auth_dialog_prompter, applet, /* data */
- NULL); /* passwd */
- KA_DEBUG ("pkinit returned with %d", retval);
- if (retval)
- goto out;
-
- retval = krb5_get_init_creds_password (kcontext, creds, kprincipal,
- NULL, auth_dialog_prompter, applet,
- 0, NULL, opts);
- out:
- if (opts)
- krb5_get_init_creds_opt_free (kcontext, opts);
- return retval;
-}
-#endif /* ! ENABLE_PKINIT */
-
-static krb5_error_code
-ka_auth_password (KaApplet *applet, krb5_creds *creds,
- const char *pk_userid, const char *pk_anchors)
-{
- krb5_error_code retval;
- krb5_get_init_creds_opt *opts = NULL;
-
- if ((retval = krb5_get_init_creds_opt_alloc (kcontext, &opts)))
- goto out;
- ka_set_ticket_options (applet, kcontext, opts, pk_userid, pk_anchors);
-
- retval = krb5_get_init_creds_password (kcontext, creds, kprincipal,
- NULL, auth_dialog_prompter, applet,
- 0, NULL, opts);
- out:
- if (opts)
- krb5_get_init_creds_opt_free (kcontext, opts);
- return retval;
-}
-
-static krb5_error_code
-ka_parse_name (KaApplet *applet, krb5_context krbcontext,
- krb5_principal * kprinc)
-{
- krb5_error_code ret;
- gchar *principal = NULL;
-
- if (*kprinc != NULL)
- krb5_free_principal (krbcontext, *kprinc);
-
- g_object_get (applet, "principal", &principal, NULL);
- ret = krb5_parse_name (krbcontext, principal, kprinc);
-
- g_free (principal);
- return ret;
-}
-
-
-/*
- * return current principal in text form
- *
- * caller needs to free the returned result using g_free();
- */
-char *
-ka_unparse_name ()
-{
- char *princ, *gprinc = NULL;
- krb5_error_code err;
-
- if (!kprincipal)
- goto out;
-
- if ((err = krb5_unparse_name (kcontext, kprincipal, &princ))) {
- ka_log_error_message (__func__, kcontext, err);
- goto out;
- }
-
- gprinc = g_strdup (princ);
- free (princ);
- out:
- return gprinc;
-}
-
-
-static void
-ccache_changed_cb (GFileMonitor * monitor G_GNUC_UNUSED,
- GFile * file,
- GFile * other_file G_GNUC_UNUSED,
- GFileMonitorEvent event_type, gpointer data)
-{
- KaApplet *applet = KA_APPLET (data);
- gchar *ccache_name = g_file_get_path (file);
-
- switch (event_type) {
- case G_FILE_MONITOR_EVENT_DELETED:
- case G_FILE_MONITOR_EVENT_CREATED:
- case G_FILE_MONITOR_EVENT_CHANGED:
- KA_DEBUG ("%s changed", ccache_name);
- credentials_expiring ((gpointer) applet);
- break;
- default:
- KA_DEBUG ("%s unhandled event: %d", ccache_name, event_type);
- }
- g_free (ccache_name);
-}
-
-
-static GFileMonitor *
-monitor_ccache (KaApplet *applet)
-{
- const gchar *ccache_name;
- GFile *ccache;
- GFileMonitor *monitor = NULL;
- GError *err = NULL;
-
- ccache_name = ka_ccache_filename ();
- g_return_val_if_fail (ccache_name != NULL, FALSE);
-
- ccache = g_file_new_for_path (ccache_name);
- monitor = g_file_monitor_file (ccache, G_FILE_MONITOR_NONE, NULL, &err);
- g_assert ((!monitor && err) || (monitor && !err));
- if (!monitor) {
- /* cache disappeared? */
- if (err->code == G_FILE_ERROR_NOENT)
- credentials_expiring ((gpointer) applet);
- else
- g_warning ("Failed to monitor %s: %s", ccache_name, err->message);
- } else {
- /* g_file_monitor_set_rate_limit(monitor, 10*1000); */
- g_signal_connect (monitor, "changed", G_CALLBACK (ccache_changed_cb),
- applet);
- KA_DEBUG ("Monitoring %s", ccache_name);
- }
- g_object_unref (ccache);
- g_clear_error (&err);
- return monitor;
-}
-
-
-/* grab credentials interactively */
-static int
-grab_credentials (KaApplet *applet)
-{
- krb5_error_code retval = KRB5_KDC_UNREACH;
- krb5_creds my_creds;
- krb5_ccache ccache;
- gchar *pk_userid = NULL;
- gchar *pk_anchors = NULL;
- gchar *errmsg = NULL;
- gboolean pw_auth = TRUE;
-
- memset (&my_creds, 0, sizeof (my_creds));
-
- retval = ka_parse_name (applet, kcontext, &kprincipal);
- if (retval)
- goto out2;
-
- retval = krb5_cc_default (kcontext, &ccache);
- if (retval)
- goto out2;
-
- g_object_get (applet, "pk-userid", &pk_userid,
- "pk-anchors", &pk_anchors, NULL);
-#if ENABLE_PKINIT && HAVE_HX509_ERR_H && HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PKINIT
- /* pk_userid set: try pkinit */
- if (pk_userid && strlen (pk_userid)) {
- retval = ka_auth_heimdal_pkinit (applet, &my_creds,
- pk_userid, pk_anchors);
- /* other error than: "no token found" - no need to try password auth: */
- if (retval != HX509_PKCS11_NO_TOKEN && retval != HX509_PKCS11_NO_SLOT)
- pw_auth = FALSE;
- }
-#endif /* ENABLE_PKINIT */
- if (pw_auth)
- retval = ka_auth_password (applet, &my_creds, pk_userid, pk_anchors);
-
- creds_expiry = my_creds.times.endtime;
- if (canceled)
- canceled_creds_expiry = creds_expiry;
- if (retval) {
- switch (retval) {
- case KRB5KDC_ERR_PREAUTH_FAILED:
- case KRB5KRB_AP_ERR_BAD_INTEGRITY:
-#ifdef HAVE_HX509_ERR_H
- case HX509_PKCS11_LOGIN:
-#endif /* Invalid password/pin, try again. */
- invalid_auth = TRUE;
- break;
- default:
- errmsg = ka_get_error_message (kcontext, retval);
- KA_DEBUG ("Auth failed with %d: %s", retval, errmsg);
- g_free (errmsg);
- break;
- }
- goto out;
- }
- retval = krb5_cc_initialize (kcontext, ccache, kprincipal);
- if (retval)
- goto out;
-
- retval = krb5_cc_store_cred (kcontext, ccache, &my_creds);
- if (retval)
- goto out;
- out:
- krb5_free_cred_contents (kcontext, &my_creds);
- krb5_cc_close (kcontext, ccache);
- out2:
- g_free (pk_userid);
- return retval;
-}
-
-/* try to renew the credentials noninteractively */
-static int
-ka_renew_credentials (KaApplet *applet)
-{
- krb5_error_code retval;
- krb5_creds my_creds;
- krb5_ccache ccache;
-
- memset (&my_creds, 0, sizeof (my_creds));
- if (kprincipal == NULL) {
- retval = ka_parse_name (applet, kcontext, &kprincipal);
- if (retval)
- return retval;
- }
-
- retval = krb5_cc_default (kcontext, &ccache);
- if (retval)
- return retval;
-
- retval = ka_get_tgt_from_ccache (kcontext, &my_creds);
- if (!retval) {
- krb5_free_cred_contents (kcontext, &my_creds);
- krb5_cc_close (kcontext, ccache);
- return -1;
- }
-
- if (ka_applet_get_tgt_renewable (applet)) {
- krb5_free_cred_contents (kcontext, &my_creds);
- retval =
- get_renewed_creds (kcontext, &my_creds, kprincipal, ccache, NULL);
- if (retval)
- goto out;
-
- retval = krb5_cc_initialize (kcontext, ccache, kprincipal);
- if (retval) {
- ka_log_error_message ("krb5_cc_initialize", kcontext, retval);
- goto out;
- }
- retval = krb5_cc_store_cred (kcontext, ccache, &my_creds);
- if (retval) {
- ka_log_error_message ("krb5_cc_store_cred", kcontext, retval);
- goto out;
- }
- ka_applet_signal_emit (applet, KA_SIGNAL_RENEWED_TGT,
- my_creds.times.endtime);
- }
- out:
- if (!retval)
- creds_expiry = my_creds.times.endtime;
- krb5_free_cred_contents (kcontext, &my_creds);
- krb5_cc_close (kcontext, ccache);
- return retval;
-}
-
-
-/* get principal associated with the default credentials cache - if found store
- * it in *creds, return FALSE otwerwise */
-static gboolean
-ka_get_tgt_from_ccache (krb5_context context, krb5_creds *creds)
-{
- krb5_ccache ccache;
- krb5_creds pattern;
- krb5_principal principal;
- gboolean ret = FALSE;
-
- ka_krb5_cc_clear_mcred (&pattern);
-
- if (krb5_cc_default (context, &ccache))
- return FALSE;
-
- if (krb5_cc_get_principal (context, ccache, &principal))
- goto out;
-
- if (krb5_build_principal_ext (context, &pattern.server,
- get_principal_realm_length (principal),
- get_principal_realm_data (principal),
- KRB5_TGS_NAME_SIZE,
- KRB5_TGS_NAME,
- get_principal_realm_length (principal),
- get_principal_realm_data (principal), 0)) {
- goto out_free_princ;
- }
- pattern.client = principal;
- if (!krb5_cc_retrieve_cred (context, ccache, 0, &pattern, creds))
- ret = TRUE;
-
- krb5_free_principal (context, pattern.server);
- out_free_princ:
- krb5_free_principal (context, principal);
- out:
- krb5_cc_close (context, ccache);
- return ret;
-}
-
-static gboolean
-using_krb5 (void)
-{
- krb5_error_code err;
- gboolean have_tgt = FALSE;
- krb5_creds creds;
-
- err = krb5_init_context (&kcontext);
- if (err)
- return FALSE;
-
- have_tgt = ka_get_tgt_from_ccache (kcontext, &creds);
- if (have_tgt) {
- krb5_copy_principal (kcontext, creds.client, &kprincipal);
- krb5_free_cred_contents (kcontext, &creds);
- }
- return have_tgt;
-}
-
-
-gboolean
-ka_destroy_ccache (KaApplet *applet)
-{
- krb5_ccache ccache;
- const char *cache;
- krb5_error_code ret;
-
- cache = krb5_cc_default_name (kcontext);
- ret = krb5_cc_resolve (kcontext, cache, &ccache);
- ret = krb5_cc_destroy (kcontext, ccache);
-
- credentials_expiring_real (applet);
-
- if (ret)
- return FALSE;
- else
- return TRUE;
-}
-
-
-/*
- * check if we have valid credentials for the requested principal - if not, grab them
- * principal: requested principal - if empty use default
- */
-gboolean
-ka_check_credentials (KaApplet *applet, const char *newprincipal)
-{
- gboolean success = FALSE;
- int retval;
- char *principal;
-
- g_object_get (applet, "principal", &principal, NULL);
-
- if (strlen (newprincipal)) {
- krb5_principal knewprinc;
-
- /* no ticket cache: is requested princ the one from our config? */
- if (!kprincipal && g_strcmp0 (principal, newprincipal)) {
- KA_DEBUG ("Requested principal %s not %s", principal,
- newprincipal);
- goto out;
- }
-
- /* ticket cache: check if the requested principal is the one we have */
- retval = krb5_parse_name (kcontext, newprincipal, &knewprinc);
- if (retval) {
- g_warning ("Cannot parse principal '%s'", newprincipal);
- goto out;
- }
- if (kprincipal
- && !krb5_principal_compare (kcontext, kprincipal, knewprinc)) {
- KA_DEBUG ("Current Principal '%s' not '%s'", principal,
- newprincipal);
- krb5_free_principal (kcontext, knewprinc);
- goto out;
- }
- krb5_free_principal (kcontext, knewprinc);
- }
-
- if (credentials_expiring_real (applet)) {
- if (!is_online)
- success = FALSE;
- else
- success = ka_grab_credentials (applet);
- } else
- success = TRUE;
- out:
- g_free (principal);
- return success;
-}
-
-
-/* initiate grabbing of credentials (e.g. on leftclick of tray icon) */
-gboolean
-ka_grab_credentials (KaApplet *applet)
-{
- int retval;
- int success = FALSE;
- KaPwDialog *pwdialog = ka_applet_get_pwdialog (applet);
-
- ka_pwdialog_set_persist (pwdialog, TRUE);
- do {
- retval = grab_credentials (applet);
- if (invalid_auth)
- continue;
- if (canceled)
- break;
- if (retval) {
- gchar *errmsg;
-
- errmsg = ka_get_error_message (kcontext, retval);
- ka_pwdialog_error (pwdialog, errmsg);
- g_free (errmsg);
- break;
- } else {
- success = TRUE;
- break;
- }
- } while (TRUE);
-
- ka_pwdialog_set_persist (pwdialog, FALSE);
- credentials_expiring_real (applet);
-
- return success;
-}
-
-
-static void
-ka_secmem_init (void)
-{
- /* Initialize secure memory. 1 is too small, so the default size
- will be used. */
- secmem_init (1);
- secmem_set_flags (SECMEM_WARN);
- drop_privs ();
-
- if (atexit (secmem_term))
- g_error ("Couln't register atexit handler");
-}
-
-
-static void
-ka_nm_shutdown (void)
-{
-#ifdef ENABLE_NETWORK_MANAGER
- if (nm_client) {
- g_object_unref (nm_client);
- nm_client = NULL;
- }
-#endif
-}
-
-
-static gboolean
-ka_nm_init (void)
-{
-#ifdef ENABLE_NETWORK_MANAGER
- nm_client = nm_client_new ();
- if (!nm_client) {
- g_warning ("Could not initialize nm-client");
- } else {
- g_signal_connect (nm_client, "notify::state",
- G_CALLBACK (ka_nm_client_state_changed_cb),
- &is_online);
- /* Set initial state */
- ka_nm_client_state_changed_cb (nm_client, NULL, &is_online);
- }
-#endif /* ENABLE_NETWORK_MANAGER */
- return TRUE;
-}
-
-
-int
-main (int argc, char *argv[])
-{
- KaApplet *applet;
- GOptionContext *context;
- GError *error = NULL;
-
- gboolean run_auto = FALSE;
-
- const char *help_msg =
- "Run '" PACKAGE
- " --help' to see a full list of available command line options";
- const GOptionEntry options[] = {
- {"auto", 'a', 0, G_OPTION_ARG_NONE, &run_auto,
- "Only run if an initialized ccache is found", NULL},
- {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}
- };
- GFileMonitor *monitor = NULL;
-
- context = g_option_context_new ("- Kerberos 5 credential checking");
- g_option_context_add_main_entries (context, options, NULL);
- g_option_context_add_group (context, gtk_get_option_group (TRUE));
- g_option_context_parse (context, &argc, &argv, &error);
-
- if (error) {
- g_print ("%s\n%s\n", error->message, help_msg);
- g_clear_error (&error);
- return 1;
- }
- g_option_context_free (context);
-
- textdomain (PACKAGE);
- bind_textdomain_codeset (PACKAGE, "UTF-8");
- bindtextdomain (PACKAGE, LOCALE_DIR);
- ka_secmem_init ();
-
- always_run = !run_auto;
- if (using_krb5 () || always_run) {
- g_set_application_name (KA_NAME);
-
- applet = ka_applet_create ();
- if (!applet)
- return 1;
-
- if (!ka_dbus_connect (applet)) {
- ka_applet_destroy (applet);
- return 1;
- }
- ka_nm_init ();
-
- g_timeout_add_seconds (CREDENTIAL_CHECK_INTERVAL,
- (GSourceFunc) credentials_expiring, applet);
- g_idle_add ((GSourceFunc) credentials_expiring_once, applet);
- monitor = monitor_ccache (applet);
-
- gtk_main ();
- }
- ka_dbus_disconnect ();
- ka_nm_shutdown ();
- if (monitor)
- g_object_unref (monitor);
- return 0;
-}
-
-/*
- * vim:ts=4:sts=4:sw=4:et:
- */
bgstack15