auth_bind with "()" in username not working
Hi all,
I have an AD testsetup with auth_bind setting
auth_bind_userdn = "spdev\\%Ln"
I created a testuser "claasc (test)" which works fine in all ldapfilters but not for the auth_bind.
the log shows everything correct just "invalid credentials"
mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: auth client connected (pid=12202) mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: client in: AUTH 1 PLAIN service=imap secured session=T6knVtc0wQB/AAAB lip=127.0.0.1 rip=127.0.0.1 lport=143 rport=39873 mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: client passdb out: CONT 1 mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: client in: CONT<hidden> mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: passwd-file(claasc (test),127.0.0.1,<T6knVtc0wQB/AAAB>): cache miss mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: passwd-file(claasc (test),127.0.0.1,<T6knVtc0wQB/AAAB>): lookup: user=claasc (test) file=/etc/dovecot/passwd.postmaster mail.info: Jun 9 14:12:31 dovecot: auth: passwd-file(claasc (test),127.0.0.1,<T6knVtc0wQB/AAAB>): unknown user (given password: HubertHans99) mail.debug: Jun 9 14:12:31 dovecot: auth: Debug: ldap(claasc (test),127.0.0.1,<T6knVtc0wQB/AAAB>): cache miss mail.info: Jun 9 14:12:31 dovecot: auth: ldap(claasc (test),127.0.0.1,<T6knVtc0wQB/AAAB>): invalid credentials mail.debug: Jun 9 14:12:33 dovecot: auth: Debug: client passdb out: FAIL 1 user=claasc (test) mail.info: Jun 9 14:12:33 dovecot: imap-login: Aborted login (auth failed, 1 attempts in 2 secs): user=<claasc (test)>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, secured, session=<T6knVtc0wQB/AAAB>
So I guess its just a bind problem.
strace output from auth process of imap login:
write(26, "0-\2\1\4`(\2\1\3\4\25spdev\\claasc \\(test\\)\200\fHubertHans99", 47) = 47
the additional \\ in front of the brackets look strange to me and might be the reason.
tested Version is 2.2.18
Greetz Matze
Hi again,
did some more tseting on this.
I think the problem is the ldap userlookup, where "("s are evil and have to be quoted, but these quotes should be removed for the bind request.
I get my usernames from ldap with a filter like this
user_filter = (sAMAccountName=%Ln)
so I think in between this to steps is the problem.
For testing I hard coded the username for auth_bind and compared strace output from the auth process
auth_bind_userdn = "spdev\\claasc (test)"
this works fine. strace output from imap login
write(26, "0+\2\1\2`&\2\1\3\4\23spdev\\claasc (test)\200\fHubertHans99", 45)
compared to
auth_bind_userdn = "spdev\\%Ln"
which gives
write(26, "0-\2\1\2`(\2\1\3\4\25spdev\\claasc \\(test\\)\200\fHubertHans99", 47)
and wrong credentials
nobody else encountering similar problems? maybe the "()" are the only chars making problems at this point
Greetz Matze
Hi guys, I had a look in the sources about this problem. the problem seems to be the ldap_escape function that is called from ldap_verify_plain_auth_bind_userdn(..) I dont really know if this escaping is needed at this point, but with this change it works for me. No other problems discovered so far. could somebody, who is deeper in the sources give me a hint if this will make some troubles? Patch for 2.2.16: diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index c1c2544..10bfe20 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -367,7 +367,7 @@ ldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request, brequest->request.type = LDAP_REQUEST_TYPE_BIND; - vars = auth_request_get_var_expand_table(auth_request, ldap_escape); + vars = auth_request_get_var_expand_table(auth_request, NULL); dn = t_str_new(512); var_expand(dn, conn->set.auth_bind_userdn, vars);
Hi once again, replying to myself I think I tracked down the problem with a local openldap server. IMO the point is, you are using a ldap search escaping for a DN Request which needs another kind of escaping. the '(' worked well with my NULL-Patch because '(' is a char that needs escaping for a search filter but not for DN. I experienced some more problems with users containing a '+', '<' for example. so I googled a bit and found this one. http://www.openldap.org/lists/openldap-software/200407/msg00722.html So you might be missing (or I didnt find it) a special DN escaping function. I added one in the following patch and all the special chars seems to work find in the bind AND search requests. diff --git a/src/auth/db-ldap.c b/src/auth/db-ldap.c index 1476fa9..e9218ca 100644 --- a/src/auth/db-ldap.c +++ b/src/auth/db-ldap.c @@ -1423,6 +1422,35 @@ db_ldap_value_get_var_expand_table(struct auth_request *auth_request, return table; } + +#define IS_LDAPDN_ESCAPED_CHAR(c) \ + ((c) == '"' || (c) == '+' || (c) == ',' || (c) == '\\' || (c) == '<' || (c) == '>' || (c) == ';') + +const char *ldapdn_escape(const char *str, + const struct auth_request *auth_request ATTR_UNUSED) +{ + const char *p; + string_t *ret; + + for (p = str; *p != '\0'; p++) { + if (IS_LDAPDN_ESCAPED_CHAR(*p)) + break; + } + + if (*p == '\0') + return str; + + ret = t_str_new((size_t) (p - str) + 64); + str_append_n(ret, str, (size_t) (p - str)); + + for (; *p != '\0'; p++) { + if (IS_LDAPDN_ESCAPED_CHAR(*p)) + str_append_c(ret, '\\'); + str_append_c(ret, *p); + } + return str_c(ret); +} + #define IS_LDAP_ESCAPED_CHAR(c) \ ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\') diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index c1c2544..5629d85 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -367,7 +374,7 @@ ldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request, brequest->request.type = LDAP_REQUEST_TYPE_BIND; - vars = auth_request_get_var_expand_table(auth_request, ldap_escape); + vars = auth_request_get_var_expand_table(auth_request, ldapdn_escape); dn = t_str_new(512); var_expand(dn, conn->set.auth_bind_userdn, vars); an ldif file for testing. add them with # slapadd -l filename # cat user.ldif dn: dc=uma,dc=local dc: uma objectClass: dcObject objectClass: domain structuralObjectClass: domain entryUUID: 5cdda309-7ad5-4b03-b981-784c1b7ec27e creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231019Z entryCSN: 20160729231019.057480Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231019Z dn: ou=users,dc=uma,dc=local ou: users objectClass: organizationalUnit structuralObjectClass: organizationalUnit entryUUID: cc56753d-09aa-404a-8446-5d0bf75531a3 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231019Z entryCSN: 20160729231019.147739Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231019Z dn: uid=s\+schmidt,ou=users,dc=uma,dc=local givenName: Stefan uid: s+schmidt sn: Schmidt mail:: cy5zY2htaWR0QHR0dC1wb2ludC5sb2NhbA0= cn: Stefan Schmidt objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: fffad6fe-d083-4ab9-b6c2-da82067d510b creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.234641Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z dn: uid=m\\mueller,ou=users,dc=uma,dc=local givenName: Melanie uid: m\mueller sn: Mueller mail:: bS5tdWVsbGVyQHR0dC1wb2ludC5sb2NhbA0= cn: Melanie Mueller objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: 6e1a3a14-dd75-4766-a308-44a8437a0139 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.308360Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z dn: uid=k(lammer,ou=users,dc=uma,dc=local givenName: karl uid: k(lammer sn: klammer mail:: a0BzcGRldi5sb2NhbA0= cn: karl klammer objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: b5a26caf-62b1-4cf5-985c-3167424d90c7 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.315462Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z dn: uid=g\>ross,ou=users,dc=uma,dc=local givenName: v uid: g>ross sn: n mail:: Z0BzcGRldi5sb2NhbA0= cn: v n objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: fb7ad7cc-a028-444c-8109-cfe9dd182b0b creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.364040Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z dn: uid=mmeier,ou=users,dc=uma,dc=local givenName: Manfred uid: mmeier sn: Meier mail:: bS5tZWllckB0dHQtcG9pbnQubG9jYWwN cn: Manfred Meier objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: 16ef0511-25ed-4001-a1bd-1ad72abbfc02 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.369003Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z Greetz On Tue, 26 Jul 2016 13:07:24 +0200 Matthias Lay <matthias.lay@securepoint.de> wrote:
Hi guys,
I had a look in the sources about this problem.
the problem seems to be the ldap_escape function that is called from
ldap_verify_plain_auth_bind_userdn(..)
I dont really know if this escaping is needed at this point, but with this change it works for me. No other problems discovered so far.
could somebody, who is deeper in the sources give me a hint if this will make some troubles?
Patch for 2.2.16:
diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index c1c2544..10bfe20 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -367,7 +367,7 @@ ldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request, brequest->request.type = LDAP_REQUEST_TYPE_BIND;
- vars = auth_request_get_var_expand_table(auth_request, ldap_escape); + vars = auth_request_get_var_expand_table(auth_request, NULL); dn = t_str_new(512); var_expand(dn, conn->set.auth_bind_userdn, vars);
sorry forgot password for all test users is "insecure" and you´ll need the function in the header too diff --git a/src/auth/db-ldap.h b/src/auth/db-ldap.h index 8a51081..82ed1b3 100644 --- a/src/auth/db-ldap.h +++ b/src/auth/db-ldap.h @@ -197,6 +197,8 @@ void db_ldap_enable_input(struct ldap_connection *conn, bool enable); const char *ldap_escape(const char *str, const struct auth_request *auth_request); +const char *ldapdn_escape(const char *str, + const struct auth_request *auth_request); const char *ldap_get_error(struct ldap_connection *conn); struct db_ldap_result_iterate_context * On Tue, 2 Aug 2016 14:32:48 +0200 Matthias Lay <matthias.lay@securepoint.de> wrote:
Hi once again, replying to myself
I think I tracked down the problem with a local openldap server.
IMO the point is, you are using a ldap search escaping for a DN Request which needs another kind of escaping. the '(' worked well with my NULL-Patch because '(' is a char that needs escaping for a search filter but not for DN.
I experienced some more problems with users containing a '+', '<' for example. so I googled a bit and found this one.
http://www.openldap.org/lists/openldap-software/200407/msg00722.html
So you might be missing (or I didnt find it) a special DN escaping function. I added one in the following patch and all the special chars seems to work find in the bind AND search requests.
diff --git a/src/auth/db-ldap.c b/src/auth/db-ldap.c index 1476fa9..e9218ca 100644 --- a/src/auth/db-ldap.c +++ b/src/auth/db-ldap.c @@ -1423,6 +1422,35 @@ db_ldap_value_get_var_expand_table(struct auth_request *auth_request, return table; }
+ +#define IS_LDAPDN_ESCAPED_CHAR(c) \ + ((c) == '"' || (c) == '+' || (c) == ',' || (c) == '\\' || (c) == '<' || (c) == '>' || (c) == ';') + +const char *ldapdn_escape(const char *str, + const struct auth_request *auth_request ATTR_UNUSED) +{ + const char *p; + string_t *ret; + + for (p = str; *p != '\0'; p++) { + if (IS_LDAPDN_ESCAPED_CHAR(*p)) + break; + } + + if (*p == '\0') + return str; + + ret = t_str_new((size_t) (p - str) + 64); + str_append_n(ret, str, (size_t) (p - str)); + + for (; *p != '\0'; p++) { + if (IS_LDAPDN_ESCAPED_CHAR(*p)) + str_append_c(ret, '\\'); + str_append_c(ret, *p); + } + return str_c(ret); +} + #define IS_LDAP_ESCAPED_CHAR(c) \ ((c) == '*' || (c) == '(' || (c) == ')' || (c) == '\\')
diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index c1c2544..5629d85 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -367,7 +374,7 @@ ldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request, brequest->request.type = LDAP_REQUEST_TYPE_BIND;
- vars = auth_request_get_var_expand_table(auth_request, ldap_escape); + vars = auth_request_get_var_expand_table(auth_request, ldapdn_escape); dn = t_str_new(512); var_expand(dn, conn->set.auth_bind_userdn, vars);
an ldif file for testing. add them with # slapadd -l filename
# cat user.ldif dn: dc=uma,dc=local dc: uma objectClass: dcObject objectClass: domain structuralObjectClass: domain entryUUID: 5cdda309-7ad5-4b03-b981-784c1b7ec27e creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231019Z entryCSN: 20160729231019.057480Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231019Z
dn: ou=users,dc=uma,dc=local ou: users objectClass: organizationalUnit structuralObjectClass: organizationalUnit entryUUID: cc56753d-09aa-404a-8446-5d0bf75531a3 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231019Z entryCSN: 20160729231019.147739Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231019Z
dn: uid=s\+schmidt,ou=users,dc=uma,dc=local givenName: Stefan uid: s+schmidt sn: Schmidt mail:: cy5zY2htaWR0QHR0dC1wb2ludC5sb2NhbA0= cn: Stefan Schmidt objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: fffad6fe-d083-4ab9-b6c2-da82067d510b creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.234641Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z
dn: uid=m\\mueller,ou=users,dc=uma,dc=local givenName: Melanie uid: m\mueller sn: Mueller mail:: bS5tdWVsbGVyQHR0dC1wb2ludC5sb2NhbA0= cn: Melanie Mueller objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: 6e1a3a14-dd75-4766-a308-44a8437a0139 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.308360Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z
dn: uid=k(lammer,ou=users,dc=uma,dc=local givenName: karl uid: k(lammer sn: klammer mail:: a0BzcGRldi5sb2NhbA0= cn: karl klammer objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: b5a26caf-62b1-4cf5-985c-3167424d90c7 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.315462Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z
dn: uid=g\>ross,ou=users,dc=uma,dc=local givenName: v uid: g>ross sn: n mail:: Z0BzcGRldi5sb2NhbA0= cn: v n objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: fb7ad7cc-a028-444c-8109-cfe9dd182b0b creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.364040Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z
dn: uid=mmeier,ou=users,dc=uma,dc=local givenName: Manfred uid: mmeier sn: Meier mail:: bS5tZWllckB0dHQtcG9pbnQubG9jYWwN cn: Manfred Meier objectClass: person objectClass: inetOrgPerson userPassword:: aW5zZWN1cmU= structuralObjectClass: inetOrgPerson entryUUID: 16ef0511-25ed-4001-a1bd-1ad72abbfc02 creatorsName: cn=admin,dc=uma,dc=local createTimestamp: 20160729231039Z entryCSN: 20160729231039.369003Z#000000#000#000000 modifiersName: cn=admin,dc=uma,dc=local modifyTimestamp: 20160729231039Z
Greetz
On Tue, 26 Jul 2016 13:07:24 +0200 Matthias Lay <matthias.lay@securepoint.de> wrote:
Hi guys,
I had a look in the sources about this problem.
the problem seems to be the ldap_escape function that is called from
ldap_verify_plain_auth_bind_userdn(..)
I dont really know if this escaping is needed at this point, but with this change it works for me. No other problems discovered so far.
could somebody, who is deeper in the sources give me a hint if this will make some troubles?
Patch for 2.2.16:
diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c index c1c2544..10bfe20 100644 --- a/src/auth/passdb-ldap.c +++ b/src/auth/passdb-ldap.c @@ -367,7 +367,7 @@ ldap_verify_plain_auth_bind_userdn(struct auth_request *auth_request, brequest->request.type = LDAP_REQUEST_TYPE_BIND;
- vars = auth_request_get_var_expand_table(auth_request, ldap_escape); + vars = auth_request_get_var_expand_table(auth_request, NULL); dn = t_str_new(512); var_expand(dn, conn->set.auth_bind_userdn, vars);
-- Mit freundlichem Gruß / Best regards, Matthias Lay Head of UMA development Securepoint GmbH Salzstrasse 1 D-21335 Lüneburg https://www.securepoint.de Tel.: +49(0)413124010 Fax: +49(0)4131240118 Geschäftsführer: Lutz Hausmann, Claudia Hausmann Amtsgericht Lüneburg HRB 1776 USt.-ID-Nr.: DE 188 528 597
participants (1)
-
Matthias Lay