[Pkg-openldap-devel] More information on sudo-ldap SSL(ldaps://) breakage

Roberto C. Sánchez roberto at connexer.com
Sun Apr 15 02:42:37 UTC 2007


After upgrading my Sarge workstation to Etch today, I decided to start
messing aroud with sudo-ldap.  I was a bit disappointed to find that it
did not work with ldaps:// schemes.  I did some digging and here is what
I have found.  I think that there are a combination of factors, which is
I why I have CC'd the pkg-openldap list.  There must be something going
here that I am just not seeing.

The scenario:

miami.connexer.com - the workstation
santiago.connexer.com - the LDAP server
localadmin - is a local account on miami
roberto - is an account served from LDAP on santiago

I followed the directions in /usr/share/doc/sudo-ldap/README.LDAP.gz.

I have the following lines in /etc/ldap/ldap.conf:

BASE    dc=connexer,dc=com
URI     ldaps://santiago.connexer.com
TLS_CACERT      /etc/ldap/cacert.pem

sudoers_base ou=Sudoers,dc=connexer,dc=com
sudoers_debug 2

Now, santiago's slapd is only accessible via SSL over port 636.  This is
done both by not allowing slapd to bind to the cleartext port and also
by shorewall rules.  I loaded the sudoers info slapd on santiago.  From
miami, I can see the data:

roberto at miami:~$ ldapsearch -x -LLL objectclass=sudoRole
dn: cn=defaults,ou=Sudoers,dc=connexer,dc=com
objectClass: top
objectClass: sudoRole
cn: defaults
description: Default sudoOption's go here

dn: cn=root,ou=Sudoers,dc=connexer,dc=com
objectClass: top
objectClass: sudoRole
cn: root
sudoUser: root
sudoHost: ALL
sudoCommand: (ALL) ALL

dn: cn=roberto,ou=Sudoers,dc=connexer,dc=com
objectClass: top
objectClass: sudoRole
cn: roberto
sudoUser: roberto
sudoHost: ALL
sudoCommand: (ALL) ALL

Now, the sudoers file on miami has the following:

root    ALL=(ALL) ALL
localadmin      ALL=(ALL) ALL

The first step was to try invoke sudo from roberto's account:

roberto at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          (no)
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind_s()=81 : Can't contact LDAP server
Password:
Sorry, try again.
Password:
sudo: 1 incorrect password attempt

No joy.  Next, we try from localadmin's account:

roberto at miami:~$ su - localadmin
Password:
localadmin at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          (no)
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind_s()=81 : Can't contact LDAP server
.   .alias         .bash_logout   .bashrc  .lesshst  .Xauthority
..  .bash_history  .bash_profile  .cshrc   .ssh
localadmin at miami:~$ logout

It works, but the ldap_bind is still causing trouble.  Now, I have an
ldaps URI, but it still claims that ssl is not on.  I explicitly force
it on by adding the line "ssl on" to /etc/ldap/ldap.conf.  This is what
we see now for both accounts:

roberto at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          on
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind_s()=81 : Can't contact LDAP server
Password:
Sorry, try again.
Password:
sudo: 1 incorrect password attempt
roberto at miami:~$ su - localadmin
Password:
localadmin at miami:~$ sudo -k
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          on
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind_s()=81 : Can't contact LDAP server
localadmin at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          on
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind_s()=81 : Can't contact LDAP server
Password:
.   .alias         .bash_logout   .bashrc  .lesshst  .Xauthority
..  .bash_history  .bash_profile  .cshrc   .ssh
localadmin at miami:~$


So, it appears that nothing is really different here.  It turns out that
sudo's handling of TLS and SSL is somewhat broken (or brain dead).  I
applied the following patch to the sudo source package, rebuilt and
installed the new package:

----------8<---------->8----------
--- sudo-1.6.8p12.orig/ldap.c
+++ sudo-1.6.8p12/ldap.c
@@ -565,6 +565,9 @@
   if (!ldap_conf.port) ldap_conf.port=389;
   if (!ldap_conf.host) ldap_conf.host=estrdup("localhost");

+  if (ldap_conf.ssl && !strcasecmp(ldap_conf.ssl, "on")) {
+    ldap_conf.tls_checkpeer = LDAP_OPT_X_TLS_NEVER;
+  }

   if (ldap_conf.debug>1) {
     printf("LDAP Config Summary\n");
@@ -821,6 +824,8 @@

   /* Actually connect */

+  if (ldap_conf.debug>1) fprintf(stderr,
+         "ldap_simple_bind(ld,%s,%d)\n",ldap_conf.binddn,ldap_conf.bindpw);
   rc=ldap_simple_bind_s(ld,ldap_conf.binddn,ldap_conf.bindpw);
   if(rc){
     fprintf(stderr,"ldap_simple_bind_s()=%d : %s\n",
----------8<---------->8----------

Now, the check really needs to be smarter, so that the mere presence of
a directive to use port 636 or a URI starting with ldaps:// will make it
realize to use SSL instead of TLS.  But this is a quick and dirty hack.
Now, I have again removed the "ssl on" line from /etc/ldap/ldap.conf.
Here is what it looks like now for the two accounts:

roberto at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          (no)
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind(ld,(null),0)
ldap_simple_bind_s()=81 : Can't contact LDAP server
Password:
Sorry, try again.
Password:
sudo: 1 incorrect password attempt
roberto at miami:~$ su - localadmin
Password:
localadmin at miami:~$ sudo -k
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          (no)
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind(ld,(null),0)
ldap_simple_bind_s()=81 : Can't contact LDAP server
localadmin at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          (no)
===================
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind(ld,(null),0)
ldap_simple_bind_s()=81 : Can't contact LDAP server
Password:
.   .alias         .bash_logout   .bashrc  .lesshst  .Xauthority
..  .bash_history  .bash_profile  .cshrc   .ssh
localadmin at miami:~$

Looks exactly the same as before.  roberto can't do anything and
localadmin succeeds, but gets an ldap_bind() warning.

Now, we add the "ssl on" line back into /etc/ldap/ldap.conf:

roberto at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          on
===================
ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT,0x00)
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind(ld,(null),0)
ldap_simple_bind_s()=81 : Can't contact LDAP server
Password:
Sorry, try again.
Password:
sudo: 1 incorrect password attempt
roberto at miami:~$ su - localadmin
Password:
localadmin at miami:~$ sudo -k
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          on
===================
ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT,0x00)
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind(ld,(null),0)
ldap_bind() ok
found:cn=defaults,ou=Sudoers,dc=connexer,dc=com
ldap search '(|(sudoUser=localadmin)(sudoUser=%localadmin)(sudoUser=%localadmin)(sudoUser=ALL))'
ldap search 'sudoUser=+*'
user_matches=0
host_matches=0
sudo_ldap_check(-1)=0x44
localadmin at miami:~$ sudo ls -a
LDAP Config Summary
===================
uri          ldaps://santiago.connexer.com
ldap_version 3
sudoers_base ou=Sudoers,dc=connexer,dc=com
binddn       (anonymous)
bindpw       (anonymous)
ssl          on
===================
ldap_set_option(LDAP_OPT_X_TLS_REQUIRE_CERT,0x00)
ldap_initialize(ld,ldaps://santiago.connexer.com)
ldap_set_option(LDAP_OPT_PROTOCOL_VERSION,0x03)
ldap_simple_bind(ld,(null),0)
ldap_bind() ok
found:cn=defaults,ou=Sudoers,dc=connexer,dc=com
ldap search '(|(sudoUser=localadmin)(sudoUser=%localadmin)(sudoUser=%localadmin)(sudoUser=ALL))'
ldap search 'sudoUser=+*'
user_matches=0
host_matches=0
sudo_ldap_check(0)=0x44
Password:
.   .alias         .bash_logout   .bashrc  .lesshst  .Xauthority
..  .bash_history  .bash_profile  .cshrc   .ssh
localadmin at miami:~$

Now things get interesting.  roberto still can't get anything, but when
localadmin tries to use sudo, his bind succeeds and sudo is able to
query the LDAP server.  Now, the strange thing is that if I add a local
account for roberto to /etc/passwd and /etc/shadow (with the same uid
and gid as is present in LDAP), then it works the same way for him.
Now, according to the LDAP documentation for sudo, it doesn't use
nsswitch at all.  But I am wondering if there might be some hidden
interaction there.  Either way, there is something about having a local
account that makes it able to bind to the LDAP server that otherwise
causes it fail.  Naturally, this makes things less desirable, since the
point of LDAP is to not have to create local accounts.

Of course, if I add the ignore_local_sudoers option in LDAP, then nobody
can do anything.

I have carefully looked through the source code to see if I can figure
out what is going on.  But as far as I can tell, everything important to
this is happening in sudo_ldap_check() in ldap.c, which is called only
one time from within sudo.c.  I can't find anything that implies that
there is some sort of additional check or another call being made that
might cause it to pull in a local account without an LDAP account.
There are a couple of calls to getuid() and while I am not a C library
guru, my understanding is to the calling application that function
transperently queries all the sources of account data available to the
system.

Hopefully someone can make a bit more sense of this.  

Regards,

-Roberto
-- 
Roberto C. Sánchez
http://people.connexer.com/~roberto
http://www.connexer.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://lists.alioth.debian.org/pipermail/pkg-openldap-devel/attachments/20070414/a8978804/attachment-0001.pgp


More information about the Pkg-openldap-devel mailing list