unix_chkpwd fails with Percona pam plugin

Bug #1086795 reported by Raghavendra D Prabhu
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
percona-pam-for-mysql
New
Undecided
Unassigned

Bug Description

Using pam_unix with PAM plugin shouldn't require root privileges
since pam_unix can use unix_chkpwd, a setuid helper.

unix_chkpwd is also used by other non-root utilities like xlock.

The helper is used only if geteuid returns non-zero, otherwise it
can read shadow file directly with getspnam etc.

http://sprunge.us/ONLb is a list of applications/roles which use
pam_unix in auth setting, some of them run as non-root.

=================
Dec 05 15:51:58 Archie mysqld[11366]: pam_warn(mysqld:auth): function=[pam_sm_authenticate] service=[mysqld] terminal=[<unknown>] user=[raghavendra] ruser=[raghavendra] rhost=[localhost]
Dec 05 15:51:58 Archie unix_chkpwd[11417]: salt null
Dec 05 15:51:58 Archie unix_chkpwd[11417]: check pass; user unknown
Dec 05 15:51:58 Archie unix_chkpwd[11417]: password check failed for user (raghavendra)
Dec 05 15:51:58 Archie mysqld[11366]: pam_unix(mysqld:auth): authentication failure; logname= uid=89 euid=89 tty= ruser=raghavendra rhost=localhost user=raghavendra

================

The "salt null" was a message I added to the PAM library for
diagnostic purposes.

Now, the salt is null because get_pwd_hash used by
helper_verify_password in pam_unix returns value 9 which stands for
PAM_AUTHINFO_UNAVAIL

However, this has nothing to do with salting itself.

This seems to be happening because the uid/euid used for PAM
should match the PAM_USER's uid.

ec 05 18:42:45 Archie mysqld[5203]: pam_warn(mysqld:auth): function=[pam_sm_authenticate] service=[mysqld] terminal=[<unknown>] user=[testit] ruser=[testit] rhost=[localhost]
Dec 05 18:42:45 Archie unix_chkpwd[5523]: name testit
Dec 05 18:42:45 Archie unix_chkpwd[5523]: retval 9
Dec 05 18:42:45 Archie unix_chkpwd[5523]: salt null
Dec 05 18:42:45 Archie unix_chkpwd[5523]: check pass; user unknown
Dec 05 18:42:45 Archie unix_chkpwd[5523]: password check failed for user (testit)
Dec 05 18:42:45 Archie mysqld[5203]: pam_unix(mysqld:auth): authentication failure; logname= uid=89 euid=89 tty= ruser=testit rhost=localhost user=testit
Dec 05 18:42:57 Archie logger[5555]: ACPI group/action undefined: processor / LNXCPU:00
Dec 05 18:43:12 Archie mysqld[5203]: pam_warn(mysqld:auth): function=[pam_sm_authenticate] service=[mysqld] terminal=[<unknown>] user=[mysql] ruser=[mysql] rhost=[localhost]
Dec 05 18:43:12 Archie unix_chkpwd[5568]: name mysql
Dec 05 18:43:12 Archie unix_chkpwd[5568]: retval 0

In the above example, testit and mysql are two users, in case of
testit it fails (name, retval, salt are diagnostics added by me).

However, it succeeds in case of mysql user (which mysqld also
runs as), why? because the uid/euid=89 matches the uid of the
user itself (added as -- create user 'mysql'@'localhost' IDENTIFIED WITH auth_pam; ).

So, the workaround, till it is fixed, is to use mysql system user itself as part of pam plugin authentication.

Revision history for this message
Raghavendra D Prabhu (raghavendra-prabhu) wrote :

https://gist.github.com/b137adf6105afc0ba83c is where the PAM authentication fails.

Since, salt is NULL,

========
 helper_log_err(LOG_WARNING, "check pass; user unknown");
retval = PAM_USER_UNKNOWN;
============

and

=============================

 retval = helper_verify_password(user, pass, nullok);

 memset(pass, '\0', MAXPASS); /* clear memory of the password */

 /* return pass or fail */

 if (retval != PAM_SUCCESS) {
  if (!nullok || !blankpass) {
   /* no need to log blank pass test */
#ifdef HAVE_LIBAUDIT
   if (getuid() != 0)
    _audit_log(AUDIT_USER_AUTH, user, PAM_AUTH_ERR);
#endif
   helper_log_err(LOG_NOTICE, "password check failed for user (%s)", user);
  }
  return PAM_AUTH_ERR;
 } else {
         if (getuid() != 0) {
#ifdef HAVE_LIBAUDIT
   return _audit_log(AUDIT_USER_AUTH, user, PAM_SUCCESS);
#else
          return PAM_SUCCESS;
#endif
         }
  return PAM_SUCCESS;
 }

=======================================

hence, the message "password check failed for user ..." printed

Revision history for this message
Raghavendra D Prabhu (raghavendra-prabhu) wrote :

 To summarize the problem -- "the one talking to PAM is not the same uid as the one who is get authenticated", hence, the PAM authentication should take place on the client side (may be in the client plugin).

Revision history for this message
Sergei Glushchenko (sergei.glushchenko) wrote :

Raghu,

Regarding the last comment "...the PAM authentication should take place on the client side...". This approach breaks security totally. Anyone could write client which will always authenticate successfully on my server in this case. This is not what I may want from PAM authentication plugin when I use it.

Revision history for this message
Raghavendra D Prabhu (raghavendra-prabhu) wrote :

> Regarding the last comment "...the PAM authentication should
> take place on the client side...". This approach breaks
> security totally. Anyone could write client which will always
> authenticate successfully on my server in this case. This is
> not what I may want from PAM authentication plugin when I use
> it.

Sergei,

1)

Isn't that the point of having pam_unix in PAM plugin stack? I
mean if I have authenticated as X user, I don't need any more
authentication (other than knowing password for X account) for
logging into mysql server as X user. Isn't that the purpose and
the role played by the plugin? (ie. when pam_unix is used)

Regarding "Anyone could write client which will always authenticate successfully on my server in this case.", they can only if they authenticate as the 'X' user.

I think that may be root cause why unix_chkpwd is not working, it
checks the euid of the user and since the tuple (euid, username)
doesn't match, it returns 'user unknown' (because getspnam
returns empty).

The gist is that if I can do sudo -u anotheruser bash and run
commands, then I should be able to do mysql -u anotheruser when
logged in as that user.

What I see happening now is that MySQL server acts as a middleman

 pam_unix/shadow <---> MySQL server <--------> MySQL client

 I don't think PAM can work like that (or may, *needs to be
 checked* (I am not sure RUSER vs USER makes difference here)).
 The other pam_unix + unix_chkpwd users like xlock run as the
 authenticating user itself.

 2) Secondary to this bug, another reason why I (and others have
 echoed it) think doing in client may help is that currently
 password is sent clear-text in the ensuing communication for
 authentication. So, fixing the above, may fix this as well.

Revision history for this message
Raghavendra D Prabhu (raghavendra-prabhu) wrote :

Quick correction in the above,
>I mean if I have authenticated as X user, I don't need any more
>authentication (other than knowing password for X account) for
>logging into mysql server as X user

I have seen that I can authenticate to mysql/pam as Y user when logged in as X user, with Y user's password (currently only possible if Y == 'mysql' ; which is essentially equivalent to authenticating as Y user). However, if I am already logged in as Y user and try to authenticate to mysql as Y user, it will still ask for Y user's password which is fine.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.