[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: ldap auth from external application



On Thursday 25 June 2009 20:47:46 Zdenek Styblik wrote:
> Buchan Milne wrote:
> > On Thursday 25 June 2009 16:58:10 Zdenek Styblik wrote:
> >> I can see your point. It's hard to say as I've disabled anonymous sneaks
> >> and peaks into LDAP directory. You can browse, but authenticate first.
> >> Btw use of such user is done in nss-ldap from Padl, isn't it?
> >> One thing came to my mind, and it's - may be I misunderstood binding as
> >> 'anonymous' user in "many" applications. Such anonymous bind could be
> >> used to search for correct dn, and then- you've already said what is
> >> next. [but I still refuse anonymous searches through LDAP tree]
> >
> > But, the distinction here is that authentication doesn't require the
> > proxy user to have access to any special attributes, they in fact require
> > minimal access just to be able to identify the DN from the username they
> > were supplied with.
>
> Evening!
>
> Yeah, of course. Sorry, I've got carried away. Understood.
>
> > SASL-GSSAPI against Heimdal with Heimdal users stored in LDAP is one
> > solution, depending on your requirements. SASL-EXTERNAL with SSL client
> > certificates is another. However, many application support neither ....
>
> I've read on SALS back and forth, and it just didn't fit. I have SSL/TLS
> enforced wherever possible - I think it's good for now. And as you say,
> some mechanisms were supported, some weren't...
>
> > Please supply the LDAP-specific parts of your pure-ftpd configuration. I
> > am sure I have had pure-ftpd authenticate by BINDing, but I don't have
> > configs handy (where I run FTP authenticating against LDAP at them moment
> > I am using proftpd).
>
> No problem:
>
> LDAPServer 127.0.0.1
> LDAPPort   389
> LDAPBaseDN dc=turnovfree,dc=net
> LDAPBindDN cn=Pureftp,dc=turnovfree,dc=net
> LDAPBindPW verySecretPassword
> LDAPDefaultUID 2000
> LDAPDefaultGID 2000
> LDAPFilter (&(objectClass=posixAccount)(uid=\L))
> LDAPUseTLS True
>

After reading the README.LDAP, I didn't see any description of how 
authentication is done, so I looked, and in src/log_ldap.c, we have this:

void pw_ldap_check(AuthResult * const result,
                   const char *account, const char *password,
                   const struct sockaddr_storage * const sa,
                   const struct sockaddr_storage * const peer)
{
    struct passwd *pw;
    const char *spwd;                  /* Stored pwd */
    const char *cpwd = NULL;           /* Computed pwd */
    signed char nocase = 0;            /* Insensitive strcmp */

    (void) sa;
    (void) peer;
    result->auth_ok = 0;
    if (account == NULL || *account == 0 || password == NULL ||
        (pw = pw_ldap_getpwnam(account, result)) == NULL) {
        return;
    }
    result->auth_ok--;                  /* -1 */
    spwd = pw->pw_passwd;
    if (strncasecmp(spwd, PASSWD_LDAP_MD5_PREFIX,
                    sizeof PASSWD_LDAP_MD5_PREFIX - 1U) == 0) {
        spwd += (sizeof PASSWD_LDAP_MD5_PREFIX - 1U);
        if (strlen(spwd) >= 32U) {
            nocase++;
        }
        cpwd = crypto_hash_md5(password, nocase);
    } else if (strncasecmp(spwd, PASSWD_LDAP_SHA_PREFIX,
                           sizeof PASSWD_LDAP_SHA_PREFIX - 1U) == 0) {
        spwd += (sizeof PASSWD_LDAP_SHA_PREFIX - 1U);
        if (strlen(spwd) >= 40U) {
            nocase++;
        }
        cpwd = crypto_hash_sha1(password, nocase);
    } else if (strncasecmp(spwd, PASSWD_LDAP_SSHA_PREFIX,
                           sizeof PASSWD_LDAP_SSHA_PREFIX - 1U) == 0) {
        spwd += (sizeof PASSWD_LDAP_SSHA_PREFIX - 1U);
        cpwd = crypto_hash_ssha1(password, spwd);
    } else if (strncasecmp(spwd, PASSWD_LDAP_SMD5_PREFIX,
                           sizeof PASSWD_LDAP_SMD5_PREFIX - 1U) == 0) {
        spwd += (sizeof PASSWD_LDAP_SMD5_PREFIX - 1U);
        cpwd = crypto_hash_smd5(password, spwd);
    } else if (strncasecmp(spwd, PASSWD_LDAP_CRYPT_PREFIX,
                           sizeof PASSWD_LDAP_CRYPT_PREFIX - 1U) == 0) {
        spwd += (sizeof PASSWD_LDAP_CRYPT_PREFIX - 1U);
        cpwd = (const char *) crypt(password, spwd);
    } else if (*password != 0) {
        cpwd = password;               /* Cleartext */
    } else {
        return;                      /* Refuse null passwords */
    }
    if (cpwd == NULL) {
        return;
    }
    if (nocase != 0) {
        if (strcasecmp(cpwd, spwd) != 0) {
            return;
        }
    }
    if (strcmp(cpwd, spwd) != 0) {
        return;
    }

IOW, pure-ftpd is retrieving the password hash from LDAP, hashing the password 
from the user with the same hash (we hope), and comparing the resulting 
character arrays.

It would have been much easier to bind as the user's DN, and look at the 
result code ...

> This user has access to 'userPassword'.
> Documentation says:
> "- LDAPBindDN is the DN we should bind the server for simple
> authentication. If you don't need authentication (ie. anonymous users can
> browse that part of the LDAP directory), just remove that line."
>
> But we need to bind to the LDAP, or we won't be allowed to read anything
> at all.
>
> Anyway. I've tried to delete 'LDAPBindDN' and here goes result:
> slapd[14940]: conn=1490 op=1 BIND dn="" method=128
> ....
> slapd[14940]: conn=1513 op=2 SEARCH RESULT tag=101 err=50 nentries=0 text=
>
> ...and it doesn't work. err=50 is insufficient access, but - isn't an
> empty dn equivalent for anonymous?


I would:
1)File a bug on pure-ftpd, that it should offer an option (my preference would 
be that this should be the default) to bind as the user to validate the 
password.
2)Switch to a different FTP server (e.g. proftpd) until this is fixed in pure-
ftpd.


Regards,
Buchan