rra / pam-krb5

PAM module for Kerberos authentication
https://www.eyrie.org/~eagle/software/pam-krb5/
Other
19 stars 14 forks source link

When authenticating with an expired password, PAM prompts for a password change, when it shouldn't #18

Closed jkbremer closed 4 years ago

jkbremer commented 4 years ago

Hello,

We noticed that authenticating with libpam-krb5 prompts for changing the passwords of users with expired passwords, when it should not prompt. This happens in auth.c when password_auth() calls krb5_get_init_creds_password(). Because "pamk5_prompter_krb5" is passed with krb5_get_init_creds_password(), heimdal will prompt for a password change.

Breakpoint 1, password_auth (args=0x555555d3aab0, creds=0x555555d4ab50, opts=0x555555d51a70, service=0x0, pass=0x555555b51a00 "************") at ../auth.c:321
321 {
(gdb) n
323     struct context *ctx = args->config->ctx;
(gdb) 
327     if (args->debug) {
(gdb) 
345     if (pass != NULL && strlen(pass) > 1024) {
(gdb) 
351     retval = krb5_get_init_creds_password(ctx->context, creds, ctx->princ,
(gdb) 
PAM prompt: 'Password has expired'
PAM prompt: 'Your password will expire at Thu Jan  1 01:00:00 1970\n'
PAM prompt: 'Changing password'
PAM prompt: 'Success: Password changed\n'
362     if (retval == KRB5KDC_ERR_KEY_EXP) {
(gdb) p retval 
$1 = 0
(gdb) 

The case "retval == KRB5KDC_ERR_KEY_EXP" is never reached, because heimdal returns 0 if the password is expired and reset successfully.

By consequence, pamret can never be PAM_NEW_AUTHTOK_REQD.

 852         case KRB5KDC_ERR_KEY_EXP:
 853             status = PAM_NEW_AUTHTOK_REQD;
 854             break;

As a result, this breaks the options "defer_pwchange" and "force_pwchange" since this code path is not reached:

 963     pamret = pamk5_password_auth(args, NULL, &creds);
 964     if (pamret == PAM_NEW_AUTHTOK_REQD) {
 965         if (args->config->fail_pwchange)
 966             pamret = PAM_AUTH_ERR;
 967         else if (args->config->defer_pwchange) {
 968             putil_debug(args, "expired account, deferring failure");
 969             ctx->expired = 1;
 970             pamret = PAM_SUCCESS;
 971         } else if (args->config->force_pwchange) {
 972             pam_syslog(args->pamh, LOG_INFO, "user %s password expired,"
 973                        " forcing password change", ctx->name);
 974             pamk5_conv(args, "Password expired.  You must change it now.",
 975                        PAM_TEXT_INFO, NULL);
 976             pamret = pam_get_item(args->pamh, PAM_AUTHTOK,
 977                                   (PAM_CONST void **) &pass);
 978             if (pamret == PAM_SUCCESS && pass != NULL)
 979                 pam_set_item(args->pamh, PAM_OLDAUTHTOK, pass);
 980             pam_set_item(args->pamh, PAM_AUTHTOK, NULL);
 981             args->config->use_first_pass = true;
 982             pamret = pamk5_password_change(args, false);
 983             if (pamret == PAM_SUCCESS)
 984                 putil_debug(args, "successfully changed expired password");
 985         }
 986     }

If "NULL" instead of "pamk5_prompter_krb5" is passed, the expired password is not reset and KRB5KDC_ERR_KEY_EXP is returned by heimdal.

rra commented 4 years ago

Yes, this is explicitly documented in the man page:

        This option is only supported when pam-krb5 is built with MIT
        Kerberos. If built against Heimdal, this option does nothing and
        normal expired password change handling still happens. (Heimdal is
        missing the required API to implement this option, at least as of
        version 1.6.)

defer_pwchange cannot currently be implemented with Heimdal because Heimdal is missing a required API. This has been fixed in Heimdal master, but has not yet been included in a release. See https://github.com/heimdal/heimdal/issues/322.

The last time I looked at this, I didn't see a good workaround, so I decided to wait for a new Heimdal release. I'm not sure if there is some variation of your patch that might work, but the patch as proposed doesn't; see all of the test failures shown below.

jkbremer commented 4 years ago

I rebuilt heimdal with the patch you mentioned and it works like a charm. :) Thank your for your help and your fast reply.