summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/doc-docbook/spec.xfpt86
-rw-r--r--doc/doc-txt/ChangeLog2
-rw-r--r--doc/doc-txt/NewStuff10
-rw-r--r--src/src/globals.c7
-rw-r--r--src/src/globals.h7
-rw-r--r--src/src/lookups/ldap.c58
-rw-r--r--src/src/readconf.c7
7 files changed, 177 insertions, 0 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 659a469bf..9dacb979c 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -6885,6 +6885,12 @@ The URL may begin with &`ldap`& or &`ldaps`& if your LDAP library supports
secure (encrypted) LDAP connections. The second of these ensures that an
encrypted TLS connection is used.
+.new
+With sufficiently modern LDAP libraries, Exim supports forcing TLS over regular
+LDAP connections, rather than the SSL-on-connect &`ldaps`&.
+See the &%ldap_start_tls%& option.
+.wen
+
.section "LDAP quoting" "SECID68"
.cindex "LDAP" "quoting"
@@ -12393,7 +12399,14 @@ listed in more than one group.
.section "Data lookups" "SECID101"
.table2
.row &%ibase_servers%& "InterBase servers"
+.row &%ldap_ca_cert_dir%& "dir of CA certs to verify LDAP server's"
+.row &%ldap_ca_cert_file%& "file of CA certs to verify LDAP server's"
+.row &%ldap_cert_file%& "client cert file for LDAP"
+.row &%ldap_cert_key%& "client key file for LDAP"
+.row &%ldap_cipher_suite%& "TLS negotiation preference control"
.row &%ldap_default_servers%& "used if no server in query"
+.row &%ldap_require_cert%& "action to take without LDAP server cert"
+.row &%ldap_start_tls%& "require TLS within LDAP"
.row &%ldap_version%& "set protocol version"
.row &%lookup_open_max%& "lookup files held open"
.row &%mysql_servers%& "default MySQL servers"
@@ -13805,6 +13818,56 @@ next attempt to deliver such a message, it gets removed. The incident is
logged.
+.new
+.option ldap_ca_cert_dir main string unset
+.cindex "LDAP", "TLS CA certificate directory"
+This option indicates which directory contains CA certificates for verifying
+a TLS certificate presented by an LDAP server.
+While Exim does not provide a default value, your SSL library may.
+Analogous to &%tls_verify_certificates%& but as a client-side option for LDAP
+and constrained to be a directory.
+.wen
+
+
+.new
+.option ldap_ca_cert_file main string unset
+.cindex "LDAP", "TLS CA certificate file"
+This option indicates which file contains CA certificates for verifying
+a TLS certificate presented by an LDAP server.
+While Exim does not provide a default value, your SSL library may.
+Analogous to &%tls_verify_certificates%& but as a client-side option for LDAP
+and constrained to be a file.
+.wen
+
+
+.new
+.option ldap_cert_file main string unset
+.cindex "LDAP" "TLS client certificate file"
+This option indicates which file contains an TLS client certificate which
+Exim should present to the LDAP server during TLS negotiation.
+Should be used together with &%ldap_cert_key%&.
+.wen
+
+
+.new
+.option ldap_cert_key main string unset
+.cindex "LDAP" "TLS client key file"
+This option indicates which file contains the secret/private key to use
+to prove identity to the LDAP server during TLS negotiation.
+Should be used together with &%ldap_cert_file%&, which contains the
+identity to be proven.
+.wen
+
+
+.new
+.option ldap_cipher_suite main string unset
+.cindex "LDAP" "TLS cipher suite"
+This controls the TLS cipher-suite negotiation during TLS negotiation with
+the LDAP server. See &<<SECTreqciphssl>>& for more details of the format of
+cipher-suite options with OpenSSL (as used by LDAP client libraries).
+.wen
+
+
.option ldap_default_servers main "string list" unset
.cindex "LDAP" "default servers"
This option provides a list of LDAP servers which are tried in turn when an
@@ -13813,6 +13876,29 @@ details of LDAP queries. This option is available only when Exim has been built
with LDAP support.
+.new
+.option ldap_require_cert main string unset.
+.cindex "LDAP" "policy for LDAP server TLS cert presentation"
+This should be one of the values "hard", "demand", "allow", "try" or "never".
+A value other than one of these is interpreted as "never".
+See the entry "TLS_REQCERT" in your system man page for ldap.conf(5).
+Although Exim does not set a default, the LDAP library probably defaults
+to hard/demand.
+.wen
+
+
+.new
+.option ldap_start_tls main boolean false
+.cindex "LDAP" "whether or not to negotiate TLS"
+If set, Exim will attempt to negotiate TLS with the LDAP server when
+connecting on a regular LDAP port. This is the LDAP equivalent of SMTP's
+"STARTTLS". This is distinct from using "ldaps", which is the LDAP form
+of SSL-on-connect.
+In the event of failure to negotiate TLS, the action taken is controlled
+by &%ldap_require_cert%&.
+.wen
+
+
.option ldap_version main integer unset
.cindex "LDAP" "protocol version, forcing"
This option can be used to force Exim to set a specific protocol version for
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 6e1bd4566..083870af6 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -32,6 +32,8 @@ NM/02 Fix wide character breakage in the rfc2047 coding
NM/03 Allow underscore in dnslist lookups
Fixes bug 1026. Patch from Graeme Fowler
+PP/04 Bugzilla 230: Support TLS-enabled LDAP (in addition to ldaps).
+ Code patches from Adam Ciarcinski of NetBSD.
Exim version 4.74
diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff
index 3a3ad5de5..55bde992d 100644
--- a/doc/doc-txt/NewStuff
+++ b/doc/doc-txt/NewStuff
@@ -9,6 +9,16 @@ test from the snapshots or the CVS before the documentation is updated. Once
the documentation is updated, this file is reduced to a short list.
+Version 4.75
+------------
+
+ 1. In addition to the existing LDAP and LDAP/SSL ("ldaps") support, there
+ is now LDAP/TLS support, given sufficiently modern OpenLDAP client
+ libraries. The following global options have been added in support of
+ this: ldap_ca_cert_dir, ldap_ca_cert_file, ldap_cert_file, ldap_cert_key,
+ ldap_cipher_suite, ldap_require_cert, ldap_start_tls.
+
+
Version 4.74
------------
diff --git a/src/src/globals.c b/src/src/globals.c
index 6653d62df..8631c7d8c 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -60,8 +60,15 @@ uschar *ibase_servers = NULL;
#endif
#ifdef LOOKUP_LDAP
+uschar *eldap_ca_cert_dir = NULL;
+uschar *eldap_ca_cert_file = NULL;
+uschar *eldap_cert_file = NULL;
+uschar *eldap_cert_key = NULL;
+uschar *eldap_cipher_suite = NULL;
uschar *eldap_default_servers = NULL;
+uschar *eldap_require_cert = NULL;
int eldap_version = -1;
+BOOL eldap_start_tls = FALSE;
#endif
#ifdef LOOKUP_MYSQL
diff --git a/src/src/globals.h b/src/src/globals.h
index db7a79bf7..bdc9bcf6d 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -35,7 +35,14 @@ extern uschar *ibase_servers;
#endif
#ifdef LOOKUP_LDAP
+extern uschar *eldap_ca_cert_dir; /* Directory with CA certificates */
+extern uschar *eldap_ca_cert_file; /* CA certificate file */
+extern uschar *eldap_cert_file; /* Certificate file */
+extern uschar *eldap_cert_key; /* Certificate key file */
+extern uschar *eldap_cipher_suite; /* Allowed cipher suite */
extern uschar *eldap_default_servers; /* List of default servers */
+extern uschar *eldap_require_cert; /* Peer certificate checking strategy */
+extern BOOL eldap_start_tls; /* Use STARTTLS */
extern int eldap_version; /* LDAP version */
#endif
diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c
index 943e431db..ddf803e21 100644
--- a/src/src/lookups/ldap.c
+++ b/src/src/lookups/ldap.c
@@ -431,6 +431,60 @@ if (lcp == NULL)
}
#endif /* LDAP_OPT_X_TLS */
+ #ifdef LDAP_OPT_X_TLS_CACERTFILE
+ if (eldap_ca_cert_file != NULL)
+ {
+ ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTFILE, eldap_ca_cert_file);
+ }
+ #endif
+ #ifdef LDAP_OPT_X_TLS_CACERTDIR
+ if (eldap_ca_cert_dir != NULL)
+ {
+ ldap_set_option(ld, LDAP_OPT_X_TLS_CACERTDIR, eldap_ca_cert_dir);
+ }
+ #endif
+ #ifdef LDAP_OPT_X_TLS_CERTFILE
+ if (eldap_cert_file != NULL)
+ {
+ ldap_set_option(ld, LDAP_OPT_X_TLS_CERTFILE, eldap_cert_file);
+ }
+ #endif
+ #ifdef LDAP_OPT_X_TLS_KEYFILE
+ if (eldap_cert_key != NULL)
+ {
+ ldap_set_option(ld, LDAP_OPT_X_TLS_KEYFILE, eldap_cert_key);
+ }
+ #endif
+ #ifdef LDAP_OPT_X_TLS_CIPHER_SUITE
+ if (eldap_cipher_suite != NULL)
+ {
+ ldap_set_option(ld, LDAP_OPT_X_TLS_CIPHER_SUITE, eldap_cipher_suite);
+ }
+ #endif
+ #ifdef LDAP_OPT_X_TLS_REQUIRE_CERT
+ if (eldap_require_cert != NULL)
+ {
+ int cert_option = LDAP_OPT_X_TLS_NEVER;
+ if (Ustrcmp(eldap_require_cert, "hard") == 0)
+ {
+ cert_option = LDAP_OPT_X_TLS_HARD;
+ }
+ else if (Ustrcmp(eldap_require_cert, "demand") == 0)
+ {
+ cert_option = LDAP_OPT_X_TLS_DEMAND;
+ }
+ else if (Ustrcmp(eldap_require_cert, "allow") == 0)
+ {
+ cert_option = LDAP_OPT_X_TLS_ALLOW;
+ }
+ else if (Ustrcmp(eldap_require_cert, "try") == 0)
+ {
+ cert_option = LDAP_OPT_X_TLS_TRY;
+ }
+ ldap_set_option(ld, LDAP_OPT_X_TLS_REQUIRE_CERT, cert_option);
+ }
+ #endif
+
/* Now add this connection to the chain of cached connections */
lcp = store_get(sizeof(LDAP_CONNECTION));
@@ -467,6 +521,10 @@ if (!lcp->bound ||
{
DEBUG(D_lookup) debug_printf("%sbinding with user=%s password=%s\n",
(lcp->bound)? "re-" : "", user, password);
+ if (eldap_start_tls)
+ {
+ ldap_start_tls_s(lcp->ld, NULL, NULL);
+ }
if ((msgid = ldap_bind(lcp->ld, CS user, CS password, LDAP_AUTH_SIMPLE))
== -1)
{
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 0b78958e4..b9d3747a5 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -262,7 +262,14 @@ static optionlist optionlist_config[] = {
{ "ignore_fromline_local", opt_bool, &ignore_fromline_local },
{ "keep_malformed", opt_time, &keep_malformed },
#ifdef LOOKUP_LDAP
+ { "ldap_ca_cert_dir", opt_stringptr, &eldap_ca_cert_dir },
+ { "ldap_ca_cert_file", opt_stringptr, &eldap_ca_cert_file },
+ { "ldap_cert_file", opt_stringptr, &eldap_cert_file },
+ { "ldap_cert_key", opt_stringptr, &eldap_cert_key },
+ { "ldap_cipher_suite", opt_stringptr, &eldap_cipher_suite },
{ "ldap_default_servers", opt_stringptr, &eldap_default_servers },
+ { "ldap_require_cert", opt_stringptr, &eldap_require_cert },
+ { "ldap_start_tls", opt_bool, &eldap_start_tls },
{ "ldap_version", opt_int, &eldap_version },
#endif
{ "local_from_check", opt_bool, &local_from_check },