Mercurial > dovecot > original-hg > dovecot-1.2
changeset 1135:81930fff13cf HEAD
passdb ldap added. fixes to userdb ldap.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 11 Feb 2003 11:55:58 +0200 |
parents | bd3dabaa598e |
children | ad6343bd4479 |
files | src/auth/Makefile.am src/auth/db-ldap.c src/auth/db-ldap.h src/auth/passdb-ldap.c src/auth/passdb.c src/auth/passdb.h src/auth/userdb-ldap.c |
diffstat | 7 files changed, 275 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/Makefile.am Mon Feb 10 09:56:23 2003 +0200 +++ b/src/auth/Makefile.am Tue Feb 11 11:55:58 2003 +0200 @@ -26,6 +26,7 @@ mech-digest-md5.c \ mycrypt.c \ passdb.c \ + passdb-ldap.c \ passdb-passwd.c \ passdb-passwd-file.c \ passdb-pam.c \
--- a/src/auth/db-ldap.c Mon Feb 10 09:56:23 2003 +0200 +++ b/src/auth/db-ldap.c Tue Feb 11 11:55:58 2003 +0200 @@ -27,6 +27,7 @@ DEF(SET_STR, dn), DEF(SET_STR, dnpass), DEF(SET_STR, deref), + DEF(SET_STR, scope), DEF(SET_STR, base), DEF(SET_STR, attrs), DEF(SET_STR, filter) @@ -37,6 +38,7 @@ MEMBER(dn) NULL, MEMBER(dnpass) NULL, MEMBER(deref) "never", + MEMBER(scope) "subtree", MEMBER(base) NULL, MEMBER(attrs) NULL, MEMBER(filter) NULL @@ -58,6 +60,18 @@ i_fatal("LDAP: Unknown deref option '%s'", str); } +static int scope2str(const char *str) +{ + if (strcasecmp(str, "base") == 0) + return LDAP_SCOPE_BASE; + if (strcasecmp(str, "onelevel") == 0) + return LDAP_SCOPE_ONELEVEL; + if (strcasecmp(str, "subtree") == 0) + return LDAP_SCOPE_SUBTREE; + + i_fatal("LDAP: Unknown scope option '%s'", str); +} + static const char *get_ldap_error(struct ldap_connection *conn) { int ret, err; @@ -251,14 +265,11 @@ conn->set = default_ldap_settings; settings_read(config_path, parse_setting, conn); - /*if (conn->set.dnuser == NULL) - i_fatal("LDAP: No user given"); - if (conn->set.dnpass == NULL) - i_fatal("LDAP: No password given");*/ if (conn->set.base == NULL) i_fatal("LDAP: No base given"); conn->set.ldap_deref = deref2str(conn->set.deref); + conn->set.ldap_scope = scope2str(conn->set.scope); (void)ldap_conn_open(conn); return conn;
--- a/src/auth/db-ldap.h Mon Feb 10 09:56:23 2003 +0200 +++ b/src/auth/db-ldap.h Tue Feb 11 11:55:58 2003 +0200 @@ -15,11 +15,12 @@ const char *dn; const char *dnpass; const char *deref; + const char *scope; const char *base; const char *attrs; const char *filter; - int ldap_deref; + int ldap_deref, ldap_scope; }; struct ldap_connection {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/auth/passdb-ldap.c Tue Feb 11 11:55:58 2003 +0200 @@ -0,0 +1,234 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "config.h" +#undef HAVE_CONFIG_H + +#ifdef PASSDB_LDAP + +#include "common.h" +#include "str.h" +#include "var-expand.h" +#include "mycrypt.h" +#include "db-ldap.h" +#include "passdb.h" + +#include <ldap.h> +#include <stdlib.h> + +/* using posixAccount */ +#define DEFAULT_ATTRIBUTES "uid,userPassword" + +enum ldap_user_attr { + ATTR_VIRTUAL_USER = 0, + ATTR_PASSWORD, + + ATTR_COUNT +}; + +struct passdb_ldap_connection { + struct ldap_connection *conn; + + unsigned int *attrs; + char **attr_names; +}; + +struct passdb_ldap_request { + struct ldap_request request; + + enum passdb_credentials credentials; + union { + verify_plain_callback_t *verify_plain; + lookup_credentials_callback_t *lookup_credentials; + } callback; + + char password[1]; /* variable width */ +}; + +static struct passdb_ldap_connection *passdb_ldap_conn; + +static void handle_request(struct ldap_connection *conn, + struct ldap_request *request, LDAPMessage *res) +{ + struct passdb_ldap_request *ldap_request = + (struct passdb_ldap_request *) request; + struct auth_request *auth_request = request->context; + LDAPMessage *entry; + BerElement *ber; + char *attr, **vals; + const char *user, *password; + + if (auth_request->realm == NULL) + user = auth_request->user; + else { + user = t_strconcat(auth_request->user, "@", + auth_request->realm, NULL); + } + + password = NULL; + + entry = ldap_first_entry(conn->ld, res); + if (entry == NULL) + i_error("ldap(%s): unknown user", user); + else { + attr = ldap_first_attribute(conn->ld, entry, &ber); + while (attr != NULL) { + vals = ldap_get_values(conn->ld, entry, attr); + if (vals != NULL && vals[0] != NULL && + vals[1] == NULL) { + if (strcasecmp(attr, passdb_ldap_conn-> + attr_names[ATTR_PASSWORD]) == 0) + password = t_strdup(vals[0]); + } + ldap_value_free(vals); + ldap_memfree(attr); + + attr = ldap_next_attribute(conn->ld, entry, ber); + } + + if (password == NULL) + i_error("ldap(%s): No password in reply", user); + else if (ldap_next_entry(conn->ld, entry) != NULL) { + i_error("ldap(%s): Multiple password replies", user); + password = NULL; + } + } + + switch (ldap_request->credentials) { + case -1: + /* verify_plain */ + if (password == NULL) { + ldap_request->callback. + verify_plain(PASSDB_RESULT_USER_UNKNOWN, + auth_request); + break; + } + + if (strncasecmp(password, "{crypt}", 7) == 0) + password += 7; + + if (strcmp(mycrypt(password, ldap_request->password), + ldap_request->password) != 0) { + if (verbose) + i_info("ldap(%s): password mismatch", user); + ldap_request->callback. + verify_plain(PASSDB_RESULT_PASSWORD_MISMATCH, + auth_request); + } else { + ldap_request->callback.verify_plain(PASSDB_RESULT_OK, + auth_request); + } + break; + case PASSDB_CREDENTIALS_PLAINTEXT: + if (password != NULL && + strncasecmp(password, "{plain}", 7) == 0) + password += 7; + else + password = NULL; + + ldap_request->callback.lookup_credentials(password, + auth_request); + break; + case PASSDB_CREDENTIALS_CRYPT: + ldap_request->callback.lookup_credentials(password, + auth_request); + break; + case PASSDB_CREDENTIALS_DIGEST_MD5: + if (password != NULL && + strncasecmp(password, "{digest-md5}", 12) == 0) + password += 12; + else + password = NULL; + + ldap_request->callback.lookup_credentials(password, + auth_request); + break; + } +} + +static void ldap_lookup_pass(struct auth_request *auth_request, + struct ldap_request *ldap_request) +{ + struct ldap_connection *conn = passdb_ldap_conn->conn; + const char *user, *filter; + string_t *str; + + if (auth_request->realm == NULL) + user = auth_request->user; + else { + user = t_strconcat(auth_request->user, "@", + auth_request->realm, NULL); + } + + if (conn->set.filter == NULL) { + filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))", + passdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user); + } else { + str = t_str_new(512); + var_expand(str, conn->set.filter, user, NULL); + filter = str_c(str); + } + + ldap_request->callback = handle_request; + ldap_request->context = auth_request; + + db_ldap_search(conn, conn->set.base, conn->set.ldap_scope, + filter, passdb_ldap_conn->attr_names, + ldap_request); +} + +static void +ldap_verify_plain(struct auth_request *request, const char *password, + verify_plain_callback_t *callback) +{ + struct passdb_ldap_request *ldap_request; + + ldap_request = i_malloc(sizeof(struct passdb_ldap_request) + + strlen(password)); + ldap_request->credentials = -1; + ldap_request->callback.verify_plain = callback; + strcpy(ldap_request->password, password); + + ldap_lookup_pass(request, &ldap_request->request); +} + +static void ldap_lookup_credentials(struct auth_request *request, + enum passdb_credentials credentials, + lookup_credentials_callback_t *callback) +{ + struct passdb_ldap_request *ldap_request; + + ldap_request = i_new(struct passdb_ldap_request, 1); + ldap_request->credentials = credentials; + ldap_request->callback.lookup_credentials = callback; + + ldap_lookup_pass(request, &ldap_request->request); +} + +static void passdb_ldap_init(const char *args) +{ + struct ldap_connection *conn; + + passdb_ldap_conn = i_new(struct passdb_ldap_connection, 1); + passdb_ldap_conn->conn = conn = db_ldap_init(args); + + db_ldap_set_attrs(conn, conn->set.attrs ? + conn->set.attrs : DEFAULT_ATTRIBUTES, + &passdb_ldap_conn->attrs, + &passdb_ldap_conn->attr_names); +} + +static void passdb_ldap_deinit(void) +{ + db_ldap_unref(passdb_ldap_conn->conn); + i_free(passdb_ldap_conn); +} + +struct passdb_module passdb_ldap = { + passdb_ldap_init, + passdb_ldap_deinit, + + ldap_verify_plain, + ldap_lookup_credentials +}; + +#endif
--- a/src/auth/passdb.c Mon Feb 10 09:56:23 2003 +0200 +++ b/src/auth/passdb.c Tue Feb 11 11:55:58 2003 +0200 @@ -11,8 +11,12 @@ const char *passdb_credentials_to_str(enum passdb_credentials credentials) { switch (credentials) { + case _PASSDB_CREDENTIALS_INTERNAL: + break; case PASSDB_CREDENTIALS_PLAINTEXT: return "plaintext"; + case PASSDB_CREDENTIALS_CRYPT: + return "crypt"; case PASSDB_CREDENTIALS_DIGEST_MD5: return "digest-md5"; } @@ -53,6 +57,10 @@ if (strcasecmp(name, "vpopmail") == 0) passdb = &passdb_vpopmail; #endif +#ifdef USERDB_LDAP + if (strcasecmp(name, "ldap") == 0) + passdb = &passdb_ldap; +#endif if (passdb == NULL) i_fatal("Unknown passdb type '%s'", name);
--- a/src/auth/passdb.h Mon Feb 10 09:56:23 2003 +0200 +++ b/src/auth/passdb.h Tue Feb 11 11:55:58 2003 +0200 @@ -7,7 +7,10 @@ ((pass)[0] != '\0' && (pass)[0] != '*' && (pass)[0] != '!') enum passdb_credentials { + _PASSDB_CREDENTIALS_INTERNAL = -1, + PASSDB_CREDENTIALS_PLAINTEXT, + PASSDB_CREDENTIALS_CRYPT, PASSDB_CREDENTIALS_DIGEST_MD5 }; @@ -49,6 +52,7 @@ extern struct passdb_module passdb_passwd_file; extern struct passdb_module passdb_pam; extern struct passdb_module passdb_vpopmail; +extern struct passdb_module passdb_ldap; void passdb_init(void); void passdb_deinit(void);
--- a/src/auth/userdb-ldap.c Mon Feb 10 09:56:23 2003 +0200 +++ b/src/auth/userdb-ldap.c Tue Feb 11 11:55:58 2003 +0200 @@ -6,6 +6,8 @@ #ifdef USERDB_LDAP #include "common.h" +#include "str.h" +#include "var-expand.h" #include "db-ldap.h" #include "userdb.h" @@ -98,6 +100,7 @@ entry = ldap_first_entry(conn->ld, res); if (entry == NULL) { i_error("LDAP: ldap_first_entry failed()"); + urequest->userdb_callback(NULL, request->context); return; } @@ -115,9 +118,10 @@ attr = ldap_next_attribute(conn->ld, entry, ber); } - if (user.virtual_user == NULL) + if (user.virtual_user == NULL) { i_error("LDAP: No username in reply"); - else { + urequest->userdb_callback(NULL, request->context); + } else { if (ldap_next_entry(conn->ld, entry) != NULL) { i_error("LDAP: Multiple replies found for user %s", user.virtual_user); @@ -135,6 +139,7 @@ struct ldap_connection *conn = userdb_ldap_conn->conn; struct userdb_ldap_request *request; const char *filter; + string_t *str; if (realm != NULL) user = t_strconcat(user, "@", realm, NULL); @@ -143,8 +148,9 @@ filter = t_strdup_printf("(&(objectClass=posixAccount)(%s=%s))", userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user); } else { - filter = t_strdup_printf("(&%s(%s=%s))", conn->set.filter, - userdb_ldap_conn->attr_names[ATTR_VIRTUAL_USER], user); + str = t_str_new(512); + var_expand(str, conn->set.filter, user, NULL); + filter = str_c(str); } request = i_new(struct userdb_ldap_request, 1); @@ -152,7 +158,7 @@ request->request.context = context; request->userdb_callback = callback; - db_ldap_search(conn, conn->set.base, LDAP_SCOPE_SUBTREE, + db_ldap_search(conn, conn->set.base, conn->set.ldap_scope, filter, userdb_ldap_conn->attr_names, &request->request); }