diff options
-rw-r--r-- | doc/doc-docbook/spec.xfpt | 86 | ||||
-rw-r--r-- | doc/doc-txt/ChangeLog | 2 | ||||
-rw-r--r-- | doc/doc-txt/NewStuff | 10 | ||||
-rw-r--r-- | src/src/globals.c | 7 | ||||
-rw-r--r-- | src/src/globals.h | 7 | ||||
-rw-r--r-- | src/src/lookups/ldap.c | 58 | ||||
-rw-r--r-- | src/src/readconf.c | 7 |
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 }, |