PAM_LDAP - System accounts locked out

Hi

I set up my FreeBSD 10.0 RELEASE to authenticate against OpenLDAP, which is installed non-redundant on the very same host. I'm using pam_ldap as described in the following tutorial: http://www.freebsd.org/doc/en/articles/ldap-auth/client.html. Fortunately it seems working quite nice, even though this little anoying problem: If slapd for what ever reason dies / isn't available to pam_ldap, then neither system- nor LDAP-logins are possible anymore. In other words: I'm locked out ;(
Of course it would be lovely to have pam.d configurations which are always giving permission to local system accounts (/etc/passwd) - no matter whether LDAP is reachable or not. Is this possible to configure within pam.d configurations - or do I have to implement a separate shell script which will periodically check for LDAP availability and change pam.d configurations according to it's result?

Those are my following configurations of pam.d:

/etc/pam.d/system
Code:
# auth
auth        sufficient  pam_opie.so                  no_warn no_fake_prompts
auth        requisite   pam_opieaccess.so            no_warn allow_local
#auth       sufficient  pam_krb5.so                  no_warn try_first_pass
#auth       sufficient  pam_ssh.so                   no_warn try_first_pass
auth        sufficient  /usr/local/lib/pam_ldap.so   no_warn try_first_pass
auth        required    pam_unix.so                  no_warn try_first_pass nullok

# account
#account    required    pam_krb5.so
account     required    /usr/local/lib/pam_ldap.so   ignore_unknown_user ignore_authinfo_unavail
account     required    pam_login_access.so
account     required    pam_unix.so

# session
#session    optional    pam_ssh.so
session     required    /usr/local/lib/pam_mkhomedir.so
session     required    pam_lastlog.so      no_fail

# password
#password   sufficient  pam_krb5.so     no_warn try_first_pass
password    required    pam_unix.so     no_warn try_first_pass

/etc/pam.d/sshd
Code:
# auth
auth        sufficient  /usr/local/lib/pam_ldap.so    no_warn
auth        sufficient  pam_opie.so                   no_warn no_fake_prompts
auth        requisite   pam_opieaccess.so             no_warn allow_local
#auth       sufficient  pam_krb5.so                   no_warn try_first_pass
#auth       sufficient  pam_ssh.so                    no_warn try_first_pass
auth        required    pam_unix.so                   no_warn try_first_pass

# account
account     required    pam_nologin.so
#account    required    pam_krb5.so
account     required    pam_login_access.so
account     required    pam_unix.so
account     required    /usr/local/lib/pam_ldap.so    no_warn ignore_authinfo_unavail ignore_unknown_user

# session
#session    optional    pam_ssh.so
session     required    /usr/local/lib/pam_mkhomedir.so
session     required    pam_permit.so

# password
#password   sufficient  pam_krb5.so     no_warn try_first_pass
password    required    pam_unix.so     no_warn try_first_pass

/etc/pam.d/su
Code:
# auth
auth            sufficient      pam_rootok.so           no_warn
auth            sufficient      pam_self.so             no_warn
auth            requisite       pam_group.so            no_warn group=wheel root_only fail_safe ruser
auth            include         system

# account
account         include         system

# session
session         required        /usr/local/lib/pam_mkhomedir.so
session         required        pam_permit.so

Any hints of what I'm missing to aim my goal are much appreciated

Thanks & best regards
 
General rule of thumb that I found useful was to add pam_ldap.so rules right before pam_unix.so for each of the policies you want to use it for. Also in nsswitch.conf I order the services files cache ldap so nscd doesn't get in the way when looking up local accounts. If you're using nscd you could very well be having a caching issue which is preventing you from logging in, don't under estimate how annoying that thing can be when troubleshooting PAM issues. Here's a snippet of how I set it up.

Code:
/etc/pam.d # grep -A1 ldap *
sshd:auth sufficient /usr/local/lib/pam_ldap.so no_warn try_first_pass minimum_uid=1000
sshd-auth               required        pam_unix.so             no_warn try_first_pass
--
sshd:account required /usr/local/lib/pam_ldap.so ignore_authinfo_unavail ignore_unknown_user minimum_uid=1000
sshd-account            required        pam_unix.so
--
sshd:password required /usr/local/lib/pam_ldap.so use_authok minimum_uid=1000
sshd-password   required        pam_unix.so             no_warn try_first_pass
--
system:auth sufficient /usr/local/lib/pam_ldap.so no_warn try_first_pass minimum_uid=1000
system-auth             required        pam_unix.so             no_warn try_first_pass nullok
--
system:account required /usr/local/lib/pam_ldap.so ignore_authinfo_unavail ignore_unknown_user minimum_uid=1000
system-account          required        pam_unix.so
--
system:password required /usr/local/lib/pam_ldap.so use_authok minimum_uid=1000
system-password required        pam_unix.so             no_warn try_first_pass
 
