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
This commit is contained in:
Patrick Monnerat 2021-11-30 17:48:28 +01:00 committed by Daniel Stenberg
parent a6e2643433
commit a40160aee8
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 83 additions and 10 deletions

View file

@ -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) {

View file

@ -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: