diff options
-rw-r--r-- | doc/doc-docbook/spec.xfpt | 10 | ||||
-rw-r--r-- | doc/doc-txt/ChangeLog | 4 | ||||
-rw-r--r-- | doc/doc-txt/NewStuff | 2 | ||||
-rw-r--r-- | src/src/auths/cyrus_sasl.c | 84 | ||||
-rw-r--r-- | src/src/expand.c | 1 | ||||
-rw-r--r-- | src/src/globals.c | 1 | ||||
-rw-r--r-- | src/src/globals.h | 1 | ||||
-rw-r--r-- | src/src/tls-gnu.c | 8 | ||||
-rw-r--r-- | src/src/tls-openssl.c | 5 |
9 files changed, 104 insertions, 12 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 8afccbf1d..9c39b4aa2 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -11824,6 +11824,16 @@ command in a filter file. Its use is explained in the description of that command, which can be found in the separate document entitled &'Exim's interfaces to mail filtering'&. +.new +.vitem &$tls_bits$& +.vindex "&$tls_bits$&" +Contains an approximation of the TLS cipher's bit-strength; the meaning of +this depends upon the TLS implementation used. +If TLS has not been negotiated, the value will be 0. +The value of this is automatically fed into the Cyrus SASL authenticator +when acting as a server, to specify the "external SSF" (a SASL term). +.wen + .vitem &$tls_certificate_verified$& .vindex "&$tls_certificate_verified$&" This variable is set to &"1"& if a TLS certificate was verified when the diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 699da323c..3f43ef83d 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -28,6 +28,10 @@ PP/05 Swapped $auth1/$auth2 for gsasl GSSAPI mechanism, to be more consistent PP/06 Local/Makefile support for USE_(GNUTLS|OPENSSL)_PC=foo to use `pkg-config foo` for cflags/libs for the TLS implementation. +PP/07 New expansion variable $tls_bits; Cyrus SASL server connection + properties get this fed in as external SSF. A number of robustness + and debugging improvements to the cyrus_sasl authenticator. + Exim version 4.77 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 487ce30b3..057656c24 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -29,6 +29,8 @@ Version 4.78 "LOOKUP_LIBS" directly. Similarly for handling the TLS library support without adjusting "TLS_INCLUDE" and "TLS_LIBS". + 4. New expansion variable $tls_bits. + Version 4.77 ------------ diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index df7abc928..e61625e28 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -98,7 +98,7 @@ auth_cyrus_sasl_options_block *ob = uschar *list, *listptr, *buffer; int rc, i; unsigned int len; -uschar *rs_point; +uschar *rs_point, *expanded_hostname; sasl_conn_t *conn; sasl_callback_t cbs[]={ @@ -109,11 +109,17 @@ sasl_callback_t cbs[]={ if(ob->server_mech == NULL) ob->server_mech=string_copy(ablock->public_name); +expanded_hostname = expand_string(ob->server_hostname); +if (expanded_hostname == NULL) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " + "couldn't expand server_hostname [%s]: %s", + ablock->name, ob->server_hostname, expand_string_message); + /* we're going to initialise the library to check that there is an * authenticator of type whatever mechanism we're using */ -cbs[0].proc = (int(*)(void))&mysasl_config; +cbs[0].proc = (int(*)(void)) &mysasl_config; cbs[0].context = ob->server_mech; rc=sasl_server_init(cbs, "exim"); @@ -122,7 +128,7 @@ if( rc != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL library.", ablock->name); -rc=sasl_server_new(CS ob->server_service, CS primary_hostname, +rc=sasl_server_new(CS ob->server_service, CS expanded_hostname, CS ob->server_realm, NULL, NULL, NULL, 0, &conn); if( rc != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " @@ -136,7 +142,11 @@ if( rc != SASL_OK ) i=':'; listptr=list; -HDEBUG(D_auth) debug_printf("Cyrus SASL knows about: %s\n", list); +HDEBUG(D_auth) { + debug_printf("Initialised Cyrus SASL service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", + ob->server_service, expanded_hostname, ob->server_realm); + debug_printf("Cyrus SASL knows mechanisms: %s\n", list); +} /* the store_get / store_reset mechanism is hierarchical * the hierarchy is stored for us behind our back. This point @@ -184,7 +194,7 @@ uschar *output, *out2, *input, *clear, *hname; uschar *debug = NULL; /* Stops compiler complaining */ sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}}; sasl_conn_t *conn; -int rc, firsttime=1, clen; +int rc, firsttime=1, clen, negotiated_ssf; unsigned int inlen, outlen; input=data; @@ -220,6 +230,10 @@ if (rc != SASL_OK) rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL, NULL, NULL, 0, &conn); +HDEBUG(D_auth) + debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", + ob->server_service, hname, ob->server_realm); + if( rc != SASL_OK ) { auth_defer_msg = US"couldn't initialise Cyrus SASL connection"; @@ -227,6 +241,23 @@ if( rc != SASL_OK ) return DEFER; } +if (tls_cipher) + { + rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, &tls_bits); + if (rc != SASL_OK) + { + HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n", + tls_bits, sasl_errstring(rc, NULL, NULL)); + auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF"; + sasl_done(); + return DEFER; + } + else + HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_bits); + } +else + HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n"); + rc=SASL_CONTINUE; while(rc==SASL_CONTINUE) @@ -325,12 +356,53 @@ while(rc==SASL_CONTINUE) /* Get the username and copy it into $auth1 and $1. The former is now the preferred variable; the latter is the original variable. */ rc = sasl_getprop(conn, SASL_USERNAME, (const void **)(&out2)); + if (rc != SASL_OK) + { + HDEBUG(D_auth) + debug_printf("Cyrus SASL library will not tell us the username: %s\n", + sasl_errstring(rc, NULL, NULL)); + log_write(0, LOG_REJECT, "%s authenticator (%s):\n " + "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech, + sasl_errstring(rc, NULL, NULL)); + sasl_dispose(&conn); + sasl_done(); + return FAIL; + } + auth_vars[0] = expand_nstring[1] = string_copy(out2); expand_nlength[1] = Ustrlen(expand_nstring[1]); expand_nmax = 1; HDEBUG(D_auth) - debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, out2); + debug_printf("Cyrus SASL %s authentication succeeded for %s\n", + ob->server_mech, auth_vars[0]); + + rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf)); + if (rc != SASL_OK) + { + HDEBUG(D_auth) + debug_printf("Cyrus SASL library will not tell us the SSF: %s\n", + sasl_errstring(rc, NULL, NULL)); + log_write(0, LOG_REJECT, "%s authenticator (%s):\n " + "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech, + sasl_errstring(rc, NULL, NULL)); + sasl_dispose(&conn); + sasl_done(); + return FAIL; + } + HDEBUG(D_auth) + debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf); + if (negotiated_ssf > 0) + { + HDEBUG(D_auth) + debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf); + log_write(0, LOG_REJECT, "%s authenticator (%s):\n " + "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf); + sasl_dispose(&conn); + sasl_done(); + return FAIL; + } + /* close down the connection, freeing up library's memory */ sasl_dispose(&conn); sasl_done(); diff --git a/src/src/expand.c b/src/src/expand.c index a3dc590cc..54501de0b 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -611,6 +611,7 @@ static var_entry var_table[] = { { "srs_status", vtype_stringptr, &srs_status }, #endif { "thisaddress", vtype_stringptr, &filter_thisaddress }, + { "tls_bits", vtype_int, &tls_bits }, { "tls_certificate_verified", vtype_int, &tls_certificate_verified }, { "tls_cipher", vtype_stringptr, &tls_cipher }, { "tls_peerdn", vtype_stringptr, &tls_peerdn }, diff --git a/src/src/globals.c b/src/src/globals.c index a5516b91d..6124cb585 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -94,6 +94,7 @@ cluttered in several places (e.g. during logging) if we can always refer to them. Also, the tls_ variables are now always visible. */ BOOL tls_active = -1; +int tls_bits = 0; BOOL tls_certificate_verified = FALSE; uschar *tls_cipher = NULL; BOOL tls_on_connect = FALSE; diff --git a/src/src/globals.h b/src/src/globals.h index 58fdb0a0c..a51e3bc50 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -75,6 +75,7 @@ cluttered in several places (e.g. during logging) if we can always refer to them. Also, the tls_ variables are now always visible. */ extern int tls_active; /* fd/socket when in a TLS session */ +extern int tls_bits; /* bits used in TLS session */ extern BOOL tls_certificate_verified; /* Client certificate verified */ extern uschar *tls_cipher; /* Cipher used */ extern BOOL tls_on_connect; /* For older MTAs that don't STARTTLS */ diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 2d1a327de..2f952e47b 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -854,8 +854,9 @@ construct_cipher_name(gnutls_session session) { static uschar cipherbuf[256]; uschar *ver; -int bits, c, kx, mac, rc; +int c, kx, mac; #ifdef GNUTLS_CB_TLS_UNIQUE +int rc; gnutls_datum_t channel; #endif @@ -864,13 +865,14 @@ ver = string_copy( if (Ustrncmp(ver, "TLS ", 4) == 0) ver[3] = '-'; /* Don't want space */ c = gnutls_cipher_get(session); -bits = gnutls_cipher_get_key_size(c); +/* returns size in "bytes" */ +tls_bits = gnutls_cipher_get_key_size(c) * 8; mac = gnutls_mac_get(session); kx = gnutls_kx_get(session); string_format(cipherbuf, sizeof(cipherbuf), "%s:%s:%u", ver, - gnutls_cipher_suite_get_name(kx, c, mac), bits); + gnutls_cipher_suite_get_name(kx, c, mac), tls_bits); tls_cipher = cipherbuf; DEBUG(D_tls) debug_printf("cipher: %s\n", cipherbuf); diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c index e5d12cb84..2104711bb 100644 --- a/src/src/tls-openssl.c +++ b/src/src/tls-openssl.c @@ -441,7 +441,6 @@ yet reflect that. It should be a safe change anyway, even 0.9.8 versions have the accessor functions use const in the prototype. */ const SSL_CIPHER *c; uschar *ver; -int bits; switch (ssl->session->ssl_version) { @@ -462,10 +461,10 @@ switch (ssl->session->ssl_version) } c = (const SSL_CIPHER *) SSL_get_current_cipher(ssl); -SSL_CIPHER_get_bits(c, &bits); +SSL_CIPHER_get_bits(c, &tls_bits); string_format(cipherbuf, sizeof(cipherbuf), "%s:%s:%u", ver, - SSL_CIPHER_get_name(c), bits); + SSL_CIPHER_get_name(c), tls_bits); tls_cipher = cipherbuf; DEBUG(D_tls) debug_printf("Cipher: %s\n", cipherbuf); |