Package: libpam-krb5 Version: 4.4-1 Severity: wishlist Tags: upstream patch
When using FAST a ticket cache should be available beforehand. On some situations there is no such cache or it is not readable. Is it possible to add an option to automatically create this ticket cache by using the anonymous user? i.e. like calling 'kinit -n' before kinit. The attached patch suppose to do this by adding anon_fast option, but I'm not sure if there are any security issues. Thanks, Yair. -- System Information: Debian Release: wheezy/sid APT prefers testing APT policy: (990, 'testing'), (500, 'unstable'), (500, 'stable'), (1, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 2.6.38.4-rt-1 (SMP w/6 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages libpam-krb5 depends on: ii krb5-config 2.2 Configuration files for Kerberos V ii libc6 2.11.2-11 Embedded GNU C Library: Shared lib ii libkrb5-3 1.9+dfsg-1+b1 MIT Kerberos runtime libraries ii libpam-runtime 1.1.2-2 Runtime support for the PAM librar ii libpam0g 1.1.2-2 Pluggable Authentication Modules l libpam-krb5 recommends no packages. libpam-krb5 suggests no packages. -- no debconf information
diff --git a/auth.c b/auth.c index 0643505..d857356 100644 --- a/auth.c +++ b/auth.c @@ -131,34 +131,127 @@ set_fast_options(struct pam_args *args, krb5_get_init_creds_opt *opts) krb5_context c = args->ctx->context; krb5_error_code k5_errno; krb5_principal princ = NULL; + krb5_principal princ2 = NULL; krb5_ccache fast_ccache = NULL; + krb5_creds *fast_creds = NULL; + char armor_name[] = "/tmp/krb5cc_pam_armor_XXXXXX"; + char* fast_cache_name = (char*)&armor_name; + int pamret; + krb5_get_init_creds_opt *fast_opts = NULL; - if (!args->fast_ccache) - return; - k5_errno = krb5_cc_resolve(c, args->fast_ccache, &fast_ccache); - if (k5_errno != 0) { - pamk5_debug_krb5(args, k5_errno, "failed resolving fast ccache %s", - args->fast_ccache); - goto done; + /* + * If fast_ccache was given, we don't need anonymous. + */ + if (!args->fast_ccache) { + if (!args->anon_fast) + return; + + fast_creds = calloc(1, sizeof(krb5_creds)); + if (fast_creds == NULL) { + pamk5_err(args, "cannot allocate memory: %s, not using fast", + strerror(errno)); + goto done; + } + + k5_errno = krb5_build_principal_ext(c, &princ, + strlen(args->realm), args->realm, + strlen(KRB5_WELLKNOWN_NAMESTR), + KRB5_WELLKNOWN_NAMESTR, + strlen(KRB5_ANONYMOUS_PRINCSTR), + KRB5_ANONYMOUS_PRINCSTR, + NULL); + if (k5_errno != 0) { + pamk5_debug_krb5(args, k5_errno, + "cannot create anonymous principal"); + goto done; + } + + k5_errno = krb5_get_init_creds_opt_alloc(c, &fast_opts); + if (k5_errno != 0) { + pamk5_err_krb5(args, k5_errno, + "cannot allocate memory, not using fast"); + goto done; + } + + krb5_get_init_creds_opt_set_anonymous(fast_opts, 1); + + k5_errno = krb5_get_init_creds_password(c, fast_creds, princ, NULL, + NULL, NULL, 0, NULL, + fast_opts); + if (k5_errno != 0) { + pamk5_debug_krb5(args, k5_errno, "failed getting initial " + "credentials for anonymous user"); + goto done; + } + + /* + * same as pamk5_cache_init_random, but differnt name and different + * environment, and need to swap principals + */ + pamret = pamk5_cache_mkstemp(args, fast_cache_name); + if (pamret != PAM_SUCCESS) + goto done; + + /* + * write cache file. pamk5_cache_init uses args->ctx->princ to + * initialize the cache, so it is temporarily swapped. + */ + princ2 = args->ctx->princ; + args->ctx->princ = fast_creds->client; + pamret = pamk5_cache_init(args, fast_cache_name, fast_creds, + &fast_ccache); + args->ctx->princ = princ2; + if (pamret != PAM_SUCCESS) + goto done; + + pamret = pamk5_set_krb5ccname(args, fast_cache_name, + "PAM_FAST_KRB5CCNAME"); + if (pamret != PAM_SUCCESS) { + pamk5_debug_pam(args, pamret, + "cannot save temporary fast cache name"); + } + + + krb5_free_principal(c, princ); + princ = NULL; + } else { + fast_cache_name = args->fast_ccache; + k5_errno = krb5_cc_resolve(c, fast_cache_name, &fast_ccache); + if (k5_errno != 0) { + pamk5_debug_krb5(args, k5_errno, "failed resolving fast ccache %s", + fast_cache_name); + goto done; + } } + k5_errno = krb5_cc_get_principal(c, fast_ccache, &princ); if (k5_errno != 0) { pamk5_debug_krb5(args, k5_errno, "failed to get principal from fast ccache %s", - args->fast_ccache); + fast_cache_name); goto done; } k5_errno = krb5_get_init_creds_opt_set_fast_ccache_name(c, opts, - args->fast_ccache); + fast_cache_name); if (k5_errno != 0) pamk5_err_krb5(args, k5_errno, "failed setting fast ccache to %s", - args->fast_ccache); + fast_cache_name); done: - if (fast_ccache != NULL) - krb5_cc_close(c, fast_ccache); + if (fast_creds != NULL) { + krb5_free_cred_contents(c, fast_creds); + free(fast_creds); + } + if (fast_ccache != NULL) { + if (args->anon_fast && k5_errno != 0) + krb5_cc_destroy(c, fast_ccache); + else + krb5_cc_close(c, fast_ccache); + } if (princ != NULL) krb5_free_principal(c, princ); + if (fast_opts != NULL) + krb5_get_init_creds_opt_free(c, fast_opts); } #else /* !HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE_NAME */ # define set_fast_options(a, o) /* empty */ @@ -596,6 +689,8 @@ pamk5_password_auth(struct pam_args *args, const char *service, int do_only_alt = 0; char *pass = NULL; int authtok = (service == NULL) ? PAM_AUTHTOK : PAM_OLDAUTHTOK; + const char* fast_cache_name; + krb5_ccache fast_cache; /* Sanity check and initialization. */ if (args->ctx == NULL) @@ -823,5 +918,30 @@ done: } if (opts != NULL) pamk5_compat_opt_free(ctx->context, opts); + + /* + * Whatever the results, destroy the anonymous fast armor cache + */ + if (args->anon_fast) { + fast_cache_name = pamk5_get_krb5ccname(args, "PAM_FAST_KRB5CCNAME"); + if (fast_cache_name != NULL) { + + success = krb5_cc_resolve(ctx->context, fast_cache_name, + &fast_cache); + if (success != 0) { + pamk5_debug_krb5(args, success, + "cannot resolve temporary fast cache %s", + fast_cache_name); + } else { + + krb5_cc_destroy(ctx->context, fast_cache); + + if (pam_putenv(args->pamh, "PAM_FAST_KRB5CCNAME") != + PAM_SUCCESS) + pam_putenv(args->pamh, "PAM_FAST_KRB5CCNAME="); + } + } + } + return retval; } diff --git a/internal.h b/internal.h index c54c444..b3c2254 100644 --- a/internal.h +++ b/internal.h @@ -58,6 +58,7 @@ struct context { * functions. */ struct pam_args { + int anon_fast; /* sets up an anonymous fast armor cache */ char *banner; /* Addition to password changing prompts. */ char *ccache; /* Path to write ticket cache to. */ char *ccache_dir; /* Directory for ticket cache. */ diff --git a/options.c b/options.c index 9aabf4a..52fb807 100644 --- a/options.c +++ b/options.c @@ -291,6 +291,7 @@ pamk5_args_parse(pam_handle_t *pamh, int flags, int argc, const char **argv) krb5_get_default_realm(c, &args->realm); if (args->realm != NULL) pamk5_compat_set_realm(args, args->realm); + default_boolean(args, c, "anon_fast", 0, &args->anon_fast); default_string(args, c, "alt_auth_map", NULL, &args->alt_auth_map); default_string(args, c, "banner", "Kerberos", &args->banner); default_string(args, c, "ccache", NULL, &args->ccache); @@ -337,6 +338,8 @@ pamk5_args_parse(pam_handle_t *pamh, int flags, int argc, const char **argv) * sense in krb5.conf. */ for (i = 0; i < argc; i++) { + if (strcmp(argv[i], "anon_fast") == 0) + args->anon_fast = 1; if (strncmp(argv[i], "alt_auth_map=", 12) == 0) { if (args->alt_auth_map != NULL) free(args->alt_auth_map); @@ -505,9 +508,9 @@ pamk5_args_parse(pam_handle_t *pamh, int flags, int argc, const char **argv) /* Warn if the FAST option was set and FAST isn't supported. */ #ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE_NAME - if (args->fast_ccache) - pamk5_err(args, "fast_ccache requested but FAST not supported by" - " Kerberos libraries"); + if (args->fast_ccache || args->anon_fast) + pamk5_err(args, "fast_ccache or anon_fast requested but FAST not" + " supported by Kerberos libraries"); #endif return args; diff --git a/pam_krb5.pod b/pam_krb5.pod index 8cc1a93..a4597f4 100644 --- a/pam_krb5.pod +++ b/pam_krb5.pod @@ -313,6 +313,15 @@ group. =over 4 +=item anon_fast + +Attempt to use Flexible Authentication Secure Tunneling (FAST) by first +authenticating as the anonymous user (WELLKNOWN/ANONYMOUS) and using its +credentials as the FAST armor. The operation is the same as if using the +I<fast_ccache> option, but the cache is created and destroyed automatically. If +both I<fast_ccache> and I<anon_fast> options are used, the I<fast_ccache> takes +precedent and no anonymous authentication is done. + =item fast_ccache=<ccache_name> Attempt to use Flexible Authenticatin Secure Tunneling (FAST) to protect