6

I have the following directives in my /etc/pam.d/sshd file on a RHEL5 box and I'm a bit confused. These directives are there to make LDAP+RADIUS+OTP work. What I'm trying to do is tell pam not to check users UID < 499 for LDAP+RADIUS+OTP and also to exclude UID = 30027 from being checked for the same.

This directive works as intended. It checks if UID >= 499 and if it is, it skips (auth sufficient pam_unix.so nullok_secure).

auth [success=1 default=ignore] pam_succeed_if.so uid >= 499 quiet

I'm confused here. This should do LDAP+RADIUS+OTP since success=1 but somehow it still works. Shouldn't it be skipping the next rule if true?

auth [success=1 default=ignore] pam_succeed_if.so uid eq 30027 quiet
auth sufficient pam_unix.so nullok_secure
auth sufficient  pam_radius_auth.so
auth required /lib/security/pam_google_authenticator.so forward_pass

Although, I've gotten things to work as I want them to, I'm confused behind the logic of it.


Update

Ok, so this is what I get in /var/log/secure when I ssh using a local user that has an uid of 30327 -

Aug  8 08:21:30 journey sshd[9357]: Accepted keyboard-interactive/pam for sidd from 10.1.1.178 port 51242 ssh2
Aug  8 08:21:30 journey sshd[9357]: pam_unix(sshd:session): session opened for user sidd by (uid=0)

This is what I get ssh using root who has a uid of 0 (<499).

Aug  8 08:25:51 journey sshd[9402]: Accepted keyboard-interactive/pam for root from 10.1.1.178 port 51246 ssh2
Aug  8 08:25:51 journey sshd[9402]: pam_unix(sshd:session): session opened for user root by (uid=0)

This is what I get when I use an ldap user with just LDAP password and no OTP -

Aug  8 08:27:04 journey sshd[9447]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=journey  user=schoure
Aug  8 08:27:05 journey sshd(pam_google_authenticator)[9447]: Failed to read "/home/schoure/.google_authenticator"
Aug  8 08:27:07 journey sshd[9445]: error: PAM: Cannot make/remove an entry for the specified session for schoure from journey

This is what I get when I use an ldap user with LDAP + OTP -

Aug  8 08:28:13 journey sshd[9452]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=journey  user=schoure
Aug  8 08:28:13 journey sshd[9450]: Accepted keyboard-interactive/pam for schoure from 10.1.1.178 port 43068 ssh2
Aug  8 08:28:13 journey sshd[9450]: pam_unix(sshd:session): session opened for user schoure by (uid=0)

So you are right - pam_unix does fail for LDAP users but since it's set to "sufficient" it's not terminal. Thanks for clearing that up.

As to your other point of -

auth [success=1 default=ignore] pam_succeed_if.so uid eq 30027 quiet

not getting evaluated, I see that it is getting evaluated. If I comment out that directive, I get

Aug  8 08:34:39 journey sshd(pam_google_authenticator)[9537]: Failed to read "/home/sidd/.google_authenticator"
Aug  8 08:34:42 journey sshd[9535]: error: PAM: Cannot make/remove an entry for the specified session for sidd from journey

So I am still confused as to how this works since clearly 30327 > 499 and hence it should skip the second line. The only reason I can see this working if PAM some how adds an implicit OR between the first two lines.

UPDATE 2

Ah, I see what is happening. That line in effect is just a place holder. I changed that UID to some random UID that doesn't exist and it still worked. So I understand the logic -

  1. Line 1 checks UID. If it's more than 499, it skips to line 3 where it is checked locally. Since UID > 499 are not local, that condition fails but being a non-terminal directive, it moves on to LDAP + RADIUS + OTP.
  2. If I comment out line 2 which has a particular UID set, what happens is PAM completely skips over local authentication because of the success=1.

So in effect, me doing something wrong made it work. I get what I need to do and it's working for me.