Hi dpejesh,

Thanks for your reply.
dpejesh said:
General rule of thumb that I found useful was to add pam_ldap.so rules right before pam_unix.so for each of the policies you want to use it for.
If I understodd you correctly, then your rule of thumb already applies to my /etc/pam.d/{system,sshd,su} config files, right? ... Yet, when slapd on localhost is not reachable, no further logins will be established successfully - instead I only get timeouts ;( My aim would be at least, that local system accounts (/etc/passwd) would still be possible - no matter if LDAP is reachable or not ... so in other words: it should skip for further LDAP checks, when initial lookup failed.

dpejesh said:
Also in nsswitch.conf I order the services files cache ldap so nscd doesn't get in the way when looking up local accounts. If you're using nscd you could very well be having a caching issue which is preventing you from logging in, don't under estimate how annoying that thing can be when troubleshooting PAM issues.

a) Thus far I'm not using nscd. It is not set to 'Yes' in /etc/rc.conf - I guess it makes sence, when my setup once is stable.

b) I modified my /usr/local/etc/rc.d/slapd script a little. When service slapd [start|restart] is executed, then nsswitch.conf(5) looks like:
Code:
group: files ldap
group_compat: nis
hosts: files dns
networks: files
passwd: files ldap
passwd_compat: nis
shells: files
services: compat
services_compat: nis
protocols: files
rpc: files
... and when service slapd stop is executed, then nsswitch.conf(5) looks like:
Code:
group: compat
group_compat: nis
hosts: files dns
networks: files
passwd: compat
passwd_compat: nis
shells: files
services: compat
services_compat: nis
protocols: files
rpc: files

What could I change in order to skip on further LDAP lookups if connection to localhost LDAP couldn't be established the very first time?

Thanks & best regards ;)
 
Leander said:
If I understodd you correctly, then your rule of thumb already applies to my /etc/pam.d/{system,sshd,su} config files, right?

What I meant was to change your configs to what I have below so the pam_ldap.so rules are right before pam_unix.so.

/etc/pam.d/system
Code:
# auth
auth        sufficient  pam_opie.so                  no_warn no_fake_prompts
auth        requisite   pam_opieaccess.so            no_warn allow_local
#auth       sufficient  pam_krb5.so                  no_warn try_first_pass
#auth       sufficient  pam_ssh.so                   no_warn try_first_pass
auth        sufficient  /usr/local/lib/pam_ldap.so   no_warn try_first_pass
auth        required    pam_unix.so                  no_warn try_first_pass nullok

# account
#account    required    pam_krb5.so
account     required    pam_login_access.so
account     required    /usr/local/lib/pam_ldap.so   ignore_unknown_user ignore_authinfo_unavail
account     required    pam_unix.so

# session
#session    optional    pam_ssh.so
session     required    /usr/local/lib/pam_mkhomedir.so
session     required    pam_lastlog.so      no_fail

# password
#password   sufficient  pam_krb5.so     no_warn try_first_pass
password    required    pam_unix.so     no_warn try_first_pass

/etc/pam.d/sshd
Code:
# auth
auth        sufficient  pam_opie.so                   no_warn no_fake_prompts
auth        requisite   pam_opieaccess.so             no_warn allow_local
#auth       sufficient  pam_krb5.so                   no_warn try_first_pass
#auth       sufficient  pam_ssh.so                    no_warn try_first_pass
auth        sufficient  /usr/local/lib/pam_ldap.so    no_warn try_first_pass
auth        required    pam_unix.so                   no_warn try_first_pass

# account
account     required    pam_nologin.so
#account    required    pam_krb5.so
account     required    pam_login_access.so
account     required    /usr/local/lib/pam_ldap.so    ignore_authinfo_unavail ignore_unknown_user
account     required    pam_unix.so

# session
#session    optional    pam_ssh.so
session     required    /usr/local/lib/pam_mkhomedir.so
session     required    pam_permit.so

# password
#password   sufficient  pam_krb5.so     no_warn try_first_pass
password    required    pam_unix.so     no_warn try_first_pass

As for /etc/pam.d/su, you shouldn't need to make any changes to that.
 
Hi dpejesh,

  • ==> /etc/pam.d/su is reset to it's defaults.
    ==> /etc/pam.d/system and
    ==> /etc/pam.d/sshd are modified according to your post.
