mirror of
https://github.com/curl/curl.git
synced 2026-08-25 01:43:32 +03:00
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
This commit is contained in:
parent
39406280bb
commit
cdc1da9120
2 changed files with 108 additions and 87 deletions
|
|
@ -30,15 +30,14 @@ CURLINFO_RESPONSE_CODE \- get the last response code
|
||||||
CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RESPONSE_CODE, long *codep);
|
CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_RESPONSE_CODE, long *codep);
|
||||||
.fi
|
.fi
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
Pass a pointer to a long to receive the last received HTTP, FTP or SMTP
|
Pass a pointer to a long to receive the last received HTTP, FTP, SMTP or
|
||||||
response code. This option was previously known as CURLINFO_HTTP_CODE in
|
LDAP (openldap only) response code. This option was previously known as
|
||||||
libcurl 7.10.7 and earlier. The stored value will be zero if no server
|
CURLINFO_HTTP_CODE in libcurl 7.10.7 and earlier.
|
||||||
response code has been received. Note that a proxy's CONNECT response should
|
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.
|
be read with \fICURLINFO_HTTP_CONNECTCODE(3)\fP and not this.
|
||||||
|
|
||||||
Support for SMTP responses added in 7.25.0.
|
|
||||||
.SH PROTOCOLS
|
.SH PROTOCOLS
|
||||||
HTTP, FTP and SMTP
|
HTTP, FTP, SMTP and LDAP
|
||||||
.SH EXAMPLE
|
.SH EXAMPLE
|
||||||
.nf
|
.nf
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
|
|
@ -55,6 +54,7 @@ if(curl) {
|
||||||
.fi
|
.fi
|
||||||
.SH AVAILABILITY
|
.SH AVAILABILITY
|
||||||
Added in 7.10.8. CURLINFO_HTTP_CODE was added in 7.4.1.
|
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
|
.SH RETURN VALUE
|
||||||
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
|
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
|
|
|
||||||
181
lib/openldap.c
181
lib/openldap.c
|
|
@ -154,20 +154,6 @@ const struct Curl_handler Curl_handler_ldaps = {
|
||||||
};
|
};
|
||||||
#endif
|
#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 {
|
struct ldapconninfo {
|
||||||
LDAP *ld; /* Openldap connection handle. */
|
LDAP *ld; /* Openldap connection handle. */
|
||||||
Curl_recv *recv; /* For stacking SSL handler */
|
Curl_recv *recv; /* For stacking SSL handler */
|
||||||
|
|
@ -231,40 +217,66 @@ static CURLcode oldap_map_error(int rc, CURLcode result)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
|
||||||
|
{
|
||||||
|
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"
|
||||||
|
};
|
||||||
|
|
||||||
|
*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";
|
||||||
|
|
||||||
|
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 result;
|
||||||
|
}
|
||||||
|
|
||||||
static CURLcode oldap_setup_connection(struct Curl_easy *data,
|
static CURLcode oldap_setup_connection(struct Curl_easy *data,
|
||||||
struct connectdata *conn)
|
struct connectdata *conn)
|
||||||
{
|
{
|
||||||
struct ldapconninfo *li;
|
CURLcode result;
|
||||||
LDAPURLDesc *lud;
|
LDAPURLDesc *lud;
|
||||||
int rc, proto;
|
struct ldapconninfo *li;
|
||||||
CURLcode status;
|
|
||||||
|
|
||||||
rc = ldap_url_parse(data->state.url, &lud);
|
/* Early URL syntax check. */
|
||||||
if(rc != LDAP_URL_SUCCESS) {
|
result = oldap_url_parse(data, &lud);
|
||||||
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];
|
|
||||||
}
|
|
||||||
failf(data, "LDAP local: %s", msg);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
|
|
||||||
ldap_free_urldesc(lud);
|
ldap_free_urldesc(lud);
|
||||||
|
|
||||||
li = calloc(1, sizeof(struct ldapconninfo));
|
if(!result) {
|
||||||
if(!li)
|
li = calloc(1, sizeof(struct ldapconninfo));
|
||||||
return CURLE_OUT_OF_MEMORY;
|
if(!li)
|
||||||
li->proto = proto;
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
conn->proto.ldapc = li;
|
else {
|
||||||
connkeep(conn, "OpenLDAP default");
|
li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
|
||||||
|
conn->proto.ldapc = li;
|
||||||
|
connkeep(conn, "OpenLDAP default");
|
||||||
|
|
||||||
/* Clear the TLS upgraded flag */
|
/* Clear the TLS upgraded flag */
|
||||||
conn->bits.tls_upgraded = FALSE;
|
conn->bits.tls_upgraded = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Starts LDAP simple bind. */
|
/* Starts LDAP simple bind. */
|
||||||
|
|
@ -350,29 +362,31 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
|
||||||
{
|
{
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct ldapconninfo *li = conn->proto.ldapc;
|
struct ldapconninfo *li = conn->proto.ldapc;
|
||||||
int rc, proto = LDAP_VERSION3;
|
static const int version = LDAP_VERSION3;
|
||||||
char hosturl[1024];
|
int rc;
|
||||||
char *ptr;
|
char *hosturl;
|
||||||
#ifdef CURL_OPENLDAP_DEBUG
|
#ifdef CURL_OPENLDAP_DEBUG
|
||||||
static int do_trace = -1;
|
static int do_trace = -1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
(void)done;
|
(void)done;
|
||||||
|
|
||||||
strcpy(hosturl, "ldap");
|
hosturl = aprintf("ldap%s://%s:%d",
|
||||||
ptr = hosturl + 4;
|
conn->handler->flags & PROTOPT_SSL? "s": "",
|
||||||
if(conn->handler->flags & PROTOPT_SSL)
|
conn->host.name, conn->remote_port);
|
||||||
*ptr++ = 's';
|
if(!hosturl)
|
||||||
msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
|
return CURLE_OUT_OF_MEMORY;
|
||||||
conn->host.name, conn->remote_port);
|
|
||||||
|
|
||||||
rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
|
rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
|
||||||
if(rc) {
|
if(rc) {
|
||||||
failf(data, "LDAP local: Cannot connect to %s, %s",
|
failf(data, "LDAP local: Cannot connect to %s, %s",
|
||||||
hosturl, ldap_err2string(rc));
|
hosturl, ldap_err2string(rc));
|
||||||
|
free(hosturl);
|
||||||
return CURLE_COULDNT_CONNECT;
|
return CURLE_COULDNT_CONNECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(hosturl);
|
||||||
|
|
||||||
#ifdef CURL_OPENLDAP_DEBUG
|
#ifdef CURL_OPENLDAP_DEBUG
|
||||||
if(do_trace < 0) {
|
if(do_trace < 0) {
|
||||||
const char *env = getenv("CURL_OPENLDAP_TRACE");
|
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);
|
ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
|
||||||
#endif
|
#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
|
#ifdef USE_SSL
|
||||||
if(conn->handler->flags & PROTOPT_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);
|
rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
|
||||||
if(rc)
|
if(rc)
|
||||||
code = 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 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
|
||||||
|
|
@ -551,44 +573,40 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
|
||||||
struct connectdata *conn = data->conn;
|
struct connectdata *conn = data->conn;
|
||||||
struct ldapconninfo *li = conn->proto.ldapc;
|
struct ldapconninfo *li = conn->proto.ldapc;
|
||||||
struct ldapreqinfo *lr;
|
struct ldapreqinfo *lr;
|
||||||
CURLcode status = CURLE_OK;
|
CURLcode result;
|
||||||
int rc = 0;
|
int rc;
|
||||||
LDAPURLDesc *ludp = NULL;
|
LDAPURLDesc *lud;
|
||||||
int msgid;
|
int msgid;
|
||||||
|
|
||||||
connkeep(conn, "OpenLDAP do");
|
connkeep(conn, "OpenLDAP do");
|
||||||
|
|
||||||
infof(data, "LDAP local: %s", data->state.url);
|
infof(data, "LDAP local: %s", data->state.url);
|
||||||
|
|
||||||
rc = ldap_url_parse(data->state.url, &ludp);
|
result = oldap_url_parse(data, &lud);
|
||||||
if(rc != LDAP_URL_SUCCESS) {
|
if(!result) {
|
||||||
const char *msg = "url parsing problem";
|
rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
|
||||||
status = CURLE_URL_MALFORMAT;
|
lud->lud_filter, lud->lud_attrs, 0,
|
||||||
if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
|
NULL, NULL, NULL, 0, &msgid);
|
||||||
if(rc == LDAP_URL_ERR_MEM)
|
ldap_free_urldesc(lud);
|
||||||
status = CURLE_OUT_OF_MEMORY;
|
if(rc != LDAP_SUCCESS) {
|
||||||
msg = url_errs[rc];
|
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;
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
|
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;
|
int rc;
|
||||||
LDAPMessage *msg = NULL;
|
LDAPMessage *msg = NULL;
|
||||||
BerElement *ber = NULL;
|
BerElement *ber = NULL;
|
||||||
struct timeval tv = {0, 1};
|
struct timeval tv = {0, 0};
|
||||||
struct berval bv, *bvals;
|
struct berval bv, *bvals;
|
||||||
int binary = 0;
|
int binary = 0;
|
||||||
CURLcode result = CURLE_AGAIN;
|
CURLcode result = CURLE_AGAIN;
|
||||||
|
|
@ -689,6 +707,9 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* store the latest code for later retrieval */
|
||||||
|
data->info.httpcode = code;
|
||||||
|
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case LDAP_SIZELIMIT_EXCEEDED:
|
case LDAP_SIZELIMIT_EXCEEDED:
|
||||||
infof(data, "There are more than %d entries", lr->nument);
|
infof(data, "There are more than %d entries", lr->nument);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue