openldap: use connection meta for context struct

Remove member of conn->proto union.

Closes #17224
This commit is contained in:
Stefan Eissing 2025-04-29 13:09:00 +02:00 committed by Daniel Stenberg
parent de881a92eb
commit d57bdbf830
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
2 changed files with 161 additions and 79 deletions

View file

@ -41,6 +41,7 @@
#include <ldap.h>
#include "urldata.h"
#include "url.h"
#include <curl/curl.h>
#include "sendf.h"
#include "vtls/vtls.h"
@ -202,15 +203,18 @@ struct ldapreqinfo {
int nument;
};
/* meta key for storing ldapconninfo at connection */
#define CURL_META_LDAP_CONN "meta:proto:ldap:conn"
/*
* oldap_state()
*
* This is the ONLY way to change LDAP state!
*/
static void oldap_state(struct Curl_easy *data, ldapstate newstate)
static void oldap_state(struct Curl_easy *data, struct ldapconninfo *li,
ldapstate newstate)
{
struct ldapconninfo *ldapc = data->conn->proto.ldapc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const names[] = {
@ -225,12 +229,12 @@ static void oldap_state(struct Curl_easy *data, ldapstate newstate)
/* LAST */
};
if(ldapc->state != newstate)
if(li->state != newstate)
infof(data, "LDAP %p state change from %s to %s",
(void *)ldapc, names[ldapc->state], names[newstate]);
(void *)li, names[li->state], names[newstate]);
#endif
ldapc->state = newstate;
(void)data;
li->state = newstate;
}
/* Map some particular LDAP error codes to CURLcode values. */
@ -288,9 +292,13 @@ static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
static CURLcode oldap_parse_login_options(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
const char *ptr = conn->options;
DEBUGASSERT(li);
if(!li)
return CURLE_FAILED_INIT;
while(!result && ptr && *ptr) {
const char *key = ptr;
const char *value;
@ -334,7 +342,12 @@ static CURLcode oldap_setup_connection(struct Curl_easy *data,
*/
static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out)
{
struct berval *servercred = data->conn->proto.ldapc->servercred;
struct ldapconninfo *li =
Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
struct berval *servercred = li ? li->servercred : NULL;
DEBUGASSERT(li);
if(!li)
return CURLE_FAILED_INIT;
if(!servercred || !servercred->bv_val)
return CURLE_WEIRD_SERVER_REPLY;
@ -349,11 +362,14 @@ static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
const struct bufref *initresp)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
struct berval cred;
struct berval *pcred = &cred;
int rc;
DEBUGASSERT(li);
if(!li)
return CURLE_FAILED_INIT;
cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(initresp));
cred.bv_len = Curl_bufref_len(initresp);
if(!cred.bv_val)
@ -371,11 +387,13 @@ static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
const struct bufref *resp)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
struct berval cred;
struct berval *pcred = &cred;
int rc;
if(!li)
return CURLE_FAILED_INIT;
cred.bv_val = (char *)CURL_UNCONST(Curl_bufref_ptr(resp));
cred.bv_len = Curl_bufref_len(resp);
if(!cred.bv_val)
@ -391,11 +409,15 @@ static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
*/
static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
{
struct ldapconninfo *li = data->conn->proto.ldapc;
int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
&li->msgid);
struct ldapconninfo *li =
Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
int rc;
(void)mech;
if(!li)
return CURLE_FAILED_INIT;
rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
&li->msgid);
if(rc != LDAP_SUCCESS)
return oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
return CURLE_OK;
@ -405,11 +427,13 @@ static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
char *binddn = NULL;
struct berval passwd;
int rc;
if(!li)
return CURLE_FAILED_INIT;
passwd.bv_val = NULL;
passwd.bv_len = 0;
@ -425,37 +449,45 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
return oldap_map_error(rc,
data->state.aptr.user ?
CURLE_LOGIN_DENIED : CURLE_LDAP_CANNOT_BIND);
oldap_state(data, newstate);
oldap_state(data, li, newstate);
return CURLE_OK;
}
/* Query the supported SASL authentication mechanisms. */
static CURLcode oldap_perform_mechs(struct Curl_easy *data)
{
struct ldapconninfo *li = data->conn->proto.ldapc;
struct ldapconninfo *li =
Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
int rc;
static const char * const supportedSASLMechanisms[] = {
"supportedSASLMechanisms",
NULL
};
if(!li)
return CURLE_FAILED_INIT;
rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
(char **)CURL_UNCONST(supportedSASLMechanisms), 0,
NULL, NULL, NULL, 0, &li->msgid);
if(rc != LDAP_SUCCESS)
return oldap_map_error(rc, CURLE_LOGIN_DENIED);
oldap_state(data, OLDAP_MECHS);
oldap_state(data, li, OLDAP_MECHS);
return CURLE_OK;
}
/* Starts SASL bind. */
static CURLcode oldap_perform_sasl(struct Curl_easy *data)
{
struct ldapconninfo *li =
Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
saslprogress progress = SASL_IDLE;
struct ldapconninfo *li = data->conn->proto.ldapc;
CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
CURLcode result;
oldap_state(data, OLDAP_SASL);
if(!li)
return CURLE_FAILED_INIT;
result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
oldap_state(data, li, OLDAP_SASL);
if(!result && progress != SASL_INPROGRESS)
result = CURLE_LOGIN_DENIED;
return result;
@ -466,17 +498,22 @@ static Sockbuf_IO ldapsb_tls;
static bool ssl_installed(struct connectdata *conn)
{
return conn->proto.ldapc->recv != NULL;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
return li && li->recv != NULL;
}
static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
bool ssldone = FALSE;
CURLcode result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
CURLcode result;
if(!li)
return CURLE_FAILED_INIT;
result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
if(!result) {
oldap_state(data, newstate);
oldap_state(data, li, newstate);
if(ssldone) {
Sockbuf *sb;
@ -495,65 +532,84 @@ static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
/* Send the STARTTLS request */
static CURLcode oldap_perform_starttls(struct Curl_easy *data)
{
struct ldapconninfo *li = data->conn->proto.ldapc;
int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
struct ldapconninfo *li =
Curl_conn_meta_get(data->conn, CURL_META_LDAP_CONN);
int rc;
if(!li)
return CURLE_FAILED_INIT;
rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
if(rc != LDAP_SUCCESS)
return oldap_map_error(rc, CURLE_USE_SSL_FAILED);
oldap_state(data, OLDAP_STARTTLS);
oldap_state(data, li, OLDAP_STARTTLS);
return CURLE_OK;
}
#endif
static void oldap_conn_dtor(void *key, size_t klen, void *entry)
{
struct ldapconninfo *li = entry;
(void)key;
(void)klen;
if(li->ld) {
ldap_unbind_ext(li->ld, NULL, NULL);
li->ld = NULL;
}
free(li);
}
static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li;
static const int version = LDAP_VERSION3;
char *hosturl = NULL;
CURLcode result;
int rc;
char *hosturl;
#ifdef CURL_OPENLDAP_DEBUG
static int do_trace = -1;
#endif
(void)done;
DEBUGASSERT(!conn->proto.ldapc);
li = calloc(1, sizeof(struct ldapconninfo));
if(!li)
return CURLE_OUT_OF_MEMORY;
else {
CURLcode result;
li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
conn->proto.ldapc = li;
/* Initialize the SASL storage */
Curl_sasl_init(&li->sasl, data, &saslldap);
result = oldap_parse_login_options(conn);
if(result)
return result;
if(!li) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
result = Curl_conn_meta_set(conn, CURL_META_LDAP_CONN, li, oldap_conn_dtor);
if(result)
goto out;
li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
/* Initialize the SASL storage */
Curl_sasl_init(&li->sasl, data, &saslldap);
result = oldap_parse_login_options(conn);
if(result)
goto out;
hosturl = aprintf("%s://%s%s%s:%d",
conn->handler->scheme,
conn->bits.ipv6_ip ? "[" : "",
conn->host.name,
conn->bits.ipv6_ip ? "]" : "",
conn->remote_port);
if(!hosturl)
return CURLE_OUT_OF_MEMORY;
if(!hosturl) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
if(rc) {
failf(data, "LDAP local: Cannot connect to %s, %s",
hosturl, ldap_err2string(rc));
free(hosturl);
return CURLE_COULDNT_CONNECT;
result = CURLE_COULDNT_CONNECT;
goto out;
}
free(hosturl);
#ifdef CURL_OPENLDAP_DEBUG
if(do_trace < 0) {
const char *env = getenv("CURL_OPENLDAP_TRACE");
@ -572,23 +628,30 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
#ifdef USE_SSL
if(Curl_conn_is_ssl(conn, FIRSTSOCKET))
return oldap_ssl_connect(data, OLDAP_SSL);
if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
result = oldap_ssl_connect(data, OLDAP_SSL);
goto out;
}
if(data->set.use_ssl) {
CURLcode result = oldap_perform_starttls(data);
result = oldap_perform_starttls(data);
if(!result || data->set.use_ssl != CURLUSESSL_TRY)
return result;
goto out;
}
#endif
if(li->sasl.prefmech != SASL_AUTH_NONE)
return oldap_perform_mechs(data);
if(li->sasl.prefmech != SASL_AUTH_NONE) {
result = oldap_perform_mechs(data);
goto out;
}
/* Force bind even if anonymous bind is not needed in protocol version 3
to detect missing version 3 support. */
return oldap_perform_bind(data, OLDAP_BIND);
result = oldap_perform_bind(data, OLDAP_BIND);
out:
free(hosturl);
return result;
}
/* Handle the supported SASL mechanisms query response */
@ -596,12 +659,14 @@ static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
LDAPMessage *msg, int code)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
int rc;
BerElement *ber = NULL;
CURLcode result = CURLE_OK;
struct berval bv, *bvals;
if(!li)
return CURLE_FAILED_INIT;
switch(ldap_msgtype(msg)) {
case LDAP_RES_SEARCH_ENTRY:
/* Got a list of supported SASL mechanisms. */
@ -661,11 +726,13 @@ static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
LDAPMessage *msg, int code)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
CURLcode result = CURLE_OK;
saslprogress progress;
int rc;
if(!li)
return CURLE_FAILED_INIT;
li->servercred = NULL;
rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
if(rc != LDAP_SUCCESS) {
@ -675,7 +742,7 @@ static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
else {
result = Curl_sasl_continue(&li->sasl, data, code, &progress);
if(!result && progress != SASL_INPROGRESS)
oldap_state(data, OLDAP_STOP);
oldap_state(data, li, OLDAP_STOP);
}
if(li->servercred)
@ -688,11 +755,14 @@ static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
int code)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
CURLcode result = CURLE_OK;
struct berval *bv = NULL;
int rc;
if(!li)
return CURLE_FAILED_INIT;
if(code != LDAP_SUCCESS)
return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
@ -703,7 +773,7 @@ static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
}
else
oldap_state(data, OLDAP_STOP);
oldap_state(data, li, OLDAP_STOP);
if(bv)
ber_bvfree(bv);
@ -714,12 +784,15 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
LDAPMessage *msg = NULL;
struct timeval tv = {0, 0};
int code = LDAP_SUCCESS;
int rc;
if(!li)
return CURLE_FAILED_INIT;
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);
@ -800,7 +873,7 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
result = oldap_perform_bind(data, OLDAP_BIND);
else {
/* Version 3 supported: no bind required */
oldap_state(data, OLDAP_STOP);
oldap_state(data, li, OLDAP_STOP);
result = CURLE_OK;
}
}
@ -840,7 +913,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead_connection)
{
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
(void) dead_connection;
#ifndef USE_SSL
(void)data;
@ -859,8 +932,6 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
li->ld = NULL;
}
Curl_sasl_cleanup(conn, li->sasl.authused);
conn->proto.ldapc = NULL;
free(li);
}
return CURLE_OK;
}
@ -868,13 +939,15 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
static CURLcode oldap_do(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
struct ldapreqinfo *lr;
CURLcode result;
int rc;
LDAPURLDesc *lud;
int msgid;
if(!li)
return CURLE_FAILED_INIT;
connkeep(conn, "OpenLDAP do");
infof(data, "LDAP local: %s", data->state.url);
@ -927,8 +1000,10 @@ static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
if(lr) {
/* if there was a search in progress, abandon it */
if(lr->msgid) {
struct ldapconninfo *li = conn->proto.ldapc;
ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
if(li && li->ld) {
ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
}
lr->msgid = 0;
}
data->req.p.ldap = NULL;
@ -965,7 +1040,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
struct ldapreqinfo *lr = data->req.p.ldap;
int rc;
LDAPMessage *msg = NULL;
@ -980,6 +1055,10 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
(void)len;
(void)buf;
(void)sockindex;
if(!li) {
*err = CURLE_FAILED_INIT;
return -1;
}
rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
if(rc < 0) {
@ -1165,9 +1244,13 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
if(data) {
struct connectdata *conn = data->conn;
if(conn) {
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
CURLcode err = CURLE_RECV_ERROR;
if(!li) {
SET_SOCKERRNO(SOCKEINVAL);
return -1;
}
ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
if(ret < 0 && err == CURLE_AGAIN) {
SET_SOCKERRNO(SOCKEWOULDBLOCK);
@ -1176,7 +1259,6 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
}
return ret;
}
static ber_slen_t
ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
{
@ -1185,8 +1267,13 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
if(data) {
struct connectdata *conn = data->conn;
if(conn) {
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN);
CURLcode err = CURLE_SEND_ERROR;
if(!li) {
SET_SOCKERRNO(SOCKEINVAL);
return -1;
}
ret = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &err);
if(ret < 0 && err == CURLE_AGAIN) {
SET_SOCKERRNO(SOCKEWOULDBLOCK);