summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2021-12-14 15:42:47 +0100
committerDaniel Stenberg <daniel@haxx.se>2021-12-15 08:07:53 +0100
commitcdc1da912066535680f02eb31e6e7c1015bc92ff (patch)
treec81d605eb5a2a2a230a3f6fdfac9b7b430977c97
parent39406280bbd66234ad2bdec072f5e183efac23d8 (diff)
downloadcurl-cdc1da912066535680f02eb31e6e7c1015bc92ff.tar.gz
openldap: several minor improvements
- Early check proper LDAP URL syntax. Reject URLs with a userinfo part. - Use dynamic memory for ldap_init_fd() URL rather than a stack-allocated buffer. - Never chase referrals: supporting it would require additional parallel connections and alternate authentication credentials. - Do not wait 1 microsecond while polling/reading query response data. - Store last received server code for retrieval with CURLINFO_RESPONSE_CODE. Closes #8140
-rw-r--r--docs/libcurl/opts/CURLINFO_RESPONSE_CODE.314
-rw-r--r--lib/openldap.c179
2 files changed, 107 insertions, 86 deletions
diff --git a/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3 b/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3
index 66b9f3719..628b438bd 100644
--- a/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3
+++ b/docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3
@@ -30,15 +30,14 @@ CURLINFO_RESPONSE_CODE \- get the last response code
CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RESPONSE_CODE, long *codep);
.fi
.SH DESCRIPTION
-Pass a pointer to a long to receive the last received HTTP, FTP or SMTP
-response code. This option was previously known as CURLINFO_HTTP_CODE in
-libcurl 7.10.7 and earlier. The stored value will be zero if no server
-response code has been received. Note that a proxy's CONNECT response should
+Pass a pointer to a long to receive the last received HTTP, FTP, SMTP or
+LDAP (openldap only) response code. This option was previously known as
+CURLINFO_HTTP_CODE in libcurl 7.10.7 and earlier.
+The stored value will be zero if no server response code has been received.
+Note that a proxy's CONNECT response should
be read with \fICURLINFO_HTTP_CONNECTCODE(3)\fP and not this.
-
-Support for SMTP responses added in 7.25.0.
.SH PROTOCOLS
-HTTP, FTP and SMTP
+HTTP, FTP, SMTP and LDAP
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
@@ -55,6 +54,7 @@ if(curl) {
.fi
.SH AVAILABILITY
Added in 7.10.8. CURLINFO_HTTP_CODE was added in 7.4.1.
+Support for SMTP responses added in 7.25.0, for OpenLDAP in 7.81.0.
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
diff --git a/lib/openldap.c b/lib/openldap.c
index f5483f478..0ffb6a36a 100644
--- a/lib/openldap.c
+++ b/lib/openldap.c
@@ -154,20 +154,6 @@ const struct Curl_handler Curl_handler_ldaps = {
};
#endif
-static const char *url_errs[] = {
- "success",
- "out of memory",
- "bad parameter",
- "unrecognized scheme",
- "unbalanced delimiter",
- "bad URL",
- "bad host or port",
- "bad or missing attributes",
- "bad or missing scope",
- "bad or missing filter",
- "bad or missing extensions"
-};
-
struct ldapconninfo {
LDAP *ld; /* Openldap connection handle. */
Curl_recv *recv; /* For stacking SSL handler */
@@ -231,40 +217,66 @@ static CURLcode oldap_map_error(int rc, CURLcode result)
return result;
}
-static CURLcode oldap_setup_connection(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
{
- struct ldapconninfo *li;
- LDAPURLDesc *lud;
- int rc, proto;
- CURLcode status;
+ CURLcode result = CURLE_OK;
+ int rc = LDAP_URL_ERR_BADURL;
+ static const char * const url_errs[] = {
+ "success",
+ "out of memory",
+ "bad parameter",
+ "unrecognized scheme",
+ "unbalanced delimiter",
+ "bad URL",
+ "bad host or port",
+ "bad or missing attributes",
+ "bad or missing scope",
+ "bad or missing filter",
+ "bad or missing extensions"
+ };
- rc = ldap_url_parse(data->state.url, &lud);
+ *ludp = NULL;
+ if(!data->state.up.user && !data->state.up.password &&
+ !data->state.up.options)
+ rc = ldap_url_parse(data->state.url, ludp);
if(rc != LDAP_URL_SUCCESS) {
const char *msg = "url parsing problem";
- status = CURLE_URL_MALFORMAT;
- if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
- if(rc == LDAP_URL_ERR_MEM)
- status = CURLE_OUT_OF_MEMORY;
+
+ result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT;
+ rc -= LDAP_URL_SUCCESS;
+ if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
msg = url_errs[rc];
- }
failf(data, "LDAP local: %s", msg);
- return status;
}
- proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
- ldap_free_urldesc(lud);
+ return result;
+}
- li = calloc(1, sizeof(struct ldapconninfo));
- if(!li)
- return CURLE_OUT_OF_MEMORY;
- li->proto = proto;
- conn->proto.ldapc = li;
- connkeep(conn, "OpenLDAP default");
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ LDAPURLDesc *lud;
+ struct ldapconninfo *li;
- /* Clear the TLS upgraded flag */
- conn->bits.tls_upgraded = FALSE;
+ /* Early URL syntax check. */
+ result = oldap_url_parse(data, &lud);
+ ldap_free_urldesc(lud);
- return CURLE_OK;
+ if(!result) {
+ li = calloc(1, sizeof(struct ldapconninfo));
+ if(!li)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
+ conn->proto.ldapc = li;
+ connkeep(conn, "OpenLDAP default");
+
+ /* Clear the TLS upgraded flag */
+ conn->bits.tls_upgraded = FALSE;
+ }
+ }
+
+ return result;
}
/* Starts LDAP simple bind. */
@@ -350,29 +362,31 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
- int rc, proto = LDAP_VERSION3;
- char hosturl[1024];
- char *ptr;
+ static const int version = LDAP_VERSION3;
+ int rc;
+ char *hosturl;
#ifdef CURL_OPENLDAP_DEBUG
static int do_trace = -1;
#endif
(void)done;
- strcpy(hosturl, "ldap");
- ptr = hosturl + 4;
- if(conn->handler->flags & PROTOPT_SSL)
- *ptr++ = 's';
- msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
- conn->host.name, conn->remote_port);
+ hosturl = aprintf("ldap%s://%s:%d",
+ conn->handler->flags & PROTOPT_SSL? "s": "",
+ conn->host.name, conn->remote_port);
+ if(!hosturl)
+ return CURLE_OUT_OF_MEMORY;
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;
}
+ free(hosturl);
+
#ifdef CURL_OPENLDAP_DEBUG
if(do_trace < 0) {
const char *env = getenv("CURL_OPENLDAP_TRACE");
@@ -382,7 +396,11 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
#endif
- ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+ /* Try version 3 first. */
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ /* Do not chase referrals. */
+ ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
#ifdef USE_SSL
if(conn->handler->flags & PROTOPT_SSL)
@@ -453,6 +471,10 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
if(rc)
code = rc;
+ else {
+ /* store the latest code for later retrieval */
+ data->info.httpcode = code;
+ }
/* If protocol version 3 is not supported, fallback to version 2. */
if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2
@@ -551,44 +573,40 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn;
struct ldapconninfo *li = conn->proto.ldapc;
struct ldapreqinfo *lr;
- CURLcode status = CURLE_OK;
- int rc = 0;
- LDAPURLDesc *ludp = NULL;
+ CURLcode result;
+ int rc;
+ LDAPURLDesc *lud;
int msgid;
connkeep(conn, "OpenLDAP do");
infof(data, "LDAP local: %s", data->state.url);
- rc = ldap_url_parse(data->state.url, &ludp);
- if(rc != LDAP_URL_SUCCESS) {
- const char *msg = "url parsing problem";
- status = CURLE_URL_MALFORMAT;
- if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
- if(rc == LDAP_URL_ERR_MEM)
- status = CURLE_OUT_OF_MEMORY;
- msg = url_errs[rc];
+ result = oldap_url_parse(data, &lud);
+ if(!result) {
+ rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
+ lud->lud_filter, lud->lud_attrs, 0,
+ NULL, NULL, NULL, 0, &msgid);
+ ldap_free_urldesc(lud);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
+ result = CURLE_LDAP_SEARCH_FAILED;
+ }
+ else {
+ lr = calloc(1, sizeof(struct ldapreqinfo));
+ if(!lr) {
+ ldap_abandon_ext(li->ld, msgid, NULL, NULL);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ lr->msgid = msgid;
+ data->req.p.ldap = lr;
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
+ *done = TRUE;
+ }
}
- failf(data, "LDAP local: %s", msg);
- return status;
- }
-
- rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
- ludp->lud_filter, ludp->lud_attrs, 0,
- NULL, NULL, NULL, 0, &msgid);
- ldap_free_urldesc(ludp);
- if(rc != LDAP_SUCCESS) {
- failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
- return CURLE_LDAP_SEARCH_FAILED;
}
- lr = calloc(1, sizeof(struct ldapreqinfo));
- if(!lr)
- return CURLE_OUT_OF_MEMORY;
- lr->msgid = msgid;
- data->req.p.ldap = lr;
- Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
- *done = TRUE;
- return CURLE_OK;
+ return result;
}
static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
@@ -653,7 +671,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
int rc;
LDAPMessage *msg = NULL;
BerElement *ber = NULL;
- struct timeval tv = {0, 1};
+ struct timeval tv = {0, 0};
struct berval bv, *bvals;
int binary = 0;
CURLcode result = CURLE_AGAIN;
@@ -689,6 +707,9 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
break;
}
+ /* store the latest code for later retrieval */
+ data->info.httpcode = code;
+
switch(code) {
case LDAP_SIZELIMIT_EXCEEDED:
infof(data, "There are more than %d entries", lr->nument);