Unfortunately no success. When I try to login as root via SSH and slapd is not running, then it doesn't even ask me for a password anymore. With my previous configuration it was still asking for a password before it didn't continue any further.

This is what I obviuolsy find in /var/log/messges
Code:
[...]
sshd[59274]: pam_ldap: ldap_starttls_s: Can't contact LDAP server
[...]
 
Yes, I do.

Code:
cd /usr/ports/net/nss_ldap
make install clean
ln -s /usr/local/etc/ldap.conf /usr/local/etc/nss_ldap.conf

PLUS my modification for the slapd rc script in order to skip ldap resolution if not running:

Code:
if [ ! -f /usr/local/etc/rc.d/slapd_ORIG ]; then
    cp -a /usr/local/etc/rc.d/slapd /usr/local/etc/rc.d/slapd_ORIG
else
    cp -a /usr/local/etc/rc.d/slapd_ORIG /usr/local/etc/rc.d/slapd
fi


if [ -z "$(cat /usr/local/etc/rc.d/slapd | grep 'files ldap')" ]; then

cat /usr/local/etc/rc.d/slapd | sed '
/start_postcmd=start_postcmd/ a\
stop_precmd=stop_precmd\
\
stop_precmd() {\
\  RESULT="$( cat /etc/nsswitch.conf | sed -E "s#(group: |passwd: ).*#\\1compat#g" )"\
\  echo "${RESULT}" > /etc/nsswitch.conf\
}\
' > /tmp/output && \
cp /tmp/output /usr/local/etc/rc.d/slapd && \
rm /tmp/output

cat /usr/local/etc/rc.d/slapd | sed '
/local socket seconds/ a\
\
\  RESULT="$( cat /etc/nsswitch.conf | sed -E "s#(group: |passwd: ).*#\\1files ldap#g" )"\
\  echo "${RESULT}" > /etc/nsswitch.conf
' > /tmp/output && \
cp /tmp/output /usr/local/etc/rc.d/slapd && \
rm /tmp/output

fi

How does this affect pam_ldap / my pam.d configs?
 
Uups, I just noticed the difference ;) no I'm not using net/nss-pam-ldapd

Should I use it instead of net/nss_ldap?

nss-pam-ldapd, a Name Service Switch (NSS) module and
Pluggable Authentication Module (PAM) that allows your
LDAP server to provide user account, group, host name,
alias, netgroup, and basically any other information that
you would normally get from /etc flat files or NIS. It also
allows you to do authentication to an LDAP server.

Key differences from nss_ldap:
* lighter NSS library
* lighter PAM library
* simpler internal semantics
* clear separation between NSS, PAM and LDAP code (the server
part could easily be implemented in another language)
* less connections to the LDAP server
 
net/nss_ldap isn't the same as net/nss-pam-ldapd. The former hasn't been updated in something like 4 years (01/17/2010 was the last update to the ports tree) while the latter started as a fork of it and is actively maintained. I'd highly suggest switching. With net/nss-pam-ldapd you no longer need /usr/local/etc/nss_ldap.conf, you instead use /usr/local/etc/nslcd.conf with a stripped down sample below.

Code:
binddn <binddn>
bindpw <pw>
bind_timelimit 15
idle_timelimit 300
timelimit 15
nss_initgroups_ignoreusers root
 
Oh, ok - thanks for the hint ;)
... Aside from the fact, that it is totally outdated - will it have effect on my initial issue, of having stucking logins, when slapd is not available anymore? Please correct me if I'm wrong, but I thought this is a plan pam.d issue?!
 
I believe it will. net/nss_ldap is so antiquated and I've had so many problems with it, not just on FreeBSD but also on Linux, over the years that I think it would be in FreeBSD's best interest to flag is as broken. Here's a link to another problem which was solved by switching.
 
Ok, I installed net/nss-pam-ldapd ... thus far it resolves UIDs as well as GUIDs propper when I test it with touch and ls. Unfortunately Logins are now totally denied.

Code:
su - Leander
su: unknown login: Leander

Code:
ssh Leander@192.168.1.100
Password for Leander@FreeBSD.domain.local:
Password for Leander@FreeBSD.domain.local:
Connection closed by 192.168.1.100

