Bug 449256

Summary: exim SMTP authentication with shadow passwords always fails
Product: Red Hat Enterprise Linux 5 Reporter: Chip Coldwell <coldwell>
Component: pamAssignee: Tomas Mraz <tmraz>
Status: CLOSED NEXTRELEASE QA Contact:
Severity: high Docs Contact:
Priority: medium    
Version: 5.2   
Target Milestone: rc   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2009-10-01 21:04:27 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
patch that fixes the issue (but might not be desirable for other reasons) none

Description Chip Coldwell 2008-06-01 03:36:07 UTC
Description of problem:

The subject nearly says it all: if you use shadow passwords and the exim
plaintext authenticator (over TLS) configured to use PAM to authenticate
credentials, thus

PLAIN:
  driver                     = plaintext
  server_set_id              = $auth2
  server_prompts             = :
  server_condition           = ${if pam{$2:$3}{1}{0}}
  server_advertise_condition = ${if def:tls_cipher }

then it doesn't work, although if you copy the password from /etc/shadow to
/etc/passwd it works fine.  I did a good deal of debugging, and I think I can
explain the root cause of the problem.

The exim MTA runs as an unprivileged user "exim" (uid 93 on my system).  When
the exim daemon does a callout to PAM to validate user credentials.  The
pam_unix module determines that the password is shadowed, and that the user is
unprivileged, and executes a SUID helper binary /sbin/unix_chkpwd as

/sbin/unix_chkpwd username nonull

with the PAM library that forked this command sending the password to the child
process through a pipe.

The problem is that /sbin/unix_chkpwd program contains the following:

        if (SELINUX_ENABLED && getuid() == 0) {
          user=argv[1];
        }
        else {
          user = getuidname(getuid());
          /* if the caller specifies the username, verify that user            
                                                    
             matches it */
          if (strcmp(user, argv[1])) {
            return PAM_AUTH_ERR;
          }
        }

So, even if SELinux is enabled, because our UID 93 is nonzero, we execute the
else clause.  This tests to see if the process UID matches the username provided
on the command line.  Since the username provided on the command line is the
name of the user wanting SMTP authentication and the UID of the process matches
the user "exim", this always fails.  Thus, SMTP authentication with exim cannot
use PAM and shadow passwords.

Version-Release number of selected component (if applicable):

pam-0.99.6.2-3.27.el5

How reproducible:

Easily.

Steps to Reproduce:
1.  Configure exim to use the PLAIN authenticator with PAM (uncomment the stanza
in the default /etc/exim/exim.conf)
2.  Configure PAM to use shadow passwords.
3.  Attempt an SMTP authentication.

It might be easier to use a simple PAM test program; I wrote one and can supply
it.  Just run the program as one unprivileged user trying to authenticate another.

Actual results:

SMTP Authentication always fails.

Expected results:

SMTP Authentication should succeed for valid credentials.

Additional info:

I have verified that patching /sbin/unix_chkpwd to remove the if/else statement
above fixes the problem.  I am attaching the patch FYI.

Comment 1 Chip Coldwell 2008-06-01 03:36:07 UTC
Created attachment 307298 [details]
patch that fixes the issue (but might not be desirable for other reasons)

Comment 2 Tomas Mraz 2008-06-02 10:05:50 UTC
The check is there for a purpose and cannot be removed. The unix_chkpwd must not
allow a regular user to check another user's password hash. The current PAM in
Fedora 9 does not do the check explicitely though. It will just do
setuid(getuid()) call and so if /etc/shadow would be readable to the exim
process - it will allow to proceed and verify the password hash. I am not sure
whether the pam_unix module in RHEL-5 would allow this, you can verify that by
adding ACL on /etc/shadow or making /etc/shadow group readable and owned by the
exim user's group.


Comment 3 Chip Coldwell 2008-06-02 15:15:53 UTC
(In reply to comment #2)
> The check is there for a purpose and cannot be removed. The unix_chkpwd must not
> allow a regular user to check another user's password hash.

That requirement is a bit too heavy handed.  I agree that if any user can read
the hashes in /etc/shadow then there's no point in storing the hashes in
/etc/shadow instead of /etc/passwd; however, I think the Fedora approach:

> The current PAM in
> Fedora 9 does not do the check explicitely though. It will just do
> setuid(getuid()) call and so if /etc/shadow would be readable to the exim
> process - it will allow to proceed and verify the password hash.

makes a lot more sense.  Then, for example, you could have a "shadow" group, and
make /etc/shadow readable to members of that group, then add the exim user to it.

> I am not sure
> whether the pam_unix module in RHEL-5 would allow this, you can verify that by
> adding ACL on /etc/shadow or making /etc/shadow group readable and owned by the
> exim user's group.

It won't; you don't have to do any experiments to see that from the source code
for /sbin/unix_chkpwd.  In particular, the test I quoted above

       if (SELINUX_ENABLED && getuid() == 0) {
          user=argv[1];
        }
        else {
          user = getuidname(getuid());
          /* if the caller specifies the username, verify that user            
                                                    
             matches it */
          if (strcmp(user, argv[1])) {
            return PAM_AUTH_ERR;
          }
        }

shows that it will only allow a user to check his own password hash,
irregardless of whether or not he can read /etc/shadow.

Comment 4 Tomas Mraz 2008-06-02 15:28:23 UTC
The pam_unix module code is different in RHEL-5 from the F-9 version so it might
work if SELinux doesn't prevent it.


Comment 6 Tomas Mraz 2009-10-01 21:04:27 UTC
The checks are slightly relaxed in current Fedora releases which means that RHEL-6 should be OK in this regard.