I don't want local users to be authenticated via LDAP + RADIUS + OTP, so these three lines should do the job for me. They are working but I would just like confirmation that they are right -

auth sufficient pam_unix.so nullok_secure
auth sufficient  pam_radius_auth.so
auth required /lib/security/pam_google_authenticator.so forward_pass
Sidd
  • 103
  • 1
  • 9
  • Didn't know this question had been updated since my last comment. Yes, multiple lines of `auth sufficient` terminating on an `auth required` is a fairly common config. If pam_radius_auth.so supports it (`man pam_radius_auth`), you can add an option of `try_first_pass` and the password used for the failed pam_unix check will be attempted for pam_radius_auth without the user being reprompted. – Andrew B Aug 19 '13 at 13:39
  • Also, I think it's worth mentioning that OTP tokens (i.e. google authenticator) are typically used to supplement password checks, not replace them. To accomplish this, you'd change the first line to `[success=1 default=ignore]` and the second line to `auth required`. To skip the OTP check on the local network (or from specified source IPs), you could then add `auth [success=done default=ignore] pam_access.so accessfile=/path/to/file noaudit` immediately before the pam_google_authenticator check. Create the accessfile first, obviously. – Andrew B Aug 19 '13 at 13:50
  • The way I have it setup, the user needs his password + OTP to login. If I change the second line to required, it doesn't work. The two lines are actually just passing the info to the radius server. On the radius server, these are the two directives that I have set in /etc/pam.d/radiusd - `auth required pam_google_authenticator.so forward_pass` `auth required pam_ldap.so use_first_pass ` I am sure there is some room for improvement here as well. – Sidd Aug 19 '13 at 16:40
  • I'm finding this question increasingly difficult to work with due to the constant shifting of the scope. I'm going to stick to to textbook facts here, and you're on your own for the rest. `sufficient` is non-terminal *on failure*, but terminal on *success*. The three lines you have provided in your question will never invoke `pam_google_authenticator.so` unless the `sufficient` tests both fail. Unless `pam.d/sshd` includes another file after those three lines, the `forward_pass` does nothing as there is no module to use the prompted password. It *prompts* for it, but nothing ever uses it. – Andrew B Aug 19 '13 at 19:45
  • I completely agree with your point. I am just pointing out that this works because on the radius server, both directives are set as required. I have this configuration running on 173 machines and they won't authenticate without password + OTP. If you just use password, the login fails. If only the OTP is used, the login fails. If I comment out the google authenticator directive on the clients, I am able to login just with password and no OTP. My systems are running as intended. I was trying to figure out the logic and I appreciate all your help. – Sidd Aug 19 '13 at 20:22

1 Answers1

3

Are you really sure it's skipping pam_unix.so?

sufficient is a "non-terminal" behavior on failure. Even if the pam_unix.so check fails, authentication will go on to attempt pam_radius_auth.so.

My interpretation is:

  • The uid eq 30027 check will never return true. The test will only run if the uid is <499, making it impossible for the condition of uid eq 30027 to be true.
  • pam_unix.so would be attempted in all scenarios, and if it fails, pam_radius_auth.so would be attempted.
  • pam_google_authenticator.so will be attempted if both of them fail.

Check your logs again. The radius logins may not be failing, but the pam_unix.so check probably is logging a failure. It just isn't preventing your logins.


This answer accurately covers the scope of the original question. Any additional questions that have been posed through updates or comments will not be covered.

Andrew B
  • 31,858
  • 12
  • 90
  • 128
  • I added more information to my original post to show what is happening. – Sidd Aug 08 '13 at 13:41
  • @Sidd Commenting out the `uid eq 30027` check would cause the `>=499` check to skip `pam_passwd.so` instead. Try temporarily removing `quiet` from the `pam_succeed_if.so` lines, that should make it easier to understand exactly what is firing and how it returns. – Andrew B Aug 08 '13 at 18:43