]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
passdb ldap added. fixes to userdb ldap.
authorTimo Sirainen <tss@iki.fi>
Tue, 11 Feb 2003 09:55:58 +0000 (11:55 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 11 Feb 2003 09:55:58 +0000 (11:55 +0200)
--HG--
branch : HEAD

src/auth/Makefile.am
src/auth/db-ldap.c
src/auth/db-ldap.h
src/auth/passdb-ldap.c [new file with mode: 0644]
src/auth/passdb.c
src/auth/passdb.h
src/auth/userdb-ldap.c

index f659ac24209206f9f23490420db7575f57352633..a9dd81482e3f067d94be996ced1542fc3f93f5f0 100644 (file)
@@ -26,6 +26,7 @@ dovecot_auth_SOURCES = \
        mech-digest-md5.c \
        mycrypt.c \
        passdb.c \
+       passdb-ldap.c \
        passdb-passwd.c \
        passdb-passwd-file.c \
        passdb-pam.c \
index da5c6f96d6b5104081f5bb77985bb46fd1e5420b..c99ddc2b3f20fbd8754d6de7c69b21695c63c50c 100644 (file)
@@ -27,6 +27,7 @@ static struct setting_def setting_defs[] = {
        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 @@ struct ldap_settings default_ldap_settings = {
        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 @@ static int deref2str(const char *str)
        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 @@ struct ldap_connection *db_ldap_init(const char *config_path)
        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;
index 490d3b7aa41db3a1963b5db4c54be8a39b5dfb1a..8f6470907f4867da81d2ca04a5199bc0288b3109 100644 (file)
@@ -15,11 +15,12 @@ struct ldap_settings {
        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 {
diff --git a/src/auth/passdb-ldap.c b/src/auth/passdb-ldap.c
new file mode 100644 (file)
index 0000000..58d9230
--- /dev/null
@@ -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
index 911b23692cb0b843366c82b25ef57830252df522..f74d401ced67417578d7671c6a9cdfd08501e76b 100644 (file)
@@ -11,8 +11,12 @@ struct passdb_module *passdb;
 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 @@ void passdb_init(void)
        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);
index 3d3256bcc760c2ff5cd3052ce608e0f799476e0a..745a100a79edddd2e25e1c2d4f8e245fc1c298a9 100644 (file)
@@ -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_shadow;
 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);
index e375d39fa60e2d7e579a9bf11e1f410939cdb22c..d733a04f4f49f3f9fd2cb2d94b09470ad2b1b7e5 100644 (file)
@@ -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 @@ static void handle_request(struct ldap_connection *conn,
        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 @@ static void handle_request(struct ldap_connection *conn,
                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 @@ static void userdb_ldap_lookup(const char *user, const char *realm,
        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 @@ static void userdb_ldap_lookup(const char *user, const char *realm,
                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 @@ static void userdb_ldap_lookup(const char *user, const char *realm,
        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);
 }