[dovecot-cvs] dovecot/src/auth db-ldap.c, 1.41.2.7, 1.41.2.8 db-ldap.h, 1.20.2.4, 1.20.2.5 passdb-ldap.c, 1.44.2.3, 1.44.2.4 userdb-ldap.c, 1.40, 1.40.2.1

tss at dovecot.org tss at dovecot.org
Sat Nov 4 15:00:31 UTC 2006


Update of /var/lib/cvs/dovecot/src/auth
In directory talvi:/tmp/cvs-serv21169/src/auth

Modified Files:
      Tag: branch_1_0
	db-ldap.c db-ldap.h passdb-ldap.c userdb-ldap.c 
Log Message:
LDAP code changes: If auth binds are used, bind back to the default dn
before doing a search. Otherwise it could fail if user gave an invalid
password. Initial binding is now also done asynchronously. Reconnecting to
LDAP server wasn't working with auth binds. Use pass_attrs even with
auth_bind=yes since it may contain other non-password fields also. Updated
dovecot-ldap.conf to contain sasl_bind settings and reflect these changes.



Index: db-ldap.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/db-ldap.c,v
retrieving revision 1.41.2.7
retrieving revision 1.41.2.8
diff -u -d -r1.41.2.7 -r1.41.2.8
--- db-ldap.c	22 Sep 2006 13:26:44 -0000	1.41.2.7
+++ db-ldap.c	4 Nov 2006 15:00:28 -0000	1.41.2.8
@@ -52,7 +52,6 @@
 	DEF(SET_STR, sasl_mech),
 	DEF(SET_STR, sasl_realm),
 	DEF(SET_STR, sasl_authz_id),
-	DEF(SET_STR, sasl_props),
 	DEF(SET_STR, deref),
 	DEF(SET_STR, scope),
 	DEF(SET_STR, base),
@@ -80,7 +79,6 @@
 	MEMBER(sasl_mech) NULL,
 	MEMBER(sasl_realm) NULL,
 	MEMBER(sasl_authz_id) NULL,
-	MEMBER(sasl_props) NULL,
 	MEMBER(deref) "never",
 	MEMBER(scope) "subtree",
 	MEMBER(base) NULL,
@@ -96,6 +94,7 @@
 
 static struct ldap_connection *ldap_connections = NULL;
 
+static int db_ldap_bind(struct ldap_connection *conn);
 static void ldap_conn_close(struct ldap_connection *conn, bool flush_requests);
 
 static int deref2str(const char *str)
@@ -143,8 +142,17 @@
 {
 	int msgid;
 
-	if (!conn->connected) {
-		if (!db_ldap_connect(conn)) {
+	if (!conn->connected && !conn->connecting) {
+		if (db_ldap_connect(conn) < 0) {
+			request->callback(conn, request, NULL);
+			return;
+		}
+	}
+
+	if (conn->last_auth_bind) {
+		/* switch back to the default dn before doing the search
+		   request. */
+		if (db_ldap_bind(conn) < 0) {
 			request->callback(conn, request, NULL);
 			return;
 		}
@@ -167,6 +175,7 @@
 	struct hash_table *old_requests;
         struct hash_iterate_context *iter;
 	void *key, *value;
+	bool have_binds = FALSE;
 
 	i_assert(conn->connected);
 
@@ -176,22 +185,45 @@
 	old_requests = conn->requests;
 	conn->requests = hash_create(default_pool, conn->pool, 0, NULL, NULL);
 
+	conn->retrying = TRUE;
+	/* first retry all the search requests */
 	iter = hash_iterate_init(old_requests);
 	while (hash_iterate(iter, &key, &value)) {
 		struct ldap_request *request = value;
 
-		i_assert(conn->connected);
-		db_ldap_search(conn, request, conn->set.ldap_scope);
+		if (request->filter == NULL) {
+			/* bind request */
+			have_binds = TRUE;
+		} else {
+			i_assert(conn->connected);
+			db_ldap_search(conn, request, conn->set.ldap_scope);
+		}
 	}
 	hash_iterate_deinit(iter);
+
+	if (have_binds && conn->set.auth_bind) {
+		/* next retry all the bind requests. without auth binds the
+		   only bind request can be the initial connection binding,
+		   which we don't care to retry. */
+		iter = hash_iterate_init(old_requests);
+		while (hash_iterate(iter, &key, &value)) {
+			struct ldap_request *request = value;
+
+			if (request->filter == NULL)
+				request->callback(conn, request, NULL);
+		}
+		hash_iterate_deinit(iter);
+	}
 	hash_destroy(old_requests);
+
+	conn->retrying = FALSE;
 }
 
 static void ldap_conn_reconnect(struct ldap_connection *conn)
 {
 	ldap_conn_close(conn, FALSE);
 
-	if (!db_ldap_connect(conn)) {
+	if (db_ldap_connect(conn) < 0) {
 		/* failed to reconnect. fail all requests. */
 		ldap_conn_close(conn, TRUE);
 	}
@@ -275,12 +307,87 @@
 }
 #endif
 
-bool db_ldap_connect(struct ldap_connection *conn)
+static int db_ldap_connect_finish(struct ldap_connection *conn, int ret)
 {
-	int ret, fd;
+	if (ret == LDAP_SERVER_DOWN) {
+		i_error("LDAP: Can't connect to server: %s",
+			conn->set.uris != NULL ?
+			conn->set.uris : conn->set.hosts);
+		return -1;
+	}
+	if (ret != LDAP_SUCCESS) {
+		i_error("LDAP: binding failed (dn %s): %s",
+			conn->set.dn == NULL ? "(none)" : conn->set.dn,
+			ldap_get_error(conn));
+		return -1;
+	}
+
+	conn->connected = TRUE;
+
+	/* in case there are requests waiting, retry them */
+	ldap_conn_retry_requests(conn);
+	return 0;
+}
+
+static void db_ldap_bind_callback(struct ldap_connection *conn,
+				  struct ldap_request *ldap_request,
+				  LDAPMessage *res)
+{
+	int ret;
+
+	conn->connecting = FALSE;
+	i_free(ldap_request);
+
+	if (res == NULL) {
+		/* aborted */
+		return;
+	}
+
+	ret = ldap_parse_sasl_bind_result(conn->ld, res, NULL, FALSE);
+	if (ret != LDAP_SUCCESS) {
+		i_error("LDAP: ldap_parse_sasl_bind_result() failed: %s",
+			ldap_err2string(ret));
+		return;
+	}
+
+	ret = ldap_result2error(conn->ld, res, FALSE);
+	(void)db_ldap_connect_finish(conn, ret);
+}
+
+static int db_ldap_bind(struct ldap_connection *conn)
+{
+	struct ldap_request *ldap_request;
+	int msgid;
+
+	conn->connecting = TRUE;
+
+	ldap_request = i_new(struct ldap_request, 1);
+	ldap_request->callback = db_ldap_bind_callback;
+	ldap_request->context = conn;
+
+	msgid = ldap_bind(conn->ld, conn->set.dn, conn->set.
+			  dnpass, LDAP_AUTH_SIMPLE);
+	if (msgid == -1) {
+		i_error("ldap_bind(%s) failed: %s",
+			conn->set.dn, ldap_get_error(conn));
+		return -1;
+	}
+	hash_insert(conn->requests, POINTER_CAST(msgid), ldap_request);
+
+	/* we're binding back to the original DN, not doing an
+	   authentication bind */
+	conn->last_auth_bind = FALSE;
+	return 0;
+}
 
+int db_ldap_connect(struct ldap_connection *conn)
+{
+	unsigned int ldap_version;
+	int ret;
+
+	i_assert(!conn->connecting);
 	if (conn->connected)
-		return TRUE;
+		return 0;
 
 	if (conn->ld == NULL) {
 		if (conn->set.uris != NULL) {
@@ -299,19 +406,34 @@
 				conn->set.hosts);
 
 		ret = ldap_set_option(conn->ld, LDAP_OPT_DEREF,
-				      (void *) &conn->set.ldap_deref);
+				      (void *)&conn->set.ldap_deref);
 		if (ret != LDAP_SUCCESS) {
 			i_fatal("LDAP: Can't set deref option: %s",
 				ldap_err2string(ret));
 		}
 
+		/* If SASL binds are used, the protocol version needs to be
+		   at least 3 */
+		ldap_version = conn->set.sasl_bind &&
+			conn->set.ldap_version < 3 ? 3 :
+			conn->set.ldap_version;
 		ret = ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION,
-				      (void *) &conn->set.ldap_version);
+				      (void *)&ldap_version);
 		if (ret != LDAP_OPT_SUCCESS) {
 			i_fatal("LDAP: Can't set protocol version %u: %s",
-				conn->set.ldap_version, ldap_err2string(ret));
+				ldap_version, ldap_err2string(ret));
 		}
+
+		/* get the connection's fd */
+		ret = ldap_get_option(conn->ld, LDAP_OPT_DESC,
+				      (void *)&conn->fd);
+		if (ret != LDAP_SUCCESS) {
+			i_fatal("LDAP: Can't get connection fd: %s",
+				ldap_err2string(ret));
+		}
+		net_set_nonblock(conn->fd, TRUE);
 	}
+	i_assert(conn->fd != -1);
 
 	if (conn->set.tls) {
 #ifdef LDAP_HAVE_START_TLS_S
@@ -319,11 +441,11 @@
 		if (ret != LDAP_SUCCESS) {
 			i_error("LDAP: ldap_start_tls_s() failed: %s",
 				ldap_err2string(ret));
-			return FALSE;
+			return -1;
 		}
 #else
 		i_error("LDAP: Your LDAP library doesn't support TLS");
-		return FALSE;
+		return -1;
 #endif
 	}
 
@@ -345,38 +467,15 @@
 #else
 		i_fatal("LDAP: sasl_bind=yes but no SASL support compiled in");
 #endif
+		if (db_ldap_connect_finish(conn, ret) < 0)
+			return -1;
 	} else {
-		ret = ldap_simple_bind_s(conn->ld, conn->set.dn,
-					 conn->set.dnpass);
-	}
-	if (ret == LDAP_SERVER_DOWN) {
-		i_error("LDAP: Can't connect to server: %s",
-			conn->set.uris != NULL ?
-			conn->set.uris : conn->set.hosts);
-		return FALSE;
-	}
-	if (ret != LDAP_SUCCESS) {
-		i_error("LDAP: binding failed (dn %s): %s",
-			conn->set.dn == NULL ? "(none)" : conn->set.dn,
-			ldap_get_error(conn));
-		return FALSE;
-	}
-
-	conn->connected = TRUE;
-
-	/* register LDAP input to ioloop */
-	ret = ldap_get_option(conn->ld, LDAP_OPT_DESC, (void *) &fd);
-	if (ret != LDAP_SUCCESS) {
-		i_fatal("LDAP: Can't get connection fd: %s",
-			ldap_err2string(ret));
+		if (db_ldap_bind(conn) < 0)
+			return -1;
 	}
 
