summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2021-11-30 17:48:28 +0100
committerDaniel Stenberg <daniel@haxx.se>2021-12-06 07:53:04 +0100
commita40160aee83acae504fd4b30e39c28ff8dbab24c (patch)
tree9039a6c31884f3052795c11a82c11b463f874435
parenta6e2643433565abf17a2e3edda184aa1a99690ac (diff)
downloadcurl-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.d6
-rw-r--r--docs/cmdline-opts/ssl.d8
-rw-r--r--docs/libcurl/opts/CURLOPT_USE_SSL.36
-rw-r--r--lib/ldap.c5
-rw-r--r--lib/openldap.c68
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: