From 5a3e5cda1cd7e322109f2ff7989875be7faf3d96 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Aug 20 2012 23:00:58 +0000 Subject: switch to using an in-memory ccache for holding creds Switch to using an in-memory ccache for holding obtained creds. This means we no longer need to create a new one when getting tokens. --- diff --git a/src/auth.c b/src/auth.c index c3da881..03e62ee 100644 --- a/src/auth.c +++ b/src/auth.c @@ -1,5 +1,5 @@ /* - * Copyright 2003,2004,2005,2006,2007,2008,2009,2010 Red Hat, Inc. + * Copyright 2003,2004,2005,2006,2007,2008,2009,2010,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -245,7 +245,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, } } retval = v5_get_creds(ctx, pamh, - &stash->v5creds, user, userinfo, + &stash->v5ccache, user, userinfo, options, KRB5_TGS_NAME, first_pass, @@ -275,23 +275,17 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, (options->ignore_afs == 0) && (options->tokens == 1) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); v4_save_for_tokens(ctx, stash, userinfo, options, NULL); tokens_obtain(ctx, stash, options, userinfo, 1); v4_destroy(ctx, stash, options); - v5_destroy(ctx, stash, options); } } else { if ((retval == PAM_SUCCESS) && (options->ignore_afs == 0) && (options->tokens == 1) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); tokens_obtain(ctx, stash, options, userinfo, 1); - v5_destroy(ctx, stash, options); } } } @@ -340,7 +334,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, } } retval = v5_get_creds(ctx, pamh, - &stash->v5creds, user, userinfo, + &stash->v5ccache, user, userinfo, options, KRB5_TGS_NAME, second_pass, @@ -370,23 +364,17 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, (options->ignore_afs == 0) && (options->tokens == 1) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); v4_save_for_tokens(ctx, stash, userinfo, options, NULL); tokens_obtain(ctx, stash, options, userinfo, 1); v4_destroy(ctx, stash, options); - v5_destroy(ctx, stash, options); } } else { if ((retval == PAM_SUCCESS) && (options->ignore_afs == 0) && (options->tokens == 1) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); tokens_obtain(ctx, stash, options, userinfo, 1); - v5_destroy(ctx, stash, options); } } } @@ -403,7 +391,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, "allowing libkrb5 to prompt for more", user); } retval = v5_get_creds(ctx, pamh, - &stash->v5creds, user, userinfo, + &stash->v5ccache, user, userinfo, options, KRB5_TGS_NAME, NULL, @@ -431,23 +419,17 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, (options->ignore_afs == 0) && (options->tokens == 1) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); v4_save_for_tokens(ctx, stash, userinfo, options, NULL); tokens_obtain(ctx, stash, options, userinfo, 1); v4_destroy(ctx, stash, options); - v5_destroy(ctx, stash, options); } } else { if ((retval == PAM_SUCCESS) && (options->ignore_afs == 0) && (options->tokens == 1) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); tokens_obtain(ctx, stash, options, userinfo, 1); - v5_destroy(ctx, stash, options); } } } diff --git a/src/kuserok.c b/src/kuserok.c index fd2876d..88f75bf 100644 --- a/src/kuserok.c +++ b/src/kuserok.c @@ -139,15 +139,13 @@ _pam_krb5_kuserok(krb5_context ctx, /* Now, attempt to assume the desired uid/gid pair. Note that * if we're not root, this is allowed to fail. */ if ((gid != getgid()) || (gid != getegid())) { - setregid(gid, gid); + i = setregid(gid, gid); } if ((uid != getuid()) || (uid != geteuid())) { - setreuid(uid, uid); + i = setreuid(uid, uid); } /* Try to get tokens. */ if ((options->ignore_afs == 0) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, - options, NULL); if (stash->v4present) { v4_save_for_tokens(ctx, stash, userinfo, options, NULL); @@ -186,7 +184,7 @@ _pam_krb5_kuserok(krb5_context ctx, if (options->debug) { debug("krb5_aname_to_localname " "failed: %s", - error_message(err)); + v5_error_message(err)); } } else { if (strcmp(localname, user) == 0) { @@ -214,7 +212,6 @@ _pam_krb5_kuserok(krb5_context ctx, if (stash->v4present) { v4_destroy(ctx, stash, options); } - v5_destroy(ctx, stash, options); } result = (allowed == 1); _pam_krb5_write_with_retry(outpipe[1], &result, 1); diff --git a/src/options.h b/src/options.h index 864b097..33b4ae9 100644 --- a/src/options.h +++ b/src/options.h @@ -1,5 +1,5 @@ /* - * Copyright 2003,2005,2006,2008,2009,2010,2011 Red Hat, Inc. + * Copyright 2003,2005,2006,2008,2009,2010,2011,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/src/password.c b/src/password.c index 7681627..12297b2 100644 --- a/src/password.c +++ b/src/password.c @@ -77,6 +77,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, PAM_KRB5_MAYBE_CONST char *user; char prompt[LINE_MAX], prompt2[LINE_MAX], *password, *password2; krb5_context ctx; + krb5_creds pwc_creds; struct _pam_krb5_options *options; struct _pam_krb5_user_info *userinfo; struct _pam_krb5_stash *stash; @@ -259,7 +260,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, /* We have a password, so try to obtain initial * credentials using the password. */ i = v5_get_creds(ctx, pamh, - &stash->v5creds, user, userinfo, + &stash->v5ccache, user, userinfo, options, PASSWORD_CHANGE_PRINCIPAL, password, tmp_gicopts, @@ -314,7 +315,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, } } i = v5_get_creds(ctx, pamh, - &stash->v5creds, user, userinfo, + &stash->v5ccache, user, userinfo, options, PASSWORD_CHANGE_PRINCIPAL, password, tmp_gicopts, @@ -344,7 +345,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, "allowing libkrb5 to prompt", user); } i = v5_get_creds(ctx, pamh, - &stash->v5creds, user, userinfo, + &stash->v5ccache, user, userinfo, options, PASSWORD_CHANGE_PRINCIPAL, NULL, tmp_gicopts, @@ -381,7 +382,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, /* If our preliminary check succeeded, then we'll have * password-changing credentials. */ - if (v5_creds_check_initialized_pwc(ctx, &stash->v5creds) == 0) { + if (v5_ccache_has_pwc(ctx, stash->v5ccache, NULL) == 0) { /* The new password (if it's already been requested by * a previously-called module) is stored as the * PAM_AUTHTOK item. The old one is stored as the @@ -451,11 +452,11 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, /* We have the new password, so attempt to change the user's * password using the previously-acquired password-changing - * magic ticket. */ + * ticket. */ + memset(&pwc_creds, 0, sizeof(pwc_creds)); if ((password != NULL) && (retval == PAM_AUTHTOK_ERR) && - (v5_creds_check_initialized_pwc(ctx, - &stash->v5creds) == 0)) { + (v5_ccache_has_pwc(ctx, stash->v5ccache, &pwc_creds) == 0)) { int result_code; krb5_data result_code_string, result_string; result_code = -1; @@ -463,10 +464,11 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, result_string.data = NULL; result_code_string.length = 0; result_code_string.data = NULL; - i = v5_change_password(ctx, &stash->v5creds, password, + i = v5_change_password(ctx, &pwc_creds, password, &result_code, &result_code_string, &result_string); + krb5_free_cred_contents(ctx, &pwc_creds); if ((i == 0) && (result_code == 0)) { notice("password changed for %s", userinfo->unparsed_name); @@ -512,7 +514,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags, "password for '%s'", userinfo->unparsed_name); } - i = v5_get_creds(ctx, pamh, &stash->v5creds, + i = v5_get_creds(ctx, pamh, &stash->v5ccache, user, userinfo, options, KRB5_TGS_NAME, password, gic_options, diff --git a/src/session.c b/src/session.c index 37d7716..9c72051 100644 --- a/src/session.c +++ b/src/session.c @@ -223,7 +223,6 @@ _pam_krb5_open_session(pam_handle_t *pamh, int flags, if ((i == PAM_SUCCESS) && (options->ignore_afs == 0) && tokens_useful()) { - v5_save_for_tokens(ctx, stash, user, userinfo, options, NULL); if (stash->v4present) { v4_save_for_tokens(ctx, stash, userinfo, options, NULL); } @@ -233,7 +232,6 @@ _pam_krb5_open_session(pam_handle_t *pamh, int flags, if (stash->v4present) { v4_destroy(ctx, stash, options); } - v5_destroy(ctx, stash, options); } /* Create the user's credential cache, but only if we didn't pick them @@ -300,7 +298,7 @@ _pam_krb5_open_session(pam_handle_t *pamh, int flags, /* If we didn't create ccache files because we couldn't, just * pretend everything's fine. */ if ((i != PAM_SUCCESS) && - (v5_creds_check_initialized(ctx, &stash->v5creds) != 0)) { + (v5_ccache_has_tgt(ctx, stash->v5ccache, NULL) != 0)) { i = PAM_SUCCESS; } diff --git a/src/sly.c b/src/sly.c index e0fbfd2..04fb636 100644 --- a/src/sly.c +++ b/src/sly.c @@ -160,10 +160,10 @@ sly_v5(krb5_context ctx, const char *v5ccname, /* Now, attempt to assume the desired uid/gid pair. Note that * if we're not root, this is allowed to fail. */ if ((userinfo->gid != getgid()) || (userinfo->gid != getegid())) { - setregid(userinfo->gid, userinfo->gid); + i = setregid(userinfo->gid, userinfo->gid); } if ((userinfo->uid != getuid()) || (userinfo->uid != geteuid())) { - setreuid(userinfo->uid, userinfo->uid); + i = setreuid(userinfo->uid, userinfo->uid); } /* Store the user's credentials. */ ccache = NULL; @@ -183,10 +183,7 @@ sly_v5(krb5_context ctx, const char *v5ccname, } krb5_free_principal(ctx, princ); } - i = krb5_cc_initialize(ctx, ccache, userinfo->principal_name); - if (i == 0) { - i = krb5_cc_store_cred(ctx, ccache, &stash->v5creds); - } + i = v5_cc_copy(ctx, stash->v5ccache, &ccache); krb5_cc_close(ctx, ccache); } result = (i == 0) ? PAM_SUCCESS : PAM_SERVICE_ERR; @@ -366,7 +363,7 @@ _pam_krb5_sly_maybe_refresh(pam_handle_t *pamh, int flags, uid = options->user_check ? userinfo->uid : getuid(); gid = options->user_check ? userinfo->gid : getgid(); - if (v5_creds_check_initialized(ctx, &stash->v5creds) == 0) { + if (v5_ccache_has_tgt(ctx, stash->v5ccache, NULL) == 0) { if (v5filename != NULL) { /* Check the permissions on the ccache file. */ if ((access(v5filename, R_OK | W_OK) == 0) && diff --git a/src/stash.c b/src/stash.c index 025b7eb..46c67cb 100644 --- a/src/stash.c +++ b/src/stash.c @@ -1,5 +1,5 @@ /* - * Copyright 2003,2004,2005,2006,2007,2009,2011 Red Hat, Inc. + * Copyright 2003,2004,2005,2006,2007,2009,2011,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -139,7 +139,9 @@ _pam_krb5_stash_cleanup(pam_handle_t *pamh, void *data, int error) { struct _pam_krb5_stash *stash = data; struct _pam_krb5_ccname_list *node; - krb5_free_cred_contents(stash->v5ctx, &stash->v5creds); + if (stash->v5ccache != NULL) { + krb5_cc_destroy(stash->v5ctx, stash->v5ccache); + } free(stash->key); while (stash->v5ccnames != NULL) { if (stash->v5ccnames->name != NULL) { @@ -173,9 +175,7 @@ _pam_krb5_stash_shm_read_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, unsigned char *blob_creds; ssize_t blob_creds_size; int fd; - krb5_context ctx; krb5_ccache ccache; - krb5_cc_cursor cursor; /* Sanity checks. */ if (blob_size < sizeof(int) * 3) { @@ -214,32 +214,9 @@ _pam_krb5_stash_shm_read_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, return; } - /* Read the first credential from the file. */ - if (stash->v5ctx != NULL) { - ctx = stash->v5ctx; - } else { - if (_pam_krb5_init_ctx(&ctx, 0, NULL) != PAM_SUCCESS) { - warn("error initializing kerberos"); - unlink(tktfile + 5); - close(fd); - return; - } - } - if (krb5_cc_resolve(ctx, tktfile, &ccache) != 0) { + /* Read the credentials from the file. */ + if (krb5_cc_resolve(stash->v5ctx, tktfile, &ccache) != 0) { warn("error creating ccache in \"%s\"", tktfile + 5); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } - unlink(tktfile + 5); - close(fd); - return; - } - if (krb5_cc_start_seq_get(ctx, ccache, &cursor) != 0) { - warn("error iterating through ccache in \"%s\"", tktfile + 5); - krb5_cc_close(ctx, ccache); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } unlink(tktfile + 5); close(fd); return; @@ -247,7 +224,7 @@ _pam_krb5_stash_shm_read_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, /* If we have an error reading the credential, there's nothing we can * do at this point to recover from it. */ - if (krb5_cc_next_cred(ctx, ccache, &cursor, &stash->v5creds) == 0) { + if (v5_cc_copy(stash->v5ctx, ccache, &stash->v5ccache) == 0) { /* Read other variables. */ stash->v5attempted = ((int*)blob)[1]; stash->v5result = ((int*)blob)[2]; @@ -259,11 +236,7 @@ _pam_krb5_stash_shm_read_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, } /* Clean up. */ - krb5_cc_end_seq_get(ctx, ccache, &cursor); - krb5_cc_destroy(ctx, ccache); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } + krb5_cc_destroy(stash->v5ctx, ccache); close(fd); } @@ -279,7 +252,6 @@ _pam_krb5_stash_shm_write_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, int *intblob; size_t blob_size; int fd, key; - krb5_context ctx; krb5_ccache ccache; /* Sanity check. */ @@ -298,44 +270,17 @@ _pam_krb5_stash_shm_write_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, } /* Write the credentials to that file. */ - if (stash->v5ctx != NULL) { - ctx = stash->v5ctx; - } else { - if (_pam_krb5_init_ctx(&ctx, 0, NULL) != PAM_SUCCESS) { - warn("error initializing kerberos"); - unlink(variable + 5); - close(fd); - return; - } - } - if (krb5_cc_resolve(ctx, variable, &ccache) != 0) { + if (krb5_cc_resolve(stash->v5ctx, variable, &ccache) != 0) { warn("error opening credential cache file \"%s\" for writing", variable + 5); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } unlink(variable + 5); close(fd); return; } - if (krb5_cc_initialize(ctx, ccache, stash->v5creds.client) != 0) { - warn("error initializing credential cache file \"%s\"", - variable + 5); - krb5_cc_close(ctx, ccache); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } - unlink(variable + 5); - close(fd); - return; - } - if (krb5_cc_store_cred(ctx, ccache, &stash->v5creds) != 0) { + if (v5_cc_copy(stash->v5ctx, stash->v5ccache, &ccache) != 0) { warn("error writing to credential cache file \"%s\"", variable + 5); - krb5_cc_close(ctx, ccache); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } + krb5_cc_close(stash->v5ctx, ccache); unlink(variable + 5); close(fd); return; @@ -357,10 +302,7 @@ _pam_krb5_stash_shm_write_v5(pam_handle_t *pamh, struct _pam_krb5_stash *stash, } /* Clean up. */ - krb5_cc_destroy(ctx, ccache); - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); - } + krb5_cc_destroy(stash->v5ctx, ccache); close(fd); if (key != -1) { @@ -595,10 +537,8 @@ _pam_krb5_stash_external_read(pam_handle_t *pamh, struct _pam_krb5_stash *stash, struct _pam_krb5_user_info *userinfo, struct _pam_krb5_options *options) { - krb5_context ctx; krb5_ccache ccache; krb5_principal princ; - krb5_cc_cursor cursor; int i, read_default_principal; const char *ccname; char *unparsed; @@ -612,35 +552,27 @@ _pam_krb5_stash_external_read(pam_handle_t *pamh, struct _pam_krb5_stash *stash, if (options->debug) { debug("KRB5CCNAME is set to \"%s\"", ccname); } - if (stash->v5ctx != NULL) { - ctx = stash->v5ctx; - } else { - if (_pam_krb5_init_ctx(&ctx, 0, NULL) != PAM_SUCCESS) { - warn("error initializing kerberos"); - return; - } - } ccache = NULL; read_default_principal = 0; - i = krb5_cc_resolve(ctx, ccname, &ccache); + i = krb5_cc_resolve(stash->v5ctx, ccname, &ccache); if (i != 0) { warn("error opening ccache \"%s\", ignoring", ccname); } else { princ = NULL; /* Read the name of the default principal from the * ccache. */ - if (krb5_cc_get_principal(ctx, ccache, &princ) != 0) { + if (krb5_cc_get_principal(stash->v5ctx, ccache, &princ) != 0) { warn("error reading ccache's default principal name"); } else { read_default_principal++; /* If they're different, update the userinfo * structure with the new principal name. */ - if (krb5_principal_compare(ctx, princ, + if (krb5_principal_compare(stash->v5ctx, princ, userinfo->principal_name)) { if (options->debug) { debug("ccache matches current principal"); } - krb5_free_principal(ctx, princ); + krb5_free_principal(stash->v5ctx, princ); princ = NULL; } else { if (options->debug) { @@ -648,9 +580,9 @@ _pam_krb5_stash_external_read(pam_handle_t *pamh, struct _pam_krb5_stash *stash, } /* Unparse the name. */ unparsed = NULL; - if (krb5_unparse_name(ctx, princ, &unparsed) != 0) { + if (krb5_unparse_name(stash->v5ctx, princ, &unparsed) != 0) { warn("error unparsing ccache's default principal name, discarding"); - krb5_free_principal(ctx, princ); + krb5_free_principal(stash->v5ctx, princ); princ = NULL; } else { if (options->debug) { @@ -659,60 +591,36 @@ _pam_krb5_stash_external_read(pam_handle_t *pamh, struct _pam_krb5_stash *stash, unparsed); } /* Save the unparsed name. */ - v5_free_unparsed_name(ctx, userinfo->unparsed_name); + v5_free_unparsed_name(stash->v5ctx, userinfo->unparsed_name); userinfo->unparsed_name = unparsed; unparsed = NULL; /* Save the principal name. */ - krb5_free_principal(ctx, userinfo->principal_name); + krb5_free_principal(stash->v5ctx, userinfo->principal_name); userinfo->principal_name = princ; princ = NULL; } } } /* If we were able to read the default principal, then - * search for a TGT. */ - cursor = NULL; - if (read_default_principal && - (krb5_cc_start_seq_get(ctx, ccache, &cursor) == 0)) { - memset(&stash->v5creds, 0, sizeof(stash->v5creds)); - while (krb5_cc_next_cred(ctx, ccache, &cursor, - &stash->v5creds) == 0) { - unparsed = NULL; - i = krb5_unparse_name(ctx, - stash->v5creds.server, - &unparsed); - if ((i == 0) && (unparsed != NULL)) { - i = strcspn(unparsed, - PAM_KRB5_PRINCIPAL_COMPONENT_SEPARATORS); - if ((i == KRB5_TGS_NAME_SIZE) && - (strncmp(unparsed, - KRB5_TGS_NAME, - KRB5_TGS_NAME_SIZE) == 0)) { - if (options->debug) { - debug("using credential for \"%s\" as a v5 TGT", unparsed); - } - v5_free_unparsed_name(ctx, unparsed); - unparsed = NULL; - stash->v5attempted = 1; - stash->v5result = 0; - stash->v5external = 1; - break; - } - if (options->debug) { - debug("not using credential for \"%s\" as a v5 TGT", unparsed); - } - v5_free_unparsed_name(ctx, unparsed); - unparsed = NULL; + * copy the ccache's contents. */ + if (read_default_principal) { + i = v5_cc_copy(stash->v5ctx, ccache, &stash->v5ccache); + if (i != 0) { + if (options->debug) { + debug("failed to copy " + "credentials from \"%s\" " + "for \"%s\"", + ccname, unparsed); + } + } else { + if (options->debug) { + debug("copied credentials from " + "\"%s\" for \"%s\"", + ccname, unparsed); } - krb5_free_cred_contents(ctx, &stash->v5creds); - memset(&stash->v5creds, 0, sizeof(stash->v5creds)); } - krb5_cc_end_seq_get(ctx, ccache, &cursor); } - krb5_cc_close(ctx, ccache); - } - if (ctx != stash->v5ctx) { - krb5_free_context(ctx); + krb5_cc_close(stash->v5ctx, ccache); } } else { if (options->debug) { @@ -793,15 +701,21 @@ _pam_krb5_stash_get(pam_handle_t *pamh, const char *user, return stash; } + if (_pam_krb5_init_ctx(&ctx, 0, NULL) != PAM_SUCCESS) { + warn("error initializing kerberos"); + return NULL; + } + stash = malloc(sizeof(struct _pam_krb5_stash)); if (stash == NULL) { free(key); + krb5_free_context(ctx); return NULL; } memset(stash, 0, sizeof(struct _pam_krb5_stash)); stash->key = key; - stash->v5ctx = NULL; + stash->v5ctx = ctx; stash->v5attempted = 0; stash->v5result = KRB5KRB_ERR_GENERIC; stash->v5expired = 0; @@ -810,7 +724,7 @@ _pam_krb5_stash_get(pam_handle_t *pamh, const char *user, stash->v5setenv = 0; stash->v5shm = -1; stash->v5shm_owner = -1; - memset(&stash->v5creds, 0, sizeof(stash->v5creds)); + stash->v5ccache = NULL; stash->v4present = 0; #ifdef USE_KRB4 memset(&stash->v4creds, 0, sizeof(stash->v4creds)); @@ -828,11 +742,9 @@ _pam_krb5_stash_get(pam_handle_t *pamh, const char *user, ((stash->v5external == 1) && (stash->v5result == 0)))) { _pam_krb5_stash_external_read(pamh, stash, user, info, options); if (stash->v5attempted && (stash->v5result == 0)) { - if ((_pam_krb5_init_ctx(&ctx, 0, NULL) == 0) && - ((options->v4 == 1) || (options->v4_for_afs == 1))) { + if ((options->v4 == 1) || (options->v4_for_afs == 1)) { v4_get_creds(ctx, pamh, stash, info, options, NULL, NULL); - krb5_free_context(ctx); } } } @@ -1101,46 +1013,19 @@ _pam_krb5_stash_clone_v5(krb5_context ctx, { char *filename, *newname; int fd; - krb5_ccache occache, nccache; - if (stash->v5ccnames == NULL) { - return; - } - if ((strncmp(stash->v5ccnames->name, "FILE:", 5) == 0) && - (strncmp(options->ccname_template, "FILE:", 5) == 0)) { - /* If the source and destinations are files, do the helper - * dance to get the context right. */ - filename = xstrdup(stash->v5ccnames->name + 5); - if (filename != NULL) { - _pam_krb5_stash_clone_file(&filename, uid, gid); - newname = malloc(strlen(filename) + 6); - if (newname != NULL) { - sprintf(newname, "FILE:%s", filename); - xstrfree(stash->v5ccnames->name); - stash->v5ccnames->name = newname; - } - xstrfree(filename); - } - } else { - /* Straight-up copy. */ - occache = NULL; - if (krb5_cc_resolve(ctx, stash->v5ccnames->name, - &occache) != 0) { - warn("error creating ccache \"%s\"", - stash->v5ccnames->name); - return; - } - /* Open a new ccache using the desired pattern. If it's a - * FILE: ccache, use mkstemp() to try to pre-create it. In any - * case, if it's going to have the same name as the current - * ccache, append a "_" in a feeble attempt at making its name - * unique. */ + krb5_ccache nccache; + { + /* Straight-up copy. Open a new ccache using the desired + * pattern. If it's a FILE: ccache, use mkstemp() to try to + * pre-create it. In any case, if it's going to have the same + * name as the current ccache, append a "_" in a feeble attempt + * at making its name unique. */ nccache = NULL; newname = v5_user_info_subst(ctx, user, userinfo, options, options->ccname_template); newname = _pam_krb5_stash_guess_unique_ccname(stash, options, newname, "_"); if (newname == NULL) { - krb5_cc_close(ctx, occache); return; } if (strncmp(newname, "FILE:", 5) == 0) { @@ -1155,33 +1040,38 @@ _pam_krb5_stash_clone_v5(krb5_context ctx, unlink(newname + 5); } free(newname); - krb5_cc_close(ctx, occache); return; } if (fd != -1) { close(fd); } - if (v5_cc_copy(ctx, occache, &nccache) == 0) { + if (v5_cc_copy(ctx, stash->v5ccache, &nccache) == 0) { if (options->debug) { - debug("copied credentials from \"%s\" to " - "\"%s\" for the user, destroying \"%s\"", - stash->v5ccnames->name, newname, - stash->v5ccnames->name); + debug("copied credentials from \"%s:%s\" to " + "\"%s\" for the user", + krb5_cc_get_type(ctx, stash->v5ccache), + krb5_cc_get_name(ctx, stash->v5ccache), + newname); } - xstrfree(stash->v5ccnames->name); - stash->v5ccnames->name = newname; krb5_cc_close(ctx, nccache); - krb5_cc_destroy(ctx, occache); - /* If the new source and the destination are files, - * re-clone it to get the permissions right. */ + _pam_krb5_stash_push_v5(ctx, stash, options, newname); + /* If the destination is a file, re-clone it to get the + * permissions right. */ if (strncmp(options->ccname_template, "FILE:", 5) == 0) { - _pam_krb5_stash_clone_v5(ctx, stash, - options, - user, userinfo, - uid, gid); + filename = xstrdup(stash->v5ccnames->name + 5); + if (filename != NULL) { + _pam_krb5_stash_clone_file(&filename, uid, gid); + newname = malloc(strlen(filename) + 6); + if (newname != NULL) { + sprintf(newname, "FILE:%s", filename); + xstrfree(stash->v5ccnames->name); + stash->v5ccnames->name = newname; + } + xstrfree(filename); + } } else - /* If the new source is a keyring, give ownership away + /* If the new ccache is a keyring, give ownership away * to the designated user. */ if (strncmp(options->ccname_template, "KEYRING:", 8) == 0) { @@ -1191,17 +1081,18 @@ _pam_krb5_stash_clone_v5(krb5_context ctx, warn("error setting permissions on " "ccache \"%s\" for the user: %s", stash->v5ccnames->name, - error_message(errno)); + v5_error_message(errno)); } } } else { - warn("error copying credentials from \"%s\" to " - "\"%s\" for the user", stash->v5ccnames->name, + warn("error copying credentials from \"%s:%s\" to " + "\"%s\" for the user", + krb5_cc_get_type(ctx, stash->v5ccache), + krb5_cc_get_name(ctx, stash->v5ccache), newname); krb5_cc_destroy(ctx, nccache); - krb5_cc_close(ctx, occache); - xstrfree(newname); } + xstrfree(newname); } } @@ -1273,7 +1164,7 @@ _pam_krb5_stash_pop(krb5_context ctx, struct _pam_krb5_ccname_list **list) #endif warn("error accessing ccache \"%s\" " "for removal: %s", node->name, - error_message(i)); + v5_error_message(i)); return -1; } else { i = krb5_cc_destroy(ctx, ccache); @@ -1286,7 +1177,7 @@ _pam_krb5_stash_pop(krb5_context ctx, struct _pam_krb5_ccname_list **list) } else { warn("error removing ccache " "\"%s\": %s", node->name, - error_message(i)); + v5_error_message(i)); return -1; } } diff --git a/src/stash.h b/src/stash.h index 1887819..be90e85 100644 --- a/src/stash.h +++ b/src/stash.h @@ -1,5 +1,5 @@ /* - * Copyright 2003,2007,2009,2011 Red Hat, Inc. + * Copyright 2003,2007,2009,2011,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -45,7 +45,7 @@ struct _pam_krb5_stash { krb5_context v5ctx; int v5attempted, v5result, v5expired, v5external; struct _pam_krb5_ccname_list *v5ccnames; - krb5_creds v5creds; + krb5_ccache v5ccache; int v5setenv; int v5shm; pid_t v5shm_owner; diff --git a/src/tokens.c b/src/tokens.c index 9dbf0ec..5086971 100644 --- a/src/tokens.c +++ b/src/tokens.c @@ -1,5 +1,5 @@ /* - * Copyright 2003,2004,2005,2006,2007,2008 Red Hat, Inc. + * Copyright 2003,2004,2005,2006,2007,2008,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -99,7 +99,6 @@ tokens_obtain(krb5_context context, lnk[LINE_MAX]; struct stat st; char ccname[PATH_MAX]; - krb5_ccache ccache; uid_t uid; const struct { const char *name; int method; @@ -170,19 +169,6 @@ tokens_obtain(krb5_context context, p = q + strspn(q, ","); } - /* Open the ccache. */ - memset(&ccache, 0, sizeof(ccache)); - snprintf(ccname, sizeof(ccname), "MEMORY:_pam_krb5_token_s_%s-%d", - info->unparsed_name, counter++); - if (stash && - (v5_creds_check_initialized(context, &stash->v5creds) == 0) && - (krb5_cc_resolve(context, ccname, &ccache) == 0) && - (krb5_cc_initialize(context, ccache, stash->v5creds.client) == 0) && - (krb5_cc_store_cred(context, ccache, &stash->v5creds) == 0)) { - } else { - memset(&ccache, 0, sizeof(ccache)); - } - /* Get the name of the local cell. The root.afs volume which is * mounted in /afs is mounted from the local cell, so we'll use that * to determine which cell is considered the local cell. Avoid getting @@ -195,7 +181,7 @@ tokens_obtain(krb5_context context, debug("obtaining tokens for local cell '%s'", localcell); } - ret = minikafs_log(context, ccache, options, + ret = minikafs_log(context, stash->v5ccache, options, localcell, NULL, uid, methods, n_methods); if (ret != 0) { @@ -245,7 +231,7 @@ tokens_obtain(krb5_context context, if (options->debug) { debug("obtaining tokens for home cell '%s'", homecell); } - ret = minikafs_log(context, ccache, options, + ret = minikafs_log(context, stash->v5ccache, options, homecell, NULL, uid, methods, n_methods); if (ret != 0) { @@ -284,7 +270,7 @@ tokens_obtain(krb5_context context, options->afs_cells[i].cell); } } - ret = minikafs_log(context, ccache, options, + ret = minikafs_log(context, stash->v5ccache, options, options->afs_cells[i].cell, options->afs_cells[i].principal_name, uid, methods, n_methods); @@ -305,10 +291,6 @@ tokens_obtain(krb5_context context, } } - if (ccache != NULL) { - krb5_cc_destroy(context, ccache); - } - /* Suppress all errors. */ return PAM_SUCCESS; } diff --git a/src/uuauth.c b/src/uuauth.c index c994468..eb7fb56 100644 --- a/src/uuauth.c +++ b/src/uuauth.c @@ -97,14 +97,14 @@ main(int argc, const char **argv) ctx = NULL; ret = _pam_krb5_init_ctx(&ctx, argc, argv); if (ret != 0) { - crit("Error initializing Kerberos: %s.", error_message(ret)); + crit("Error initializing Kerberos: %s.", v5_error_message(ret)); return ret; } ccache = NULL; ret = krb5_cc_default(ctx, &ccache); if (ret != 0) { - crit("Error opening ccache: %s.", error_message(ret)); + crit("Error opening ccache: %s.", v5_error_message(ret)); return ret; } occache = NULL; @@ -112,7 +112,7 @@ main(int argc, const char **argv) ret = krb5_cc_resolve(ctx, argv[1], &occache); if (ret != 0) { crit("Error opening ccache %s: %s.", - argv[1], error_message(ret)); + argv[1], v5_error_message(ret)); return ret; } } else { @@ -123,7 +123,7 @@ main(int argc, const char **argv) ret = krb5_cc_get_principal(ctx, ccache, &client); if (ret != 0) { crit("Error determining client principal name: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } @@ -138,7 +138,7 @@ main(int argc, const char **argv) 0); if (ret != 0) { crit("Error building TGS principal name: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } @@ -150,7 +150,7 @@ main(int argc, const char **argv) ret = krb5_cc_retrieve_cred(ctx, occache, 0, &mcreds, &ocreds); if (ret != 0) { crit("Error getting old creds: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } key = v5_creds_get_key(&ocreds); @@ -162,7 +162,7 @@ main(int argc, const char **argv) &mcreds, &creds); if (ret != 0) { crit("Error getting creds: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } @@ -170,7 +170,7 @@ main(int argc, const char **argv) ret = krb5_auth_con_init(ctx, &auth_con); if (ret != 0) { crit("Error initializing auth context: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } @@ -179,7 +179,7 @@ main(int argc, const char **argv) NULL, creds, &req); if (ret != 0) { crit("Error generating AP request: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } @@ -187,7 +187,7 @@ main(int argc, const char **argv) ret = krb5_auth_con_init(ctx, &oauth_con); if (ret != 0) { crit("Error initializing auth context: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } ret = v5_auth_con_setuserkey(ctx, oauth_con, key); @@ -197,7 +197,7 @@ main(int argc, const char **argv) ret = krb5_rd_req(ctx, &oauth_con, &req, NULL, NULL, &flags, &ticket); if (ret != 0) { crit("Error receiving AP request: %s.", - error_message(ret)); + v5_error_message(ret)); return ret; } if (krb5_principal_compare(ctx, v5_ticket_get_client(ticket), diff --git a/src/v5.c b/src/v5.c index 962912d..31b2d10 100644 --- a/src/v5.c +++ b/src/v5.c @@ -1,5 +1,5 @@ /* - * Copyright 2003,2004,2005,2006,2007,2008,2009,2010,2011 Red Hat, Inc. + * Copyright 2003,2004,2005,2006,2007,2008,2009,2010,2011,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -829,7 +829,7 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, ccache = NULL; ret = krb5_cc_default(ctx, &ccache); if (ret != 0) { - warn("error opening default ccache: %s", error_message(ret)); + warn("error opening default ccache: %s", v5_error_message(ret)); return PAM_SERVICE_ERR; } @@ -841,7 +841,7 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, &mcreds, &ocreds); if (ret != 0) { warn("error getting cached creds for the same client/server " - "pair: %s", error_message(ret)); + "pair: %s", v5_error_message(ret)); krb5_cc_close(ctx, ccache); return PAM_SERVICE_ERR; } @@ -869,14 +869,14 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, ret = krb5_cc_resolve(ctx, ccname, &ccache); if (ret != 0) { warn("internal error creating in-memory ccache: %s", - error_message(ret)); + v5_error_message(ret)); krb5_free_creds(ctx, ocreds); return PAM_SERVICE_ERR; } ret = krb5_cc_initialize(ctx, ccache, creds->client); if (ret != 0) { warn("internal error initializing in-memory ccache: %s", - error_message(ret)); + v5_error_message(ret)); krb5_cc_destroy(ctx, ccache); krb5_free_creds(ctx, ocreds); return PAM_SERVICE_ERR; @@ -884,7 +884,7 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, ret = krb5_cc_store_cred(ctx, ccache, creds); if (ret != 0) { warn("internal error storing creds to in-memory ccache: %s", - error_message(ret)); + v5_error_message(ret)); krb5_cc_destroy(ctx, ccache); krb5_free_creds(ctx, ocreds); return PAM_SERVICE_ERR; @@ -901,10 +901,10 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, &mcreds, &ucreds); if (ret != 0) { warn("error obtaining user-to-user creds to '%s': %s", - userinfo->unparsed_name, error_message(ret)); + userinfo->unparsed_name, v5_error_message(ret)); notice("TGT failed verification using previously-obtained " "credentials in '%s': %s", krb5_cc_default_name(ctx), - error_message(ret)); + v5_error_message(ret)); krb5_cc_destroy(ctx, ccache); krb5_free_creds(ctx, ocreds); return PAM_AUTH_ERR; @@ -917,7 +917,7 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, ret = krb5_auth_con_init(ctx, &auth_con); if (ret != 0) { warn("error initializing auth context: %s", - error_message(ret)); + v5_error_message(ret)); krb5_free_creds(ctx, ucreds); krb5_free_creds(ctx, ocreds); return PAM_SERVICE_ERR; @@ -931,10 +931,10 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, NULL, ucreds, &req); if (ret != 0) { warn("error generating user-to-user AP request to '%s': %s", - userinfo->unparsed_name, error_message(ret)); + userinfo->unparsed_name, v5_error_message(ret)); notice("TGT failed verification using previously-obtained " "credentials in '%s': %s", krb5_cc_default_name(ctx), - error_message(ret)); + v5_error_message(ret)); krb5_auth_con_free(ctx, auth_con); krb5_free_creds(ctx, ucreds); krb5_free_creds(ctx, ocreds); @@ -949,7 +949,7 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, ret = krb5_auth_con_init(ctx, &auth_con); if (ret != 0) { warn("error initializing auth context: %s", - error_message(ret)); + v5_error_message(ret)); krb5_free_data_contents(ctx, &req); krb5_free_creds(ctx, ocreds); return PAM_SERVICE_ERR; @@ -959,7 +959,7 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, krb5_free_creds(ctx, ocreds); if (ret != 0) { warn("error setting up to receive user-to-user AP request: %s", - error_message(ret)); + v5_error_message(ret)); krb5_free_data_contents(ctx, &req); krb5_auth_con_free(ctx, auth_con); return PAM_SERVICE_ERR; @@ -972,10 +972,10 @@ v5_validate_using_ccache(krb5_context ctx, krb5_creds *creds, krb5_free_data_contents(ctx, &req); if (ret != 0) { warn("error receiving user-to-user AP request: %s", - error_message(ret)); + v5_error_message(ret)); notice("TGT failed verification using previously-obtained " "credentials in '%s': %s", krb5_cc_default_name(ctx), - error_message(ret)); + v5_error_message(ret)); krb5_auth_con_free(ctx, auth_con); return PAM_AUTH_ERR; } @@ -1203,7 +1203,8 @@ v5_select_keytab_service(krb5_context ctx, krb5_creds *creds, } static int -v5_validate_using_keytab(krb5_context ctx, krb5_creds *creds, +v5_validate_using_keytab(krb5_context ctx, + krb5_creds *creds, krb5_ccache ccache, const struct _pam_krb5_options *options, int *krberr) { int i; @@ -1241,7 +1242,7 @@ v5_validate_using_keytab(krb5_context ctx, krb5_creds *creds, * have some idea of what the service's name is, and that we can read * the key. */ krb5_verify_init_creds_opt_init(&opt); - i = krb5_verify_init_creds(ctx, creds, princ, keytab, NULL, &opt); + i = krb5_verify_init_creds(ctx, creds, princ, keytab, &ccache, &opt); *krberr = i; if (keytab != NULL) { krb5_kt_close(ctx, keytab); @@ -1274,7 +1275,7 @@ v5_validate_using_keytab(krb5_context ctx, krb5_creds *creds, } static int -v5_validate(krb5_context ctx, krb5_creds *creds, +v5_validate(krb5_context ctx, krb5_creds *creds, krb5_ccache ccache, struct _pam_krb5_user_info *userinfo, const struct _pam_krb5_options *options) { @@ -1282,7 +1283,7 @@ v5_validate(krb5_context ctx, krb5_creds *creds, /* Obtain creds for a service for which we have keys in the keytab and * then just authenticate to it. */ krberr = 0; - ret = v5_validate_using_keytab(ctx, creds, options, &krberr); + ret = v5_validate_using_keytab(ctx, creds, ccache, options, &krberr); switch (ret) { case PAM_AUTH_ERR: switch (krberr) { @@ -1323,7 +1324,7 @@ v5_validate(krb5_context ctx, krb5_creds *creds, int v5_get_creds(krb5_context ctx, pam_handle_t *pamh, - krb5_creds *creds, + krb5_ccache *ccache, const char *user, struct _pam_krb5_user_info *userinfo, struct _pam_krb5_options *options, @@ -1347,13 +1348,20 @@ v5_get_creds(krb5_context ctx, struct _pam_krb5_prompter_data prompter_data; struct _pam_krb5_perms *saved_perms; krb5_principal service_principal; - krb5_creds tmpcreds; - krb5_ccache ccache; + krb5_creds creds; krb5_get_init_creds_opt *tmp_gicopts; + char ccname[LINE_MAX]; /* In case we already have creds, get rid of them. */ - krb5_free_cred_contents(ctx, creds); - memset(creds, 0, sizeof(*creds)); + if (*ccache != NULL) { + krb5_cc_destroy(ctx, *ccache); + *ccache = NULL; + } + snprintf(ccname, sizeof(ccname), "MEMORY:%p", ccache); + if (krb5_cc_resolve(ctx, ccname, ccache) != 0) { + return PAM_SERVICE_ERR; + } + memset(&creds, 0, sizeof(creds)); /* Check some string lengths. */ if (strchr(userinfo->unparsed_name, '@') != NULL) { @@ -1465,8 +1473,11 @@ v5_get_creds(krb5_context ctx, } } #endif +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_OUT_CCACHE + krb5_get_init_creds_opt_set_out_ccache(ctx, gic_options, *ccache); +#endif i = krb5_get_init_creds_password(ctx, - creds, + &creds, userinfo->principal_name, password, prompter, @@ -1485,14 +1496,20 @@ v5_get_creds(krb5_context ctx, /* Interpret the return code. */ switch (i) { case 0: - /* Flat-out success. Validate the TGT if it's actually a TGT, - * and if we can. */ + /* Flat-out success. Initialize the ccache, store the creds to + * it, and validate the TGT if it's actually a TGT, if we can. */ + if (v5_ccache_has_tgt(ctx, *ccache, NULL) != 0) { + krb5_cc_initialize(ctx, *ccache, + userinfo->principal_name); + krb5_cc_store_cred(ctx, *ccache, &creds); + } if ((options->validate == 1) && (strcmp(service, KRB5_TGS_NAME) == 0)) { if (options->debug) { debug("validating credentials"); } - switch (v5_validate(ctx, creds, userinfo, options)) { + switch (v5_validate(ctx, &creds, *ccache, + userinfo, options)) { case PAM_AUTH_ERR: return PAM_AUTH_ERR; break; @@ -1536,7 +1553,7 @@ v5_get_creds(krb5_context ctx, prompter_data.previous_password = password; prompter_data.options = options; prompter_data.userinfo = userinfo; - memset(&tmpcreds, 0, sizeof(tmpcreds)); + memset(&creds, 0, sizeof(creds)); if (options->debug && options->debug_sensitive) { debug("attempting with password=%s%s%s", password ? "\"" : "", @@ -1555,7 +1572,7 @@ v5_get_creds(krb5_context ctx, tmp_gicopts = NULL; } i = krb5_get_init_creds_password(ctx, - &tmpcreds, + &creds, userinfo->principal_name, password, prompter, @@ -1564,7 +1581,7 @@ v5_get_creds(krb5_context ctx, realm_service, tmp_gicopts); v5_free_get_init_creds_opt(ctx, tmp_gicopts); - krb5_free_cred_contents(ctx, &tmpcreds); + krb5_free_cred_contents(ctx, &creds); switch (i) { case 0: /* Got password-changing creds, so warn about the @@ -1602,25 +1619,23 @@ v5_get_creds(krb5_context ctx, } } -static int -v5_save(krb5_context ctx, - struct _pam_krb5_stash *stash, - const char *user, - struct _pam_krb5_user_info *userinfo, - struct _pam_krb5_options *options, - const char **ret_ccname, - int for_user) +int +v5_save_for_user(krb5_context ctx, + struct _pam_krb5_stash *stash, + const char *user, + struct _pam_krb5_user_info *userinfo, + struct _pam_krb5_options *options, + const char **ccname) { - char ccname[PATH_MAX]; krb5_ccache ccache; static int counter = 0; - if (ret_ccname != NULL) { - *ret_ccname = NULL; + if (ccname != NULL) { + *ccname = NULL; } /* Ensure that we have credentials for saving. */ - if (v5_creds_check_initialized(ctx, &stash->v5creds) != 0) { + if (v5_ccache_has_tgt(ctx, stash->v5ccache, NULL) != 0) { if (options->debug) { debug("credentials not initialized"); } @@ -1628,73 +1643,17 @@ v5_save(krb5_context ctx, } /* Derive the ccache name from the supplied template. */ - snprintf(ccname, sizeof(ccname), "MEMORY:_pam_krb5_tmp_s_%s-%d", - userinfo->unparsed_name, counter++); - if (options->debug) { - debug("saving v5 credentials to '%s' for internal use", ccname); - } - /* Create an in-memory structure and then open the file. One of two - * things will happen here. Either libkrb5 will just use the file, and - * we're safer because it wouldn't have used O_EXCL to do so, or it - * will nuke the file and reopen it with O_EXCL. In the latter case, - * the descriptor we have will become useless, so we don't actually use - * it for anything. */ - if (krb5_cc_resolve(ctx, ccname, &ccache) != 0) { - warn("error resolving ccache '%s'", ccname); - return PAM_SERVICE_ERR; - } - if (krb5_cc_initialize(ctx, ccache, userinfo->principal_name) != 0) { - warn("error initializing ccache '%s'", ccname); - krb5_cc_destroy(ctx, ccache); - return PAM_SERVICE_ERR; - } - if (krb5_cc_store_cred(ctx, ccache, &stash->v5creds) != 0) { - warn("error storing credentials in ccache '%s'", ccname); - krb5_cc_destroy(ctx, ccache); - return PAM_SERVICE_ERR; + _pam_krb5_stash_clone_v5(ctx, stash, options, + user, userinfo, + options->user_check ? + userinfo->uid : getuid(), + options->user_check ? + userinfo->gid : getgid()); + if (ccname != NULL) { + *ccname = stash->v5ccnames->name; } - /* If we got to here, we succeeded. */ - krb5_cc_close(ctx, ccache); - /* Save the new ccache name in the stash, and optionally return it to - * the caller. */ - if (_pam_krb5_stash_push_v5(ctx, stash, options, ccname) == 0) { - /* Generate a *new* ccache with the same contents as this - * one, but for the user's use, and destroy this one. */ - if (for_user) { - _pam_krb5_stash_clone_v5(ctx, stash, options, - user, userinfo, - options->user_check ? - userinfo->uid : getuid(), - options->user_check ? - userinfo->gid : getgid()); - } - if (ret_ccname != NULL) { - *ret_ccname = stash->v5ccnames->name; - } - } - return PAM_SUCCESS; -} - -int -v5_save_for_user(krb5_context ctx, - struct _pam_krb5_stash *stash, - const char *user, - struct _pam_krb5_user_info *userinfo, - struct _pam_krb5_options *options, - const char **ccname) -{ - return v5_save(ctx, stash, user, userinfo, options, ccname, 1); -} -int -v5_save_for_tokens(krb5_context ctx, - struct _pam_krb5_stash *stash, - const char *user, - struct _pam_krb5_user_info *userinfo, - struct _pam_krb5_options *options, - const char **ccname) -{ - return v5_save(ctx, stash, user, userinfo, options, ccname, 0); + return PAM_SUCCESS; } int @@ -1872,3 +1831,54 @@ v5_enctype_to_string(krb5_context ctx, krb5_enctype enctype, return i; #endif } + +static krb5_error_code +v5_ccache_has_cred(krb5_context ctx, krb5_ccache ccache, krb5_creds *creds, + const char *first, const char *second) +{ + krb5_creds match, matched; + krb5_error_code err; + const char *realm; + int rlength; + + memset(&match, 0, sizeof(match)); + memset(&matched, 0, sizeof(matched)); + err = krb5_cc_get_principal(ctx, ccache, &match.client); + if (err != 0) { + return err; + } + realm = v5_princ_realm_contents(match.client); + rlength = v5_princ_realm_length(match.client); + if (second == NULL) { + err = krb5_build_principal_ext(ctx, &match.server, + rlength, realm, + strlen(first), first, + rlength, realm, + 0); + } else { + err = krb5_build_principal(ctx, &match.server, + rlength, realm, + first, second, NULL); + } + if (creds == NULL) { + creds = &matched; + } + err = krb5_cc_retrieve_cred(ctx, ccache, 0, &match, creds); + if (creds == &matched) { + krb5_free_cred_contents(ctx, creds); + } + krb5_free_cred_contents(ctx, &match); + return err; +} + +krb5_error_code +v5_ccache_has_tgt(krb5_context ctx, krb5_ccache ccache, krb5_creds *creds) +{ + return v5_ccache_has_cred(ctx, ccache, creds, KRB5_TGS_NAME, NULL); +} + +krb5_error_code +v5_ccache_has_pwc(krb5_context ctx, krb5_ccache ccache, krb5_creds *creds) +{ + return v5_ccache_has_cred(ctx, ccache, creds, "kadmin", "changepw"); +} diff --git a/src/v5.h b/src/v5.h index a40bb03..32ccb0e 100644 --- a/src/v5.h +++ b/src/v5.h @@ -1,5 +1,5 @@ /* - * Copyright 2003,2006,2007,2009,2011 Red Hat, Inc. + * Copyright 2003,2006,2007,2009,2011,2012 Red Hat, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -41,7 +41,7 @@ int v5_get_creds(krb5_context ctx, pam_handle_t *pamh, - krb5_creds *creds, + krb5_ccache *ccache, const char *user, struct _pam_krb5_user_info *userinfo, struct _pam_krb5_options *options, @@ -69,16 +69,13 @@ int v5_save_for_user(krb5_context ctx, struct _pam_krb5_user_info *userinfo, struct _pam_krb5_options *options, const char **ccname); -int v5_save_for_tokens(krb5_context ctx, - struct _pam_krb5_stash *stash, - const char *user, - struct _pam_krb5_user_info *userinfo, - struct _pam_krb5_options *options, - const char **ccname); - void v5_destroy(krb5_context ctx, struct _pam_krb5_stash *stash, struct _pam_krb5_options *options); +krb5_error_code v5_ccache_has_tgt(krb5_context ctx, krb5_ccache ccache, + krb5_creds *creds); +krb5_error_code v5_ccache_has_pwc(krb5_context ctx, krb5_ccache ccache, + krb5_creds *creds); krb5_error_code v5_cc_copy(krb5_context ctx, krb5_ccache occache, krb5_ccache *nccache); int v5_creds_check_initialized(krb5_context ctx, krb5_creds *creds); diff --git a/src/vfy.c b/src/vfy.c index 805b917..6c4bf4c 100644 --- a/src/vfy.c +++ b/src/vfy.c @@ -79,21 +79,21 @@ main(int argc, const char **argv) ctx = NULL; ret = krb5_init_context(&ctx); if (ret != 0) { - crit("error initializing Kerberos: %s", error_message(ret)); + crit("error initializing Kerberos: %s", v5_error_message(ret)); return ret; } ccache = NULL; ret = krb5_cc_default(ctx, &ccache); if (ret != 0) { - crit("error resolving ccache: %s", error_message(ret)); + crit("error resolving ccache: %s", v5_error_message(ret)); return ret; } keytab = NULL; ret = krb5_kt_default(ctx, &keytab); if (ret != 0) { - crit("error resolving keytab: %s", error_message(ret)); + crit("error resolving keytab: %s", v5_error_message(ret)); return ret; } @@ -102,7 +102,7 @@ main(int argc, const char **argv) ret = krb5_cc_get_principal(ctx, ccache, &mcreds.client); if (ret != 0) { crit("error reading client name from ccache: %s", - error_message(ret)); + v5_error_message(ret)); return ret; } ret = krb5_build_principal_ext(ctx, &mcreds.server, @@ -115,13 +115,13 @@ main(int argc, const char **argv) 0); if (ret != 0) { crit("error building ticket granting server name: %s", - error_message(ret)); + v5_error_message(ret)); return ret; } ret = krb5_cc_retrieve_cred(ctx, ccache, 0, &mcreds, &creds); if (ret != 0) { - crit("error reading ccache: %s", error_message(ret)); + crit("error reading ccache: %s", v5_error_message(ret)); return ret; } krb5_cc_close(ctx, ccache); @@ -131,7 +131,7 @@ main(int argc, const char **argv) server, keytab, NULL, &opts); if (ret != 0) { - crit("error verifying creds: %s", error_message(ret)); + crit("error verifying creds: %s", v5_error_message(ret)); } else { printf("OK\n"); }