Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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 nullok_secure).

auth [success=1 default=ignore] 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] uid eq 30027 quiet
auth sufficient nullok_secure
auth sufficient
auth required /lib/security/ forward_pass

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


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 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 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 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] 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.


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 nullok_secure
auth sufficient
auth required /lib/security/ forward_pass
share|improve this question
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 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] 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 forward_pass auth required 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 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

Are you really sure it's skipping

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

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.
  • would be attempted in all scenarios, and if it fails, would be attempted.
  • will be attempted if both of them fail.

Check your logs again. The radius logins may not be failing, but the 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.

share|improve this answer
I added more information to my original post to show what is happening. – Sidd Aug 8 '13 at 13:41
@Sidd Commenting out the uid eq 30027 check would cause the >=499 check to skip instead. Try temporarily removing quiet from the lines, that should make it easier to understand exactly what is firing and how it returns. – Andrew B Aug 8 '13 at 18:43

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.