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
@ -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"
|
||||
|
||||
181
lib/openldap.c
181
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_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,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
struct ldapconninfo *li;
|
||||
CURLcode result;
|
||||
LDAPURLDesc *lud;
|
||||
int rc, proto;
|
||||
CURLcode status;
|
||||
struct ldapconninfo *li;
|
||||
|
||||
rc = ldap_url_parse(data->state.url, &lud);
|
||||
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];
|
||||
}
|
||||
failf(data, "LDAP local: %s", msg);
|
||||
return status;
|
||||
}
|
||||
proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
|
||||
/* Early URL syntax check. */
|
||||
result = oldap_url_parse(data, &lud);
|
||||
ldap_free_urldesc(lud);
|
||||
|
||||
li = calloc(1, sizeof(struct ldapconninfo));
|
||||
if(!li)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
li->proto = proto;
|
||||
conn->proto.ldapc = li;
|
||||
connkeep(conn, "OpenLDAP default");
|
||||
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;
|
||||
/* Clear the TLS upgraded flag */
|
||||
conn->bits.tls_upgraded = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user