-	net_set_nonblock(fd, TRUE);
-	conn->io = io_add(fd, IO_READ, ldap_input, conn);
-
-	/* in case there are requests waiting, retry them */
-        ldap_conn_retry_requests(conn);
-	return TRUE;
+	conn->io = io_add(conn->fd, IO_READ, ldap_input, conn);
+	return 0;
 }
 
 static void ldap_conn_close(struct ldap_connection *conn, bool flush_requests)
@@ -404,15 +503,17 @@
 		ldap_unbind(conn->ld);
 		conn->ld = NULL;
 	}
+	conn->fd = -1;
 }
 
 void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
 		       char ***attr_names_r, struct hash_table *attr_map,
-		       const char *const default_attr_map[])
+		       const char *const default_attr_map[],
+		       const char *skip_attr)
 {
 	const char *const *attr;
 	char *name, *value, *p;
-	unsigned int i, size;
+	unsigned int i, j, size;
 
 	if (*attrlist == '\0')
 		return;
@@ -424,7 +525,7 @@
 	for (size = 0; attr[size] != NULL; size++) ;
 	*attr_names_r = p_new(conn->pool, char *, size + 1);
 
-	for (i = 0; i < size; i++) {
+	for (i = j = 0; i < size; i++) {
 		p = strchr(attr[i], '=');
 		if (p == NULL) {
 			name = p_strdup(conn->pool, attr[i]);
@@ -435,9 +536,13 @@
 			value = p_strdup(conn->pool, p + 1);
 		}
 
-		(*attr_names_r)[i] = name;
-		if (*name != '\0')
+		if (skip_attr != NULL && strcmp(skip_attr, value) == 0)
+			name = "";
+
+		if (*name != '\0') {
 			hash_insert(attr_map, name, value);
+			(*attr_names_r)[j++] = name;
+		}
 
 		if (*default_attr_map != NULL)
 			default_attr_map++;
@@ -516,6 +621,7 @@
 	conn->refcount = 1;
 	conn->requests = hash_create(default_pool, pool, 0, NULL, NULL);
 
+	conn->fd = -1;
 	conn->config_path = p_strdup(pool, config_path);
 	conn->set = default_ldap_settings;
 	if (!settings_read(config_path, NULL, parse_setting, NULL, conn))

Index: db-ldap.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/db-ldap.h,v
retrieving revision 1.20.2.4
retrieving revision 1.20.2.5
diff -u -d -r1.20.2.4 -r1.20.2.5
--- db-ldap.h	19 Jun 2006 16:10:04 -0000	1.20.2.4
+++ db-ldap.h	4 Nov 2006 15:00:28 -0000	1.20.2.5
@@ -56,6 +56,7 @@
         struct ldap_settings set;
 
 	LDAP *ld;
+	int fd; /* only set when ld is not NULL */
 	struct io *io;
 	struct hash_table *requests;
 
@@ -63,12 +64,16 @@
 	struct hash_table *pass_attr_map, *user_attr_map;
 
 	unsigned int connected:1;
+	unsigned int connecting:1;
+	unsigned int retrying:1; /* just reconnected, resending requests */
+	unsigned int last_auth_bind:1;
 };
 
 struct ldap_request {
 	db_search_callback_t *callback;
 	void *context;
 
+	/* for bind requests, base contains the DN and filter=NULL */
 	const char *base;
 	const char *filter;
 	char **attributes; /* points to pass_attr_names / user_attr_names */
@@ -86,12 +91,13 @@
 
 void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
 		       char ***attr_names_r, struct hash_table *attr_map,
-		       const char *const default_attr_map[]);
+		       const char *const default_attr_map[],
+		       const char *skip_attr);
 
 struct ldap_connection *db_ldap_init(const char *config_path);
 void db_ldap_unref(struct ldap_connection **conn);
 
-bool db_ldap_connect(struct ldap_connection *conn);
+int db_ldap_connect(struct ldap_connection *conn);
 
 const char *ldap_escape(const char *str,
 			const struct auth_request *auth_request);

Index: passdb-ldap.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/passdb-ldap.c,v
retrieving revision 1.44.2.3
retrieving revision 1.44.2.4
diff -u -d -r1.44.2.3 -r1.44.2.4
--- passdb-ldap.c	2 Nov 2006 21:19:43 -0000	1.44.2.3
+++ passdb-ldap.c	4 Nov 2006 15:00:28 -0000	1.44.2.4
@@ -34,84 +34,108 @@
 	} callback;
 };
 
