From: Emmanuel Fuste Date: Wed, 8 Feb 2017 19:12:00 +0000 (+1300) Subject: digest_ldap_auth: Add -r option to clamp the realm to a fixed value X-Git-Tag: M-staged-PR71~277 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=46e791c629e44630fe6e1df32bb0d73f10b1299d;p=thirdparty%2Fsquid.git digest_ldap_auth: Add -r option to clamp the realm to a fixed value Some historic Digest Auth implementations do not include the realm in the digest password attribute. The password is effectively stored as "HA1" instead of "REALM:HA1". The realm cannot simply be ignored due to: 1) the realm is both the salting value used within the hash and the scope limitation on what inputs from HTTP are used to compare against the A1, and 2) Squid does not itself verify the realm received was the one offered and leaves the comparison to the backend system. There is some possibility the authentication system is using multiple security realms and Squids realm string is just an offer. Not having realm tied to the credentials in the backend storage leaves this particular helper with no other option but to trust the realm sent (probably) over clear-text by any client/attacker actually matches the salting. That allows remote senders to manipulate the realm string they send to perform a collision attack against the stored password. They no longer have to find and prove knowledge of the password. But just find a collision for its hash vs arbitrary realm strings. Old Digest systems are not the safest things to begin with. They also tend to use MD5 hashing which was the only one available for many years and relatively easy to find collisions for. To resolve all these problems allow the -l parameter to accept an empty string ('-l "" ') when the -r option provides a fixed realm. Also, fix several typos in the help text. --- diff --git a/src/auth/digest/LDAP/ldap_backend.cc b/src/auth/digest/LDAP/ldap_backend.cc index dc0256fa1e..7f167e5567 100644 --- a/src/auth/digest/LDAP/ldap_backend.cc +++ b/src/auth/digest/LDAP/ldap_backend.cc @@ -63,6 +63,7 @@ static const char *usersearchfilter = NULL; static const char *binddn = NULL; static const char *bindpasswd = NULL; static const char *delimiter = ":"; +static const char *frealm = ""; static int encrpass = 0; static int searchscope = LDAP_SCOPE_SUBTREE; static int persistent = 0; @@ -267,7 +268,7 @@ retrydnattr: } value = values; while (*value) { - if (encrpass) { + if (encrpass && *delimiter ) { const char *t = strtok(*value, delimiter); if (t && strcmp(t, realm) == 0) { password = strtok(NULL, delimiter); @@ -451,6 +452,9 @@ LDAPArguments(int argc, char **argv) case 'l': delimiter = value; break; + case 'r': + frealm = value; + break; case 'b': userbasedn = value; break; @@ -574,10 +578,11 @@ LDAPArguments(int argc, char **argv) if (!ldapServer) ldapServer = (char *) "localhost"; - if (!userbasedn || !passattr) { - fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn -f filter [options] ldap_server_name\n\n"); + if (!userbasedn || !passattr || (!*delimiter && !*frealm)) { + fprintf(stderr, "Usage: " PROGRAM_NAME " -b basedn -F filter [options] ldap_server_name\n\n"); fprintf(stderr, "\t-A password attribute(REQUIRED)\t\tUser attribute that contains the password\n"); - fprintf(stderr, "\t-l password realm delimiter(REQUIRED)\tCharater(s) that devides the password attribute\n\t\t\t\t\t\tin realm and password tokens, default ':' realm:password\n"); + fprintf(stderr, "\t-l password realm delimiter(REQUIRED)\tCharacter(s) that divides the password attribute\n\t\t\t\t\t\tin realm and password tokens, default ':' realm:password, could be\n\t\t\t\t\t\tempty string if the password is alone in the password attribute\n"); + fprintf(stderr, "\t-r filtered realm\t\t\tonly honor Squid requests for this realm. Mandatory if the password is alone in\n\t\t\t\t\t\tthe password attribute, acting as the implicit realm\n"); fprintf(stderr, "\t-b basedn (REQUIRED)\t\t\tbase dn under where to search for users\n"); fprintf(stderr, "\t-e Encrypted passwords(REQUIRED)\tPassword are stored encrypted using HHA1\n"); fprintf(stderr, "\t-F filter\t\t\t\tuser search filter pattern. %%s = login\n"); @@ -644,9 +649,17 @@ readSecret(const char *filename) void LDAPHHA1(RequestData * requestData) { - char *password; + char *password = NULL; ldapconnect(); - password = getpassword(requestData->user, requestData->realm); + + // use the -l delimiter to find realm, or + // only honor the -r specified realm + const bool lookup = (!*frealm && *delimiter) || + (*frealm && strcmp(requestData->realm, frealm) != 0); + + if (lookup) + password = getpassword(requestData->user, requestData->realm); + if (password != NULL) { if (encrpass) xstrncpy(requestData->HHA1, password, sizeof(requestData->HHA1));