Re: Race condition on change of expired password?

Russ Allbery <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.heimdal.general
Organization The Eyrie
Message-ID <[email protected]>
Russ Allbery <[email protected]> writes:

> It doesn't seem to *just* be a race condition.  I redid this test inside
> the Kerberos PAM module and added a forced five second delay in the
> prompter after printing the success message, but the subsequent AS-REQ
> still fails:

I think the code may just be wrong here, although that surprises me since
I would have thought someone would have noticed.

In lib/krb5/init_creds_pw.c, krb5_get_init_creds_password does:

    if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
        char buf2[1024];

        /* try to avoid recursion */
        if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
           goto out;

        /* don't try to change password where then where none */
        if (prompter == NULL)
            goto out;

        ret = change_password (context,
                               client,
                               ctx->password,
                               buf2,
                               sizeof(buf),
                               prompter,
                               data,
                               options);
        if (ret)
            goto out;
        chpw = 1;
        krb5_init_creds_free(context, ctx);
        goto again;
    }

change_password puts the new password in the fourth argument to that
function, which is buf2.  (Passing in sizeof(buf) instead of sizeof(buf2)
also looks wrong, since BUFSIZ may be larger than 1024.)  But then nothing
is ever done with buf2 before the function goes back to the top and does
the authentication again.  The authentication will therefore be retried
with the original password, and of course fail.

I think buf2 needs to be lifted to the outside scope, and in the above
change password code there should be a:

    password = buf2;

before retrying so that the new password is used for the retry.

Also, buf2 needs to be cleared.

Attached is a proposed patch, although I've not tested it.  Also pushed to
rra/heimdal on github.

-- 
Russ Allbery ([email protected])             <http://www.eyrie.org/~eagle/>
0001-Fix-reauthentication-after-password-change-in-init_c.patch (text/x-diff, 1.9 KB)
From d782936bb75112ca0609bf4dc6602f302023aeb7 Mon Sep 17 00:00:00 2001
From: Russ Allbery <[email protected]>
Date: Wed, 21 Dec 2011 18:38:36 -0800
Subject: [PATCH] Fix reauthentication after password change in
 init_creds_password

When retrying authentication after a password change of an expired
password, use the new password instead of the original one.  Also,
pass in the correct length for the new password buffer to
change_password and zero the buffer that holds the new password on
function exit.

Signed-off-by: Russ Allbery <[email protected]>
---
 lib/krb5/init_creds_pw.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c
index f6f6ff5..24cecb6 100644
--- a/lib/krb5/init_creds_pw.c
+++ b/lib/krb5/init_creds_pw.c
@@ -2422,7 +2422,7 @@ krb5_get_init_creds_password(krb5_context context,
 			     krb5_get_init_creds_opt *options)
 {
     krb5_init_creds_context ctx;
-    char buf[BUFSIZ];
+    char buf[BUFSIZ], buf2[BUFSIZ];
     krb5_error_code ret;
     int chpw = 0;
 
@@ -2474,8 +2474,6 @@ krb5_get_init_creds_password(krb5_context context,
 
 
     if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
-	char buf2[1024];
-
 	/* try to avoid recursion */
 	if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
 	   goto out;
@@ -2488,12 +2486,13 @@ krb5_get_init_creds_password(krb5_context context,
 			       client,
 			       ctx->password,
 			       buf2,
-			       sizeof(buf),
+			       sizeof(buf2),
 			       prompter,
 			       data,
 			       options);
 	if (ret)
 	    goto out;
+	password = buf2;
 	chpw = 1;
 	krb5_init_creds_free(context, ctx);
 	goto again;
@@ -2507,6 +2506,7 @@ krb5_get_init_creds_password(krb5_context context,
 	krb5_init_creds_free(context, ctx);
 
     memset(buf, 0, sizeof(buf));
+    memset(buf2, 0, sizeof(buf2));
     return ret;
 }
 
-- 
1.7.7.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.