From 39d1976b7f709a516e3243338ebc0443bdd8d56d Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Thu, 4 Dec 2025 00:14:20 +0100
Subject: [PATCH] ldap: call ldap_init() before setting the options

Closes #19830

CVE: CVE-2025-14017
Upstream-Status: Backport [https://github.com/curl/curl/commit/39d1976b7f709a516e3243338ebc0443bdd8d56d]
Signed-off-by: Peter Marko <peter.marko@siemens.com>
---
 lib/ldap.c | 49 +++++++++++++++++++------------------------------
 1 file changed, 19 insertions(+), 30 deletions(-)

diff --git a/lib/ldap.c b/lib/ldap.c
index 63b2cbc414..0911a9239a 100644
--- a/lib/ldap.c
+++ b/lib/ldap.c
@@ -333,16 +333,29 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
     passwd = conn->passwd;
   }
 
+#ifdef USE_WIN32_LDAP
+  if(ldap_ssl)
+    server = ldap_sslinit(host, (int)conn->port, 1);
+  else
+#else
+    server = ldap_init(host, (int)conn->port);
+#endif
+  if(!server) {
+    failf(data, "LDAP local: Cannot connect to %s:%ld",
+          conn->host.dispname, conn->port);
+    result = CURLE_COULDNT_CONNECT;
+    goto quit;
+  }
+
 #ifdef LDAP_OPT_NETWORK_TIMEOUT
-  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
+  ldap_set_option(server, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
 #endif
-  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+  ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
 
   if(ldap_ssl) {
 #ifdef HAVE_LDAP_SSL
 #ifdef USE_WIN32_LDAP
     /* Win32 LDAP SDK doesn't support insecure mode without CA! */
-    server = ldap_sslinit(host, (int)conn->port, 1);
     ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
 #else
     int ldap_option;
@@ -410,7 +423,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
         goto quit;
       }
       infof(data, "LDAP local: using PEM CA cert: %s", ldap_ca);
-      rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
+      rc = ldap_set_option(server, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
       if(rc != LDAP_SUCCESS) {
         failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
                 ldap_err2string(rc));
@@ -422,20 +435,13 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
     else
       ldap_option = LDAP_OPT_X_TLS_NEVER;
 
-    rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
+    rc = ldap_set_option(server, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
     if(rc != LDAP_SUCCESS) {
       failf(data, "LDAP local: ERROR setting cert verify mode: %s",
               ldap_err2string(rc));
       result = CURLE_SSL_CERTPROBLEM;
       goto quit;
     }
-    server = ldap_init(host, (int)conn->port);
-    if(!server) {
-      failf(data, "LDAP local: Cannot connect to %s:%ld",
-            conn->host.dispname, conn->port);
-      result = CURLE_COULDNT_CONNECT;
-      goto quit;
-    }
     ldap_option = LDAP_OPT_X_TLS_HARD;
     rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
     if(rc != LDAP_SUCCESS) {
@@ -444,15 +450,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       result = CURLE_SSL_CERTPROBLEM;
       goto quit;
     }
-/*
-    rc = ldap_start_tls_s(server, NULL, NULL);
-    if(rc != LDAP_SUCCESS) {
-      failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
-              ldap_err2string(rc));
-      result = CURLE_SSL_CERTPROBLEM;
-      goto quit;
-    }
-*/
 #else
     /* we should probably never come up to here since configure
        should check in first place if we can support LDAP SSL/TLS */
@@ -469,15 +466,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
     result = CURLE_NOT_BUILT_IN;
     goto quit;
   }
-  else {
-    server = ldap_init(host, (int)conn->port);
-    if(!server) {
-      failf(data, "LDAP local: Cannot connect to %s:%ld",
-            conn->host.dispname, conn->port);
-      result = CURLE_COULDNT_CONNECT;
-      goto quit;
-    }
-  }
+
 #ifdef USE_WIN32_LDAP
   ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
   rc = ldap_win_bind(data, server, user, passwd);
