diff options
author | Patrick Monnerat <patrick@monnerat.net> | 2021-11-30 17:48:28 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2021-12-06 07:53:04 +0100 |
commit | a40160aee83acae504fd4b30e39c28ff8dbab24c (patch) | |
tree | 9039a6c31884f3052795c11a82c11b463f874435 | |
parent | a6e2643433565abf17a2e3edda184aa1a99690ac (diff) | |
download | curl-a40160aee83acae504fd4b30e39c28ff8dbab24c.tar.gz |
openldap: implement STARTTLS
As this introduces use of CURLOPT_USE_SSL option for LDAP, also check
this option in ldap.c as it is not supported by this backend.
Closes #8065
-rw-r--r-- | docs/cmdline-opts/ssl-reqd.d | 6 | ||||
-rw-r--r-- | docs/cmdline-opts/ssl.d | 8 | ||||
-rw-r--r-- | docs/libcurl/opts/CURLOPT_USE_SSL.3 | 6 | ||||
-rw-r--r-- | lib/ldap.c | 5 | ||||
-rw-r--r-- | lib/openldap.c | 68 |
5 files changed, 83 insertions, 10 deletions
diff --git a/docs/cmdline-opts/ssl-reqd.d b/docs/cmdline-opts/ssl-reqd.d index 81e0ea794..fb9a1aa83 100644 --- a/docs/cmdline-opts/ssl-reqd.d +++ b/docs/cmdline-opts/ssl-reqd.d @@ -1,6 +1,6 @@ Long: ssl-reqd Help: Require SSL/TLS -Protocols: FTP IMAP POP3 SMTP +Protocols: FTP IMAP POP3 SMTP LDAP Added: 7.20.0 Category: tls Example: --ssl-reqd ftp://example.com @@ -9,4 +9,8 @@ See-also: ssl insecure Require SSL/TLS for the connection. Terminates the connection if the server does not support SSL/TLS. +This option is handled in LDAP since version 7.81.0. It is fully supported +by the openldap backend and rejected by the generic ldap backend if explicit +TLS is required. + This option was formerly known as --ftp-ssl-reqd. diff --git a/docs/cmdline-opts/ssl.d b/docs/cmdline-opts/ssl.d index 96e4169aa..83cac5c9d 100644 --- a/docs/cmdline-opts/ssl.d +++ b/docs/cmdline-opts/ssl.d @@ -1,6 +1,6 @@ Long: ssl Help: Try SSL/TLS -Protocols: FTP IMAP POP3 SMTP +Protocols: FTP IMAP POP3 SMTP LDAP Added: 7.20.0 Category: tls Example: --ssl pop3://example.com/ @@ -10,5 +10,11 @@ Try to use SSL/TLS for the connection. Reverts to a non-secure connection if the server does not support SSL/TLS. See also --ftp-ssl-control and --ssl-reqd for different levels of encryption required. +This option is handled in LDAP since version 7.81.0. It is fully supported +by the openldap backend and ignored by the generic ldap backend. + +Please note that a server may close the connection if the negotiation does +not succeed. + This option was formerly known as --ftp-ssl (Added in 7.11.0). That option name can still be used but will be removed in a future version. diff --git a/docs/libcurl/opts/CURLOPT_USE_SSL.3 b/docs/libcurl/opts/CURLOPT_USE_SSL.3 index 767be1f36..3fcc2dfc5 100644 --- a/docs/libcurl/opts/CURLOPT_USE_SSL.3 +++ b/docs/libcurl/opts/CURLOPT_USE_SSL.3 @@ -40,7 +40,8 @@ This is for enabling SSL/TLS when you use FTP, SMTP, POP3, IMAP etc. .IP CURLUSESSL_NONE do not attempt to use SSL. .IP CURLUSESSL_TRY -Try using SSL, proceed as normal otherwise. +Try using SSL, proceed as normal otherwise. Note that server may close the +connection if the negotiation does not succeed. .IP CURLUSESSL_CONTROL Require SSL for the control connection or fail with \fICURLE_USE_SSL_FAILED\fP. .IP CURLUSESSL_ALL @@ -48,7 +49,7 @@ Require SSL for all communication or fail with \fICURLE_USE_SSL_FAILED\fP. .SH DEFAULT CURLUSESSL_NONE .SH PROTOCOLS -FTP, SMTP, POP3, IMAP +FTP, SMTP, POP3, IMAP, LDAP .SH EXAMPLE .nf CURL *curl = curl_easy_init(); @@ -65,6 +66,7 @@ if(curl) { .SH AVAILABILITY Added in 7.11.0. This option was known as CURLOPT_FTP_SSL up to 7.16.4, and the constants were known as CURLFTPSSL_* +Handled by LDAP since 7.81.0. Fully supported by the openldap backend only. .SH RETURN VALUE Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not. .SH "SEE ALSO" diff --git a/lib/ldap.c b/lib/ldap.c index 1d9e44cc9..284f165ea 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -464,6 +464,11 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #endif #endif /* CURL_LDAP_USE_SSL */ } + else if(data->set.use_ssl > CURLUSESSL_TRY) { + failf(data, "LDAP local: explicit TLS not supported"); + result = CURLE_NOT_BUILT_IN; + goto quit; + } else { server = ldap_init(host, (int)conn->port); if(!server) { diff --git a/lib/openldap.c b/lib/openldap.c index ba632d85b..003d0f8e5 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -74,6 +74,8 @@ typedef enum { OLDAP_STOP, /* Do nothing state, stops the state machine */ OLDAP_SSL, /* Performing SSL handshake. */ + OLDAP_STARTTLS, /* STARTTLS request sent. */ + OLDAP_TLS, /* Performing TLS handshake. */ OLDAP_BIND, /* Simple bind reply. */ OLDAP_BINDV2, /* Simple bind reply in protocol version 2. */ OLDAP_LAST /* Never used */ @@ -194,6 +196,8 @@ static void state(struct Curl_easy *data, ldapstate newstate) static const char * const names[] = { "STOP", "SSL", + "STARTTLS", + "TLS", "BIND", "BINDV2", /* LAST */ @@ -256,6 +260,10 @@ static CURLcode oldap_setup_connection(struct Curl_easy *data, li->proto = proto; conn->proto.ldapc = li; connkeep(conn, "OpenLDAP default"); + + /* Clear the TLS upgraded flag */ + conn->bits.tls_upgraded = FALSE; + return CURLE_OK; } @@ -297,7 +305,7 @@ static bool ssl_installed(struct connectdata *conn) return conn->proto.ldapc->recv != NULL; } -static CURLcode oldap_ssl_connect(struct Curl_easy *data) +static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate) { CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; @@ -307,7 +315,7 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data) result = Curl_ssl_connect_nonblocking(data, conn, FALSE, FIRSTSOCKET, &ssldone); if(!result) { - state(data, OLDAP_SSL); + state(data, newstate); if(ssldone) { Sockbuf *sb; @@ -322,6 +330,20 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data) return result; } + +/* Send the STARTTLS request */ +static CURLcode oldap_perform_starttls(struct Curl_easy *data) +{ + CURLcode result = CURLE_OK; + struct ldapconninfo *li = data->conn->proto.ldapc; + int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid); + + if(rc == LDAP_SUCCESS) + state(data, OLDAP_STARTTLS); + else + result = oldap_map_error(rc, CURLE_USE_SSL_FAILED); + return result; +} #endif static CURLcode oldap_connect(struct Curl_easy *data, bool *done) @@ -364,7 +386,14 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done) #ifdef USE_SSL if(conn->handler->flags & PROTOPT_SSL) - return oldap_ssl_connect(data); + return oldap_ssl_connect(data, OLDAP_SSL); + + if(data->set.use_ssl) { + CURLcode result = oldap_perform_starttls(data); + + if(!result || data->set.use_ssl != CURLUSESSL_TRY) + return result; + } #endif /* Force bind even if anonymous bind is not needed in protocol version 3 @@ -409,7 +438,7 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) int code = LDAP_SUCCESS; int rc; - if(li->state != OLDAP_SSL) { + if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) { /* Get response to last command. */ rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg); if(!rc) @@ -426,7 +455,11 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) code = rc; /* If protocol version 3 is not supported, fallback to version 2. */ - if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2) { + if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 +#ifdef USE_SSL + && (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) +#endif + ) { static const int version = LDAP_VERSION2; ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version); @@ -440,10 +473,33 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done) #ifdef USE_SSL case OLDAP_SSL: - result = oldap_ssl_connect(data); + result = oldap_ssl_connect(data, OLDAP_SSL); if(!result && ssl_installed(conn)) result = oldap_perform_bind(data, OLDAP_BIND); break; + case OLDAP_STARTTLS: + if(code != LDAP_SUCCESS) { + if(data->set.use_ssl != CURLUSESSL_TRY) + result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else + result = oldap_perform_bind(data, OLDAP_BIND); + break; + } + /* FALLTHROUGH */ + case OLDAP_TLS: + result = oldap_ssl_connect(data, OLDAP_TLS); + if(result && data->set.use_ssl != CURLUSESSL_TRY) + result = oldap_map_error(code, CURLE_USE_SSL_FAILED); + else if(ssl_installed(conn)) { + conn->bits.tls_upgraded = TRUE; + if(conn->bits.user_passwd) + result = oldap_perform_bind(data, OLDAP_BIND); + else { + state(data, OLDAP_STOP); /* Version 3 supported: no bind required */ + result = CURLE_OK; + } + } + break; #endif case OLDAP_BIND: |