Here is the significant part of nslcd -d
Code:
nslcd: [6f59b2] <authc="Leander"> username changed from "Leander" to "leander"
nslcd: [6f59b2] <authc="Leander"> DEBUG: myldap_search(base="uid=leander,ou=users,dc=domain,dc=local", filter="(objectClass=*)")
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_initialize(ldap://127.0.0.1/)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_rebind_proc()
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,3)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_DEREF,0)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_TIMELIMIT,5)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_TIMEOUT,5)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT,5)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_REFERRALS,LDAP_OPT_ON)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_set_option(LDAP_OPT_RESTART,LDAP_OPT_ON)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_start_tls_s()
nslcd: [6f59b2] <authc="Leander"> DEBUG: set_socket_timeout(5,500000)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_simple_bind_s("uid=leander,ou=users,dc=domain,dc=local","***") (uri="ldap://127.0.0.1/")
nslcd: [6f59b2] <authc="Leander"> DEBUG: failed to bind to LDAP server ldap://127.0.0.1/: Invalid credentials
nslcd: [6f59b2] <authc="Leander"> DEBUG: set_socket_timeout(2,0)
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_unbind()
nslcd: [6f59b2] <authc="Leander"> uid=leander,ou=users,dc=domain,dc=local: lookup failed: Invalid credentials
nslcd: [6f59b2] <authc="Leander"> DEBUG: myldap_search(base="dc=domain,dc=local", filter="(&(objectClass=shadowAccount)(uid=leander))")
nslcd: [6f59b2] <authc="Leander"> DEBUG: ldap_result(): uid=leander,ou=users,dc=domain,dc=local
nslcd: DEBUG: accept() failed (ignored): Resource temporarily unavailable
nslcd: [6a1853] DEBUG: connection from pid=-1 uid=0 gid=0


Am I missing something?!
 
I'm not sure, I've never needed it, this might be what you're looking for though. Does it now let you login with a system account if slapd is down?
 
Ok, it looks like this case insenstiv option is not realy secure to use, is it?
This specifies whether or not to perform searches for group, netgroup, passwd, protocols, rpc, services and shadow maps using case-insensitive matching. Setting this to yes could open up the system to authorisation vulnerabilities and introduce nscd cache poisoning vulnerabilities which allow denial of service. The default is to perform case-sensitve filtering of LDAP search results for the above maps.


Yes, it works now. I set low timeouts, so if slapd is down, root and other /etc/passwd accounts still have access.
^^ THANKS A LOT for your help :beergrin

In order to give only a limited group of users acces to shell logins, I use following group:
Code:
ldapsearch -Z -tT /tmp "cn=Hostname-01"
[...]
# Hostname-01, groups, domain.local
dn: cn=Hostname-01,ou=groups,dc=domain,dc=local
objectClass: top
objectClass: groupOfUniqueNames
cn: Hostname-01
uniqueMember: uid=leander,ou=users,dc=domain,dc=local
uniqueMember: uid=patrick,ou=users,dc=domain,dc=local
[...]
... in combination with following option:
Code:
pam_groupdn          cn=Hostname-01,ou=groups,dc=domain,dc=local
... since I'm now using net/nss-pam-ldap, this option isn't valid anymore and it needs to be replaced. Therefore I found smething like this:
Code:
pam_authz_search (&(uid=\$username)(uniqueMember=cn=Hostname-01,ou=groups,dc=domain,dc=local))
which is placed in /usr/local/etc/nslcd.conf. Unfortunately it won't work - all logins fail after pam_authz_search is in nslcd.conf
Also, those users should still be able to browse through samba shares ... only su and ssh logins should be denied. Do you have any ideas of how I could solve this?

Thanks
 
Leander said:
Ok, it looks like this case insenstiv option is not realy secure to use, is it?

Depends on what you really need it for. But in general when you start mixing case you can get unexpected behavior.

Yes, it works now. I set low timeouts, so if slapd is down, root and other /etc/passwd accounts still have access.
^^ THANKS A LOT for your help :beergrin

You're welcome.

In order to give only a limited group of users acces to shell logins, I use following group:
Code:
ldapsearch -Z -tT /tmp "cn=Hostname-01"
[...]
# Hostname-01, groups, domain.local
dn: cn=Hostname-01,ou=groups,dc=domain,dc=local
objectClass: top
objectClass: groupOfUniqueNames
cn: Hostname-01
uniqueMember: uid=leander,ou=users,dc=domain,dc=local
uniqueMember: uid=patrick,ou=users,dc=domain,dc=local
[...]
... in combination with following option:
Code:
pam_groupdn          cn=Hostname-01,ou=groups,dc=domain,dc=local
... since I'm now using net/nss-pam-ldap, this option isn't valid anymore and it needs to be replaced. Therefore I found smething like this:
Code:
pam_authz_search (&(uid=\$username)(uniqueMember=cn=Hostname-01,ou=groups,dc=domain,dc=local))
which is placed in /usr/local/etc/nslcd.conf. Unfortunately it won't work - all logins fail after pam_authz_search is in nslcd.conf
Also, those users should still be able to browse through samba shares ... only su and ssh logins should be denied. Do you have any ideas of how I could solve this?

