One of my peers at work noticed that mod_authnz_ldap returns a HTTP 500 code, when the users sents an empty password. After further investigation I noticed that this only happens in case the authentication to the LDAP server happens via AuthLDAPInitialBindAsUser / AuthLDAPInitialBindPattern and not via AuthLDAPBindDN / AuthLDAPBindPassword (in this case it correctly returns a HTTP 401 code).
I also found the following comment in line 1875 of modules/ldap/util_ldap.c: /* * A bind to the server with an empty password always succeeds, so * we check to ensure that the password is not empty. This implies * that users who actually do have empty passwords will never be * able to authenticate with this module. I don't see this as a big * problem. */ This causes the initial bind with the user credentials to succeed, but the following ldap_search_ext_s to fail with "Operations error". Hence I would propose the following two patches: 1. Do not allow to set an empty bind password via AuthLDAPBindPassword (no_empty_bind_password.diff). 2. In authn_ldap_check_password move the checks for NULL user / password up (IMHO we cannot do anything sensible in case they are NULL) in addition check if the password is empty and return an AUTH_DENIED if this is the case. This would be similar to the behavior in case AuthLDAPBindDN / AuthLDAPBindPassword is used (no_empty_password_check.diff). Opinions? Regards RĂ¼diger
Index: modules/aaa/mod_authnz_ldap.c =================================================================== --- modules/aaa/mod_authnz_ldap.c (revision 1885229) +++ modules/aaa/mod_authnz_ldap.c (working copy) @@ -1719,6 +1719,10 @@ sec->bindpw = (char *)arg; } + if (!(*sec->bindpw)) { + return "Empty passwords are invalid for AuthLDAPBindPassword"; + } + return NULL; }
Index: modules/aaa/mod_authnz_ldap.c =================================================================== --- modules/aaa/mod_authnz_ldap.c (revision 1885229) +++ modules/aaa/mod_authnz_ldap.c (working copy) @@ -539,6 +539,32 @@ return AUTH_GENERAL_ERROR; } + /* Get the password that the client sent */ + if (password == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01692) + "auth_ldap authenticate: no password specified"); + return AUTH_GENERAL_ERROR; + } + + if (user == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01693) + "auth_ldap authenticate: no user specified"); + return AUTH_GENERAL_ERROR; + } + + /* + * A bind to the server with an empty password always succeeds, so + * we check to ensure that the password is not empty. This implies + * that users who actually do have empty passwords will never be + * able to authenticate with this module. I don't see this as a big + * problem. + */ + if (!(*password)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO() + "auth_ldap authenticate: empty password specified"); + return AUTH_DENIED; + } + /* There is a good AuthLDAPURL, right? */ if (sec->host) { const char *binddn = sec->binddn; @@ -562,21 +588,6 @@ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01691) "auth_ldap authenticate: using URL %s", sec->url); - /* Get the password that the client sent */ - if (password == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01692) - "auth_ldap authenticate: no password specified"); - release_ldc(r, ldc); - return AUTH_GENERAL_ERROR; - } - - if (user == NULL) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01693) - "auth_ldap authenticate: no user specified"); - release_ldc(r, ldc); - return AUTH_GENERAL_ERROR; - } - /* build the username filter */ if (APR_SUCCESS != authn_ldap_build_filter(filtbuf, r, user, NULL, sec)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02622)