aboutsummaryrefslogtreecommitdiff
path: root/src/krb5-auth-dialog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/krb5-auth-dialog.c')
-rw-r--r--src/krb5-auth-dialog.c395
1 files changed, 267 insertions, 128 deletions
diff --git a/src/krb5-auth-dialog.c b/src/krb5-auth-dialog.c
index f376ffd..c8fc27c 100644
--- a/src/krb5-auth-dialog.c
+++ b/src/krb5-auth-dialog.c
@@ -43,16 +43,21 @@
#include <libnm_glib.h>
#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_password;
+static gboolean invalid_auth;
static gboolean always_run;
-static int grab_credentials (Krb5AuthApplet* applet, gboolean renewable);
-static gboolean get_tgt_from_ccache (krb5_context context, krb5_creds *creds);
+static int grab_credentials (Krb5AuthApplet* applet);
+static int ka_renew_credentials (Krb5AuthApplet* applet);
+static gboolean ka_get_tgt_from_ccache (krb5_context context, krb5_creds *creds);
/* YAY for different Kerberos implementations */
static int
@@ -124,18 +129,45 @@ get_principal_realm_data(krb5_principal p)
return p->realm.data;
#endif
}
+
+static const char*
+get_error_message(krb5_context context, krb5_error_code err)
+{
+ const char *msg = NULL;
+
+#if defined(HAVE_KRB5_GET_ERROR_MESSAGE)
+ msg = krb5_get_error_message(context, err);
+#else
+ msg = error_message(err);
+#endif
+ if (msg == NULL)
+ return "unknown error";
+ else
+ 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
+}
+
/* ***************************************************************** */
/* ***************************************************************** */
static gboolean
-credentials_expiring_real (Krb5AuthApplet* applet, gboolean *renewable)
+credentials_expiring_real (Krb5AuthApplet* applet)
{
krb5_creds my_creds;
krb5_timestamp now;
gboolean retval = FALSE;
- *renewable = FALSE;
+ applet->renewable = FALSE;
- if (!get_tgt_from_ccache (kcontext, &my_creds)) {
+ if (!ka_get_tgt_from_ccache (kcontext, &my_creds)) {
creds_expiry = 0;
retval = TRUE;
goto out;
@@ -152,7 +184,7 @@ credentials_expiring_real (Krb5AuthApplet* applet, gboolean *renewable)
/* If our creds are expiring, determine whether they are renewable */
if (retval && get_cred_renewable(&my_creds) && my_creds.times.renew_till > now) {
- *renewable = TRUE;
+ applet->renewable = TRUE;
}
krb5_free_cred_contents (kcontext, &my_creds);
@@ -215,13 +247,12 @@ static gboolean
krb5_auth_dialog_do_updates (gpointer data)
{
Krb5AuthApplet* applet = (Krb5AuthApplet*)data;
- gboolean refreshable;
g_return_val_if_fail (applet != 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, &refreshable)) {
- KA_DEBUG("PW Dialog persist is %d", applet->pw_dialog_persist);
+ if (!credentials_expiring_real(applet)) {
+ KA_DEBUG("PW Dialog persist: %d", applet->pw_dialog_persist);
if (!applet->pw_dialog_persist)
gtk_widget_hide(applet->pw_dialog);
}
@@ -275,7 +306,7 @@ krb5_auth_dialog_setup (Krb5AuthApplet *applet,
wrong_text = NULL;
if (applet->pw_wrong_label) {
- if (invalid_password) {
+ if (invalid_auth) {
wrong_text = g_strdup (_("The password you entered is invalid"));
} else {
krb5_timestamp now;
@@ -313,7 +344,7 @@ auth_dialog_prompter (krb5_context ctx,
krb5_error_code errcode;
int i;
- errcode = KRB5_LIBOS_CANTREADPWD;
+ errcode = KRB5KRB_ERR_GENERIC;
canceled = FALSE;
canceled_creds_expiry = 0;
@@ -321,7 +352,7 @@ auth_dialog_prompter (krb5_context ctx,
const gchar *password = NULL;
int password_len = 0;
int response;
- guint32 source_id = 0;
+ guint32 source_id;
GtkWidget *entry;
@@ -338,7 +369,6 @@ auth_dialog_prompter (krb5_context ctx,
case GTK_RESPONSE_OK:
password = gtk_secure_entry_get_text (GTK_SECURE_ENTRY (entry));
password_len = strlen (password);
- errcode = 0;
break;
case GTK_RESPONSE_CANCEL:
canceled = TRUE;
@@ -350,16 +380,23 @@ auth_dialog_prompter (krb5_context ctx,
g_warning ("Unknown Response: %d", response);
g_assert_not_reached ();
}
-
g_source_remove (source_id);
- prompts[i].reply->data = (char *) password;
+ 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:
/* Reset this, so we know the next time we get a TRUE value, it is accurate. */
gtk_widget_hide (applet->pw_dialog);
- invalid_password = FALSE;
+ invalid_auth = FALSE;
return errcode;
}
@@ -394,72 +431,132 @@ network_state_cb (libnm_glib_ctx *context,
}
#endif
-
static gboolean
credentials_expiring (gpointer *data)
{
int retval;
gboolean give_up;
- gboolean renewable;
Krb5AuthApplet* applet = (Krb5AuthApplet*) data;
- KA_DEBUG("Checking expiry: %d", applet->pw_prompt_secs);
- if (credentials_expiring_real (applet, &renewable) && is_online && !applet->show_trayicon) {
+ KA_DEBUG("Checking expiry <%ds", applet->pw_prompt_secs);
+ if (credentials_expiring_real (applet) && is_online) {
+ KA_DEBUG("Expiry @ %ld", creds_expiry);
+
+ if (!ka_renew_credentials (applet)) {
+ KA_DEBUG("Credentials renewed");
+ goto out;
+ }
+
+ /* no popup when using a trayicon */
+ if (applet->show_trayicon)
+ goto out;
+
give_up = canceled && (creds_expiry == canceled_creds_expiry);
if (!give_up) {
do {
- retval = grab_credentials (applet, renewable);
+ retval = grab_credentials (applet);
give_up = canceled &&
(creds_expiry == canceled_creds_expiry);
} while ((retval != 0) &&
(retval != KRB5_REALM_CANT_RESOLVE) &&
(retval != KRB5_KDC_UNREACH) &&
- invalid_password &&
+ invalid_auth &&
!give_up);
}
}
+out:
ka_update_status(applet, creds_expiry);
return TRUE;
}
static void
-set_options_using_creds(const Krb5AuthApplet* applet,
- krb5_context context,
- krb5_creds *creds,
- krb5_get_init_creds_opt *opts)
+set_options_from_creds(const Krb5AuthApplet* applet,
+ krb5_context context,
+ krb5_creds *in,
+ krb5_get_init_creds_opt *out)
{
krb5_deltat renew_lifetime;
int flag;
- flag = get_cred_forwardable(creds) != 0;
- krb5_get_init_creds_opt_set_forwardable(opts, flag);
- flag = get_cred_proxiable(creds) != 0;
- krb5_get_init_creds_opt_set_proxiable(opts, flag);
- flag = get_cred_renewable(creds) != 0;
- if (flag && (creds->times.renew_till > creds->times.starttime)) {
- renew_lifetime = creds->times.renew_till -
- creds->times.starttime;
- krb5_get_init_creds_opt_set_renew_life(opts,
+#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS
+ krb5_get_init_creds_opt_set_default_flags(kcontext, PACKAGE,
+ krb5_principal_get_realm(kcontext, kprincipal), out);
+#endif
+
+ flag = get_cred_forwardable(in) != 0;
+ krb5_get_init_creds_opt_set_forwardable(out, flag);
+ flag = get_cred_proxiable(in) != 0;
+ krb5_get_init_creds_opt_set_proxiable(out, flag);
+ flag = get_cred_renewable(in) != 0;
+ if (flag && (in->times.renew_till > in->times.starttime)) {
+ renew_lifetime = in->times.renew_till -
+ in->times.starttime;
+ krb5_get_init_creds_opt_set_renew_life(out,
renew_lifetime);
}
- if (creds->times.endtime >
- creds->times.starttime + applet->pw_prompt_secs) {
- krb5_get_init_creds_opt_set_tkt_life(opts,
- creds->times.endtime -
- creds->times.starttime);
+ if (in->times.endtime >
+ in->times.starttime + applet->pw_prompt_secs) {
+ krb5_get_init_creds_opt_set_tkt_life(out,
+ in->times.endtime -
+ in->times.starttime);
}
/* This doesn't do a deep copy -- fix it later. */
- /* krb5_get_init_creds_opt_set_address_list(opts, creds->addresses); */
+ /* krb5_get_init_creds_opt_set_address_list(out, creds->addresses); */
+}
+
+
+static krb5_error_code
+ka_auth_pkinit(Krb5AuthApplet* applet, krb5_creds* creds)
+{
+#ifdef ENABLE_PKINIT
+ krb5_get_init_creds_opt *opts = NULL;
+ krb5_error_code retval;
+
+ KA_DEBUG("pkinit with %s", applet->pk_userid);
+
+ if (!applet->pk_userid)
+ return 0;
+
+ retval = krb5_get_init_creds_opt_alloc (kcontext, &opts);
+ if (retval)
+ goto out;
+ set_options_from_creds (applet, kcontext, creds, opts);
+
+ retval = krb5_get_init_creds_opt_set_pkinit(kcontext, opts,
+ kprincipal,
+ applet->pk_userid,
+ NULL, /* x509 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:
+ krb5_get_init_creds_opt_free(kcontext, opts);
+ return retval;
+#else /* ENABLE_PKINIT */
+ return 0;
+#endif /* ! ENABLE_PKINIT */
}
+
+/* grab credentials interactively */
static int
-grab_credentials (Krb5AuthApplet* applet, gboolean renewable)
+grab_credentials (Krb5AuthApplet* applet)
{
krb5_error_code retval;
krb5_creds my_creds;
krb5_ccache ccache;
- krb5_get_init_creds_opt opts;
+ krb5_get_init_creds_opt *opt = NULL;
memset(&my_creds, 0, sizeof(my_creds));
@@ -475,103 +572,148 @@ grab_credentials (Krb5AuthApplet* applet, gboolean renewable)
if (retval)
return retval;
- krb5_get_init_creds_opt_init (&opts);
- if (get_tgt_from_ccache (kcontext, &my_creds)) {
- set_options_using_creds (applet, kcontext, &my_creds, &opts);
- creds_expiry = my_creds.times.endtime;
-
- if (renewable) {
- retval = get_renewed_creds (kcontext, &my_creds, kprincipal, ccache, NULL);
-
- /* If we succeeded in renewing the credentials, we store it. */
- if (retval == 0) {
- goto store;
- }
- /* Else, try to get new credentials, so just fall through */
- }
- krb5_free_cred_contents (kcontext, &my_creds);
+#if ENABLE_PKINIT
+ if (applet->pk_userid) { /* try pkinit */
+#else
+ if (0) {
+#endif
+ retval = ka_auth_pkinit(applet, &my_creds);
} else {
- creds_expiry = 0;
+ retval = krb5_get_init_creds_opt_alloc (kcontext, &opt);
+ if (retval)
+ goto out;
+ set_options_from_creds (applet, kcontext, &my_creds, opt);
+ retval = krb5_get_init_creds_password(kcontext, &my_creds, kprincipal,
+ NULL, auth_dialog_prompter, applet,
+ 0, NULL, opt);
}
-
- retval = krb5_get_init_creds_password(kcontext, &my_creds, kprincipal,
- NULL, auth_dialog_prompter, applet,
- 0, NULL, &opts);
- if (canceled) {
+ 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:
- /* Invalid password, try again. */
- invalid_password = TRUE;
+#ifdef HAVE_HX509_ERR_H
+ case HX509_PKCS11_LOGIN:
+#endif
+ /* Invalid password/pin, try again. */
+ invalid_auth = TRUE;
goto out;
default:
+ KA_DEBUG("Auth failed with %d: %s", retval,
+ get_error_message(kcontext, retval));
break;
}
goto out;
}
-
-store:
retval = krb5_cc_initialize(kcontext, ccache, kprincipal);
- if (retval) {
+ if (retval)
goto out;
- }
retval = krb5_cc_store_cred(kcontext, ccache, &my_creds);
- if (retval) {
+ if (retval)
goto out;
- }
- creds_expiry = my_creds.times.endtime;
out:
+ if (opt)
+ krb5_get_init_creds_opt_free(kcontext, opt);
krb5_free_cred_contents (kcontext, &my_creds);
krb5_cc_close (kcontext, ccache);
return retval;
}
-static gboolean
-get_tgt_from_ccache (krb5_context context, krb5_creds *creds)
+/* try to renew the credentials noninteractively */
+static int
+ka_renew_credentials (Krb5AuthApplet* applet)
{
+ krb5_error_code retval;
+ krb5_creds my_creds;
krb5_ccache ccache;
- krb5_creds mcreds;
- krb5_principal principal, tgt_principal;
- gboolean ret;
-
- memset(&ccache, 0, sizeof(ccache));
- ret = FALSE;
- if (krb5_cc_default(context, &ccache) == 0) {
- memset(&principal, 0, sizeof(principal));
- if (krb5_cc_get_principal(context, ccache, &principal) == 0) {
- memset(&tgt_principal, 0, sizeof(tgt_principal));
- if (krb5_build_principal_ext(context, &tgt_principal,
- 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) == 0) {
- memset(creds, 0, sizeof(*creds));
- memset(&mcreds, 0, sizeof(mcreds));
- mcreds.client = principal;
- mcreds.server = tgt_principal;
- if (krb5_cc_retrieve_cred(context, ccache,
- 0,
- &mcreds,
- creds) == 0) {
- ret = TRUE;
- } else {
- memset(creds, 0, sizeof(*creds));
- }
- krb5_free_principal(context, tgt_principal);
- }
- krb5_free_principal(context, principal);
+ krb5_get_init_creds_opt opts;
+
+ if (kprincipal == NULL) {
+ retval = krb5_parse_name(kcontext, applet->principal,
+ &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_cc_close (kcontext, ccache);
+ return -1;
+ }
+
+ krb5_get_init_creds_opt_init (&opts);
+ set_options_from_creds (applet, kcontext, &my_creds, &opts);
+
+ if (applet->renewable) {
+ retval = get_renewed_creds (kcontext, &my_creds, kprincipal, ccache, NULL);
+ if (retval)
+ goto out;
+
+ retval = krb5_cc_initialize(kcontext, ccache, kprincipal);
+ if(retval) {
+ g_warning("krb5_cc_initialize: %s", get_error_message(kcontext, retval));
+ goto out;
+ }
+ retval = krb5_cc_store_cred(kcontext, ccache, &my_creds);
+ if (retval) {
+ g_warning("krb5_cc_store_cred: %s", get_error_message(kcontext, retval));
+ goto out;
}
- krb5_cc_close(context, ccache);
}
+out:
+ 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;
}
@@ -583,11 +725,10 @@ using_krb5()
krb5_creds creds;
err = krb5_init_context(&kcontext);
- if (err) {
- return TRUE;
- }
+ if (err)
+ return FALSE;
- have_tgt = get_tgt_from_ccache(kcontext, &creds);
+ 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);
@@ -604,20 +745,19 @@ ka_destroy_cache (GtkMenuItem *menuitem, gpointer data)
krb5_ccache ccache;
const char* cache;
krb5_error_code ret;
- gboolean renewable;
cache = krb5_cc_default_name(kcontext);
ret = krb5_cc_resolve(kcontext, cache, &ccache);
ret = krb5_cc_destroy (kcontext, ccache);
- credentials_expiring_real(applet, &renewable);
+ credentials_expiring_real(applet);
}
static void
ka_error_dialog(int err)
{
- const char* msg = error_message(err);
+ const char* msg = get_error_message(kcontext, err);
GtkWidget *dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
@@ -633,18 +773,18 @@ void
ka_grab_credentials (Krb5AuthApplet* applet)
{
int retval;
- gboolean renewable, retry;
+ gboolean retry;
applet->pw_dialog_persist = TRUE;
do {
retry = TRUE;
- retval = grab_credentials (applet, FALSE);
+ retval = grab_credentials (applet);
+ if (invalid_auth)
+ continue;
switch (retval) {
- case KRB5KRB_AP_ERR_BAD_INTEGRITY:
- retry = TRUE;
- break;
case 0: /* success */
- case KRB5_LIBOS_CANTREADPWD: /* canceled */
+ case KRB5_LIBOS_PWDINTR: /* canceled (heimdal) */
+ case KRB5_LIBOS_CANTREADPWD: /* canceled (mit) */
retry = FALSE;
break;
case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
@@ -656,7 +796,7 @@ ka_grab_credentials (Krb5AuthApplet* applet)
} while(retry);
applet->pw_dialog_persist = FALSE;
- credentials_expiring_real(applet, &renewable);
+ credentials_expiring_real(applet);
}
@@ -679,7 +819,7 @@ ka_create_gtk_secure_entry (GladeXML *xml, gchar *func_name, gchar *name,
}
-static void
+static void
ka_secmem_init ()
{
/* Initialize secure memory. 1 is too small, so the default size
@@ -752,7 +892,6 @@ main (int argc, char *argv[])
applet->pw_dialog = glade_xml_get_widget (applet->pw_xml, "krb5_dialog");
g_set_application_name (_("Network Authentication"));
- gtk_window_set_default_icon_name (applet->icons[1]);
#ifdef ENABLE_NETWORK_MANAGER
nm_context = libnm_glib_init ();
bgstack15