Thanks

I found using posixGroups in LDAP and AllowGroups in /etc/ssh/sshd_config to be the easiest way of controlling who has remote shell access.

ldif
Code:
DN: cn=sysadmin,ou=groups,dc=domain,dc=local
objectClass: posixGroup
objectClass: top
cn: sysadmin
gidNumber: 5000
memberUid: leander
memberUid: patrick

/etc/ssh/sshd_config
Code:
AllowGroups wheel sysadmin
 
dpejesh said:
I found using posixGroups in LDAP and AllowGroups in /etc/ssh/sshd_config to be the easiest way of controlling who has remote shell access.

ldif
Code:
DN: cn=sysadmin,ou=groups,dc=domain,dc=local
objectClass: posixGroup
objectClass: top
cn: sysadmin
gidNumber: 5000
memberUid: leander
memberUid: patrick

/etc/ssh/sshd_config
Code:
AllowGroups wheel sysadmin

Thanks - this worked ;)
Unfortunately su(1) logins are still possible from all LDAP accounts. Do you have a trick to restrict their access to su(1) as well?


Best regards
 
They shouldn't be able to. Did you make any changes to /etc/pam.d/su? The default should look like this. Or are your LDAP accounts in the wheel system group?
 
No, the two testusers are note member of wheel or any other group except the syslogin group you where pointing out.
Code:
id -Gn leander
leander storage-10

id -Gn patrick
patrick hostname-01

Yes, it looks alike, except the entry pam_mkhomedir.so ... but that shouldn't be the problem.
Code:
# auth
auth            sufficient      pam_rootok.so           no_warn
auth            sufficient      pam_self.so             no_warn
auth            requisite       pam_group.so            no_warn group=wheel root_only fail_safe ruser
auth            include         system

# account
account         include         system

# session
session         required        /usr/local/lib/pam_mkhomedir.so
session         required        pam_permit.so

is it mybe because of the system include line?
 
I tried to understand pam.d a little more and to me it doesn't make sense, why
Code:
no_warn group=wheel root_only fail_safe ruser
is not breaking the chain even though it is set to
Code:
requisite
... which according to the pam.d(5), should break the chain.
requisite
If this module succeeds, the result of the chain will be
success unless a later module fails. If the module fails,
the chain is broken and the result is failure.

To me it seems like I have to use something on a higher level, like this in /usr/local/etc/nslcd.conf:
Code:
pam_authz_search (&(uid=\$username)(uniqueMember=cn=Hostname-01,ou=groups,dc=domain,dc=local))
Yet I don't seem to get it into the right syntax ;(
 
I don't for sure know what's causing it, I've never run into this problem. What happens when you run getent group wheel? If the system doesn't see the wheel group it will allow anybody to su.

Edit: to clarify, I've been able to reproduce it by remove the wheel group altogether or just removing root from it and leaving it empty. In either case it will allow my LDAP accounts to run su.
 
I got the restriction working with
Code:
pam_authz_search (&(objectClass=posixGroup)(cn=Hostname-01)(memberUid=\$username))

The group wheel is left in default configuration except that I added the user admin to it:
Code:
getent group wheel
wheel:*:0:root,admin
I still don't get where the problem with this lies - even though the wildcard and the zero of getent(1) output are a bit confusing?!
 
Leander said:
I got the restriction working with
Code:
pam_authz_search (&(objectClass=posixGroup)(cn=Hostname-01)(memberUid=\$username))
That's another way of restricting access instead of AllowGroups in /etc/ssh/sshd_config. I prefer the sshd_config route because it's easier to allow access to multiple groups than it is to try and accomplish the same with pam_authz_search. The cleanest way I found to allow multiple groups using pam_authz_search was to use a dynamic group overlay and complicate the whole setup for something that's just a single setting in sshd_config. It's been awhile since I tried it, maybe they've made it easier.

The group wheel is left in default configuration except that I added the user admin to it:
Code:
getent group wheel
wheel:*:0:root,admin
I still don't get where the problem with this lies - even though the wildcard and the zero of getent(1) output are a bit confusing?!

That looks fine, I was just on a hunch that maybe you had modified the entry in /etc/group because at this point I'm pretty much stumped. Without actually having had this problem I'm just stabbing in the dark trying to reproduce it in my environment.
 
Back
Top