]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
openldap: several minor improvements
authorPatrick Monnerat <patrick@monnerat.net>
Tue, 14 Dec 2021 14:42:47 +0000 (15:42 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 15 Dec 2021 07:07:53 +0000 (08:07 +0100)
- 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

docs/libcurl/opts/CURLINFO_RESPONSE_CODE.3
lib/openldap.c

index 66b9f3719ada6bb0fb704ebb9f0baa97f6094bc9..628b438bdd0740f34948837897b7ee2c59af8284 100644 (file)
@@ -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"
index f5483f4782b3f25615966993c291391c538cfb3d..0ffb6a36a2acf3a4764b954c4ddd0d2666187fa3 100644 (file)
@@ -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);