Bug:

pam_opie module _always_ allows Unix (plaintext) password, even in the
cases which are disabled by OPIE auth procedure.

Description:

How non-PAM standalone OPIE works:

1) If OPIE user exists, its remote host checked against /etc/opieaccess
via opieaccessfile()

2) If remote host is found there, user home dir checked for ~/.opiealways 
file via opiealways()

3) If no such file, it is assumed than OPIE user is allowed to
authenticate with plaintext (Unix) password additionly to OPIE exchange.

In all other cases OPIE user is not allowed to authenticate with plaintext
(Unix) password.

How PAM OPIE works:

OPIE user can _always_ authenticate with plaintext (Unix) password which 
is is security lowering and violates OPIE way of things.

Fix:

It can't be fixed in current 2-state pam_opie return codes model, we need 
3 codes:

1) For OPIE exchange success
2) For OPIE exchange failure, but Unix (plaintext) passwords allowed
3) For OPIE exchange failure, but Unix (plaintext) passwords disabled

1) and 2) works exact as in old 2-state model, so 1) is PAM_SUCCESS and 2) 
is PAM_AUTH_ERR.

I choose PAM_CRED_INSUFFICIENT for case 3) which means that pam_opie 
module deside that all additionally possible auth will be insufficient and 
returns immediately from modules chain with this code.

--- pam_opie.c.old      Sun Jan 20 23:56:47 2002
+++ pam_opie.c  Mon Jan 21 00:24:51 2002
@@ -66,13 +66,14 @@
        struct opie opie;
        struct options options;
        struct passwd *pwd;
-       int retval, i;
+       int retval, i, pwok;
        char *(promptstr[]) = { "%s\nPassword: ", "%s\nPassword [echo on]: "};
        char challenge[OPIE_CHALLENGE_MAX];
        char prompt[OPIE_CHALLENGE_MAX+22];
        char resp[OPIE_SECRET_MAX];
        const char *user;
        const char *response;
+       const char *rhost;
 
        pam_std_option(&options, other_options, argc, argv);
 
@@ -97,6 +98,8 @@
                retval = pam_get_user(pamh, (const char **)&user, NULL);
                if (retval != PAM_SUCCESS)
                        PAM_RETURN(retval);
+               if ((pwd = getpwnam(user)) == NULL)
+                       PAM_RETURN(PAM_AUTH_ERR);
        }
 
        PAM_LOG("Got user: %s", user);
@@ -107,7 +110,14 @@
         */
        opiedisableaeh();
 
-       opiechallenge(&opie, (char *)user, challenge);
+       if (opiechallenge(&opie, (char *)user, challenge) == 0) {
+               rhost = NULL;
+               (void) pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);
+               pwok = (rhost != NULL) && (*rhost != '\0') &&
+                      opieaccessfile((char *)rhost) &&
+                      opiealways(pwd->pw_dir);
+       } else
+               pwok = 1;
        for (i = 0; i < 2; i++) {
                snprintf(prompt, sizeof prompt, promptstr[i], challenge);
                retval = pam_get_pass(pamh, &response, prompt, &options);
@@ -134,7 +144,10 @@
         * it expects.  Thus we can't log an error and can only check for
         * success or lack thereof.
         */
-       retval = opieverify(&opie, resp) == 0 ? PAM_SUCCESS : PAM_AUTH_ERR;
+       if (opieverify(&opie, resp) != 0)
+               retval = pwok ? PAM_AUTH_ERR : PAM_CRED_INSUFFICIENT;
+       else
+               retval = PAM_SUCCESS;
        PAM_RETURN(retval);
 }
 
--- ftpd.c.bak  Sat Jan 19 21:29:50 2002
+++ ftpd.c      Mon Jan 21 00:30:03 2002
@@ -1190,6 +1190,7 @@
                break;
 
        case PAM_AUTH_ERR:
+       case PAM_CRED_INSUFFICIENT:
        case PAM_USER_UNKNOWN:
        case PAM_MAXTRIES:
                rval = 1;
--- login.c.bak Sat Jan 19 21:05:16 2002
+++ login.c     Mon Jan 21 00:31:45 2002
@@ -802,6 +802,7 @@
                break;
 
        case PAM_AUTH_ERR:
+       case PAM_CRED_INSUFFICIENT:
        case PAM_USER_UNKNOWN:
        case PAM_MAXTRIES:
                rval = 1;
--- su.bak      Sat Jan 19 21:29:49 2002
+++ su  Mon Jan 21 00:39:04 2002
@@ -9,7 +9,7 @@
 auth           requisite       pam_wheel.so    no_warn auth_as_self noroot_ok
 #auth          sufficient      pam_kerberosIV.so       no_warn
 #auth          sufficient      pam_krb5.so     no_warn try_first_pass auth_as_self
-#auth          required        pam_opie.so     no_warn
+#auth [defalt=ignore success=done cred_insufficient=die] pam_opie.so  no_warn
 #auth          required        pam_ssh.so      no_warn try_first_pass
 auth           required        pam_unix.so     no_warn try_first_pass nullok
 #auth          sufficient      pam_rootok.so   no_warn
--- login.bak   Sat Jan 19 21:29:49 2002
+++ login       Mon Jan 21 00:39:04 2002
@@ -6,7 +6,7 @@
 
 # auth
 auth           required        pam_nologin.so  no_warn
-#auth          sufficient      pam_opie.so     no_warn
+#auth [defalt=ignore success=done cred_insufficient=die] pam_opie.so  no_warn
 #auth          sufficient      pam_kerberosIV.so       no_warn try_first_pass
 #auth          sufficient      pam_krb5.so     no_warn try_first_pass
 #auth          required        pam_ssh.so      no_warn try_first_pass
--- ftpd.bak    Sat Jan 19 21:29:49 2002
+++ ftpd        Mon Jan 21 00:39:04 2002
@@ -9,10 +9,8 @@
 #auth          sufficient      pam_kerberosIV.so       no_warn
 #auth          sufficient      pam_krb5.so     no_warn
 #auth           sufficient      pam_ssh.so      no_warn try_first_pass
-# Uncomment either pam_opie or pam_unix, but not both of them.
-# pam_unix can't be simple chained with pam_opie, ftpd provides proper fallback
-auth           required        pam_opie.so     no_warn
-#auth          required        pam_unix.so     no_warn try_first_pass
+#auth [defalt=ignore success=done cred_insufficient=die] pam_opie.so  no_warn
+auth           required        pam_unix.so     no_warn try_first_pass
 
 # account
 #account       required        pam_kerberosIV.so

-- 
Andrey A. Chernov
http://ache.pp.ru/

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message

Reply via email to