+struct ldap_query_save_context {
+	struct ldap_connection *conn;
+	struct auth_request *auth_request;
+	LDAPMessage *entry;
+
+	string_t *debug;
+	unsigned int userdb_fields:1;
+	unsigned int add_userdb_uid:1;
+	unsigned int add_userdb_gid:1;
+};
+
 static void
-ldap_query_save_result(struct ldap_connection *conn, LDAPMessage *entry,
-		       struct auth_request *auth_request)
+ldap_query_save_attr(struct ldap_query_save_context *ctx, const char *attr)
 {
-	struct auth *auth = auth_request->auth;
-	BerElement *ber;
+	struct auth *auth = ctx->auth_request->auth;
 	const char *name;
-	char *attr, **vals;
+	char **vals;
 	unsigned int i;
-	string_t *debug = NULL;
-	bool userdb_fields = FALSE;
-	bool add_userdb_uid = FALSE, add_userdb_gid = FALSE;
 
-	attr = ldap_first_attribute(conn->ld, entry, &ber);
-	while (attr != NULL) {
-		name = hash_lookup(conn->pass_attr_map, attr);
-		vals = ldap_get_values(conn->ld, entry, attr);
+	name = hash_lookup(ctx->conn->pass_attr_map, attr);
 
-		if (auth->verbose_debug) {
-			if (debug == NULL)
-				debug = t_str_new(256);
-			else
-				str_append_c(debug, ' ');
-			str_append(debug, attr);
-			str_printfa(debug, "(%s)=",
-				    name != NULL ? name : "?unknown?");
-		}
+	if (auth->verbose_debug) {
+		if (ctx->debug == NULL)
+			ctx->debug = t_str_new(256);
+		else
+			str_append_c(ctx->debug, ' ');
+		str_append(ctx->debug, attr);
+		str_printfa(ctx->debug, "(%s)=",
+			    name != NULL ? name : "?unknown?");
+	}
 
-		if (strncmp(name, "userdb_", 7) == 0) {
-			/* in case we're trying to use prefetch userdb,
-			   see if we need to add global uid/gid */
-			if (!userdb_fields) {
-				add_userdb_uid = add_userdb_gid = TRUE;
-				userdb_fields = TRUE;
-			}
-			if (strcmp(name, "userdb_uid") == 0)
-				add_userdb_uid = FALSE;
-			else if (strcmp(name, "userdb_gid") == 0)
-				add_userdb_gid = FALSE;
+	if (name == NULL)
+		return;
+
+	if (strncmp(name, "userdb_", 7) == 0) {
+		/* in case we're trying to use prefetch userdb,
+		   see if we need to add global uid/gid */
+		if (!ctx->userdb_fields) {
+			ctx->add_userdb_uid = ctx->add_userdb_gid = TRUE;
+			ctx->userdb_fields = TRUE;
 		}
+		if (strcmp(name, "userdb_uid") == 0)
+			ctx->add_userdb_uid = FALSE;
+		else if (strcmp(name, "userdb_gid") == 0)
+			ctx->add_userdb_gid = FALSE;
+	}
 
-		if (name != NULL && vals != NULL && *name != '\0') {
-			for (i = 0; vals[i] != NULL; i++) {
-				if (debug != NULL) {
-					if (i != 0)
-						str_append_c(debug, '/');
-					if (auth->verbose_debug_passwords ||
-					    strcmp(name, "password") != 0)
-						str_append(debug, vals[i]);
-					else {
-						str_append(debug,
-							   PASSWORD_HIDDEN_STR);
-					}
+	vals = ldap_get_values(ctx->conn->ld, ctx->entry, attr);
+	if (vals != NULL && *name != '\0') {
+		for (i = 0; vals[i] != NULL; i++) {
+			if (ctx->debug != NULL) {
+				if (i != 0)
+					str_append_c(ctx->debug, '/');
+				if (auth->verbose_debug_passwords ||
+				    strcmp(name, "password") != 0)
+					str_append(ctx->debug, vals[i]);
+				else {
+					str_append(ctx->debug,
+						   PASSWORD_HIDDEN_STR);
 				}
-				auth_request_set_field(auth_request,
-						name, vals[i],
-						conn->set.default_pass_scheme);
 			}
+			auth_request_set_field(ctx->auth_request, name, vals[i],
+					ctx->conn->set.default_pass_scheme);
 		}
+	}
 
-		ldap_value_free(vals);
+	ldap_value_free(vals);
+}
+
+static void
+ldap_query_save_result(struct ldap_connection *conn, LDAPMessage *entry,
+		       struct auth_request *auth_request)
+{
+	struct ldap_query_save_context ctx;
+	BerElement *ber;
+	char *attr;
+
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.conn = conn;
+	ctx.auth_request = auth_request;
+	ctx.entry = entry;
+
+	attr = ldap_first_attribute(conn->ld, entry, &ber);
+	while (attr != NULL) {
+		ldap_query_save_attr(&ctx, attr);
 		ldap_memfree(attr);
 
 		attr = ldap_next_attribute(conn->ld, entry, ber);
 	}
 
-	if (add_userdb_uid && conn->set.uid != (uid_t)-1) {
+	if (ctx.add_userdb_uid && conn->set.uid != (uid_t)-1) {
 		auth_request_set_field(auth_request, "userdb_uid",
 				       dec2str(conn->set.uid), NULL);
 	}
-	if (add_userdb_gid && conn->set.gid != (gid_t)-1) {
+	if (ctx.add_userdb_gid && conn->set.gid != (gid_t)-1) {
 		auth_request_set_field(auth_request, "userdb_gid",
 				       dec2str(conn->set.gid), NULL);
 	}
 
-	if (debug != NULL) {
+	if (ctx.debug != NULL) {
 		auth_request_log_debug(auth_request, "ldap",
-				       "%s", str_c(debug));
+				       "%s", str_c(ctx.debug));
 	}
 }
 
@@ -218,13 +242,41 @@
 	auth_request_unref(&auth_request);
 }
 
+static void authbind_start(struct ldap_connection *conn,
+			   struct ldap_request *ldap_request)
+{
+	struct passdb_ldap_request *passdb_ldap_request =
+		(struct passdb_ldap_request *)ldap_request;
+	struct auth_request *auth_request = ldap_request->context;
+	int msgid;
+
+	/* switch back to the default dn before doing the next search request */
+	conn->last_auth_bind = TRUE;
+
+	/* the DN is kept in base variable, a bit ugly.. */
+	msgid = ldap_bind(conn->ld, ldap_request->base,
+			  auth_request->mech_password, LDAP_AUTH_SIMPLE);
+	if (msgid == -1) {
+		i_error("ldap_bind(%s) failed: %s",
+			ldap_request->base, ldap_get_error(conn));
+		passdb_ldap_request->callback.
+			verify_plain(PASSDB_RESULT_INTERNAL_FAILURE,
+				     auth_request);
+		return;
+	}
+
+	/* Bind started */
+	auth_request_ref(auth_request);
+	hash_insert(conn->requests, POINTER_CAST(msgid), ldap_request);
+}
+
 static void
 handle_request_authbind(struct ldap_connection *conn,
-			struct ldap_request *request, LDAPMessage *res)
+			struct ldap_request *ldap_request, LDAPMessage *res)
 {
 	struct passdb_ldap_request *passdb_ldap_request =
-		(struct passdb_ldap_request *)request;
-	struct auth_request *auth_request = request->context;
+		(struct passdb_ldap_request *)ldap_request;
+	struct auth_request *auth_request = ldap_request->context;
 	enum passdb_result passdb_result;
 	int ret;
 
@@ -237,37 +289,20 @@
 		else if (ret == LDAP_INVALID_CREDENTIALS)
 			passdb_result = PASSDB_RESULT_PASSWORD_MISMATCH;
 		else {
-			auth_request_log_error(request->context, "ldap",
+			auth_request_log_error(auth_request, "ldap",
 					       "ldap_bind() failed: %s",
 					       ldap_err2string(ret));
 		}
 	}
 
-	passdb_ldap_request->callback.verify_plain(passdb_result, auth_request);
-        auth_request_unref(&auth_request);
-}
-
-static void authbind_start(struct ldap_connection *conn,
-			   struct ldap_request *ldap_request, const char *dn)
-{
-	struct passdb_ldap_request *passdb_ldap_request =
-		(struct passdb_ldap_request *)ldap_request;
-	struct auth_request *auth_request = ldap_request->context;
-	int msgid;
-
-	msgid = ldap_bind(conn->ld, dn, auth_request->mech_password,
-			  LDAP_AUTH_SIMPLE);
-	if (msgid == -1) {
-		i_error("ldap_bind(%s) failed: %s", dn, ldap_get_error(conn));
+	if (conn->retrying && res == NULL) {
+		/* reconnected, retry binding */
+		authbind_start(conn, ldap_request);
+	} else {
 		passdb_ldap_request->callback.
-			verify_plain(PASSDB_RESULT_INTERNAL_FAILURE,
-				     auth_request);
-		return;
+			verify_plain(passdb_result, auth_request);
 	}
-
-	/* Bind started */
-	auth_request_ref(auth_request);
-	hash_insert(conn->requests, POINTER_CAST(msgid), ldap_request);
+        auth_request_unref(&auth_request);
 }
 
 static void
@@ -285,10 +320,15 @@
 	if (entry == NULL)
 		return;
 
+	ldap_query_save_result(conn, entry, auth_request);
+
 	/* switch the handler to the authenticated bind handler */
+	ldap_request->base =
+		p_strdup(auth_request->pool, ldap_get_dn(conn->ld, entry));
+	ldap_request->filter = NULL;
 	ldap_request->callback = handle_request_authbind;
 
-        authbind_start(conn, ldap_request, ldap_get_dn(conn->ld, entry));
+        authbind_start(conn, ldap_request);
 	auth_request_unref(&auth_request);
 }
 
@@ -345,7 +385,8 @@
 	ldap_request->callback = handle_request_authbind;
 	ldap_request->context = auth_request;
 
-        authbind_start(conn, ldap_request, str_c(dn));
+	ldap_request->base = p_strdup(auth_request->pool, str_c(dn));
+        authbind_start(conn, ldap_request);
 }
 
 static void
@@ -369,9 +410,10 @@
 	var_expand(str, conn->set.pass_filter, vars);
 	ldap_request->filter = p_strdup(auth_request->pool, str_c(str));
 
-	/* we don't want any attributes in our search results;
-	   we only need the DN. */
-	ldap_request->attributes = p_new(auth_request->pool, char *, 1);
+	/* we don't need the attributes to perform authentication, but they
+	   may contain some extra parameters. if a password is returned,
+	   it's just ignored. */
+	ldap_request->attributes = conn->pass_attr_names;
 
 	auth_request_ref(auth_request);
 	ldap_request->context = auth_request;
@@ -395,6 +437,15 @@
 	struct ldap_connection *conn = module->conn;
 	struct passdb_ldap_request *ldap_request;
 
+	/* reconnect if needed. this is also done by db_ldap_search(), but
+	   with auth binds we'll have to do it ourself */
+	if (!conn->connected && !conn->connecting) {
+		if (db_ldap_connect(conn)< 0) {
+			callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
+			return;
+		}
+	}
+
 	ldap_request = p_new(request->pool, struct passdb_ldap_request, 1);
 	ldap_request->callback.verify_plain = callback;
 
@@ -429,8 +480,11 @@
 		hash_create(default_pool, conn->pool, 0, str_hash,
 			    (hash_cmp_callback_t *)strcmp);
 
+	if (conn->set.auth_bind_userdn != NULL)
+		conn->set.auth_bind = TRUE;
 	db_ldap_set_attrs(conn, conn->set.pass_attrs, &conn->pass_attr_names,
-			  conn->pass_attr_map, default_attr_map);
+			  conn->pass_attr_map, default_attr_map,
+			  conn->set.auth_bind ? "password" : NULL);
 	module->module.cache_key =
 		auth_cache_parse_key(auth_passdb->auth->pool,
 				     conn->set.pass_filter);

Index: userdb-ldap.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/auth/userdb-ldap.c,v
retrieving revision 1.40
retrieving revision 1.40.2.1
diff -u -d -r1.40 -r1.40.2.1
--- userdb-ldap.c	14 Feb 2006 17:43:04 -0000	1.40
+++ userdb-ldap.c	4 Nov 2006 15:00:28 -0000	1.40.2.1
@@ -219,7 +219,7 @@
 			    (hash_cmp_callback_t *)strcmp);
 
 	db_ldap_set_attrs(conn, conn->set.user_attrs, &conn->user_attr_names,
-			  conn->user_attr_map, default_attr_map);
+			  conn->user_attr_map, default_attr_map, NULL);
 	return &module->module;
 }
 



More information about the dovecot-cvs mailing list