changeset 7191:1cbaa724aba8 HEAD

Added support for OpenLDAP-specific TLS settings.
author Timo Sirainen <tss@iki.fi>
date Fri, 25 Jan 2008 14:25:11 +0200
parents b9a9c7257f4e
children 5b654defd376
files doc/dovecot-ldap-example.conf src/auth/db-ldap.c src/auth/db-ldap.h
diffstat 3 files changed, 110 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/doc/dovecot-ldap-example.conf	Fri Jan 25 13:45:36 2008 +0200
+++ b/doc/dovecot-ldap-example.conf	Fri Jan 25 14:25:11 2008 +0200
@@ -40,6 +40,14 @@
 
 # Use TLS to connect to the LDAP server.
 #tls = no
+# TLS options, currently supported only with OpenLDAP:
+#tls_ca_cert_file =
+#tls_ca_cert_dir =
+#tls_cert_file =
+#tls_key_file =
+#tls_cipher_suite =
+# Valid values: never, hard, demand, allow, try
+#tls_require_cert =
 
 # Use authentication binding for verifying password's validity. This works by
 # logging into LDAP server using the username and password given by client.
--- a/src/auth/db-ldap.c	Fri Jan 25 13:45:36 2008 +0200
+++ b/src/auth/db-ldap.c	Fri Jan 25 14:25:11 2008 +0200
@@ -26,6 +26,9 @@
 #else
 #  undef HAVE_LDAP_SASL
 #endif
+#ifdef LDAP_OPT_X_TLS
+#  define OPENLDAP_TLS_OPTIONS
+#endif
 #if SASL_VERSION_MAJOR < 2
 #  undef HAVE_LDAP_SASL
 #endif
@@ -84,6 +87,12 @@
 	DEF_STR(sasl_mech),
 	DEF_STR(sasl_realm),
 	DEF_STR(sasl_authz_id),
+	DEF_STR(tls_ca_cert_file),
+	DEF_STR(tls_ca_cert_dir),
+	DEF_STR(tls_cert_file),
+	DEF_STR(tls_key_file),
+	DEF_STR(tls_cipher_suite),
+	DEF_STR(tls_require_cert),
 	DEF_STR(deref),
 	DEF_STR(scope),
 	DEF_STR(base),
@@ -109,6 +118,12 @@
 	MEMBER(sasl_mech) NULL,
 	MEMBER(sasl_realm) NULL,
 	MEMBER(sasl_authz_id) NULL,
+	MEMBER(tls_ca_cert_file) NULL,
+	MEMBER(tls_ca_cert_dir) NULL,
+	MEMBER(tls_cert_file) NULL,
+	MEMBER(tls_key_file) NULL,
+	MEMBER(tls_cipher_suite) NULL,
+	MEMBER(tls_require_cert) NULL,
 	MEMBER(deref) "never",
 	MEMBER(scope) "subtree",
 	MEMBER(base) NULL,
@@ -151,6 +166,24 @@
 	i_fatal("LDAP: Unknown scope option '%s'", str);
 }
 
+#ifdef OPENLDAP_TLS_OPTIONS
+static int tls_require_cert2str(const char *str)
+{
+	if (strcasecmp(str, "never") == 0)
+		return LDAP_OPT_X_TLS_NEVER;
+	if (strcasecmp(str, "hard") == 0)
+		return LDAP_OPT_X_TLS_HARD;
+	if (strcasecmp(str, "demand") == 0)
+		return LDAP_OPT_X_TLS_DEMAND;
+	if (strcasecmp(str, "allow") == 0)
+		return LDAP_OPT_X_TLS_ALLOW;
+	if (strcasecmp(str, "try") == 0)
+		return LDAP_OPT_X_TLS_TRY;
+
+	i_fatal("LDAP: Unknown tls_require_cert value '%s'", str);
+}
+#endif
+
 static int ldap_get_errno(struct ldap_connection *conn)
 {
 	int ret, err;
@@ -621,9 +654,69 @@
 	net_set_nonblock(conn->fd, TRUE);
 }
 
+static void
+db_ldap_set_opt(struct ldap_connection *conn, int opt, const void *value,
+		const char *optname, const char *value_str)
+{
+	int ret;
+
+	ret = ldap_set_option(conn == NULL ? NULL : conn->ld, opt, value);
+	if (ret != LDAP_SUCCESS) {
+		i_fatal("LDAP: Can't set option %s to %s: %s",
+			optname, value_str, ldap_err2string(ret));
+	}
+}
+
+static void
+db_ldap_set_opt_str(struct ldap_connection *conn, int opt, const char *value,
+		    const char *optname)
+{
+	if (value != NULL)
+		db_ldap_set_opt(conn, opt, value, optname, value);
+}
+
+static void db_ldap_set_tls_options(struct ldap_connection *conn)
+{
+	if (!conn->set.tls)
+		return;
+
+#ifdef OPENLDAP_TLS_OPTIONS
+	db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTFILE,
+			    conn->set.tls_ca_cert_file, "tls_ca_cert_file");
+	db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CACERTDIR,
+			    conn->set.tls_ca_cert_dir, "tls_ca_cert_dir");
+	db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CERTFILE,
+			    conn->set.tls_cert_file, "tls_cert_file");
+	db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_KEYFILE,
+			    conn->set.tls_key_file, "tls_key_file");
+	db_ldap_set_opt_str(NULL, LDAP_OPT_X_TLS_CIPHER_SUITE,
+			    conn->set.tls_cipher_suite, "tls_cipher_suite");
+	if (conn->set.tls_require_cert != NULL) {
+		int value = tls_require_cert2str(conn->set.tls_require_cert);
+		db_ldap_set_opt(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &value,
+				"tls_require_cert", conn->set.tls_require_cert);
+	}
+#endif
+}
+
+static void db_ldap_set_options(struct ldap_connection *conn)
+{
+	unsigned int ldap_version;
+
+	db_ldap_set_opt(conn, LDAP_OPT_DEREF, &conn->set.ldap_deref,
+			"deref", conn->set.deref);
+
+	/* 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;
+	db_ldap_set_opt(conn, LDAP_OPT_PROTOCOL_VERSION, &ldap_version,
+			"protocol_version", dec2str(ldap_version));
+	db_ldap_set_tls_options(conn);
+}
+
 int db_ldap_connect(struct ldap_connection *conn)
 {
-	unsigned int ldap_version;
 	int ret;
 
 	if (conn->conn_state != LDAP_CONN_STATE_DISCONNECTED)
@@ -646,24 +739,7 @@
 			i_fatal("LDAP: ldap_init() failed with hosts: %s",
 				conn->set.hosts);
 
-		ret = ldap_set_option(conn->ld, LDAP_OPT_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 *)&ldap_version);
-		if (ret != LDAP_OPT_SUCCESS) {
-			i_fatal("LDAP: Can't set protocol version %u: %s",
-				ldap_version, ldap_err2string(ret));
-		}
+		db_ldap_set_options(conn);
 	}
 
 	if (conn->set.tls) {
--- a/src/auth/db-ldap.h	Fri Jan 25 13:45:36 2008 +0200
+++ b/src/auth/db-ldap.h	Fri Jan 25 14:25:11 2008 +0200
@@ -42,6 +42,13 @@
 	const char *sasl_realm;
 	const char *sasl_authz_id;
 
+	const char *tls_ca_cert_file;
+	const char *tls_ca_cert_dir;
+	const char *tls_cert_file;
+	const char *tls_key_file;
+	const char *tls_cipher_suite;
+	const char *tls_require_cert;
+
 	const char *deref;
 	const char *scope;
 	const char *base;