ldap: detect version of "legacy" LDAP

Legacy LDAP means an OpenLDAP-compatible implementation
without the private API `ldap_init_fd()` introduced in OpenLDAP
2.4.6+ (2007-10-31), and not WinLDAP.

One known example is Apple's LDAP build, which is based on
OpenLDAP 2.4.28 (2011-11-25), without providing this private API.

The version query API was introduced around 1998-1999, before
the minimum (2.0 2000-08-01) required by curl.

Follow-up to 3e2a946926853608d67805bd9f4a58345fff364a #19808
Closes #19832
diff --git a/lib/ldap.c b/lib/ldap.c
index 6104ff2..92cfa39 100644
--- a/lib/ldap.c
+++ b/lib/ldap.c
@@ -1029,7 +1029,27 @@
 #ifdef USE_WIN32_LDAP
   curl_msnprintf(buf, bufsz, "WinLDAP");
 #else
-  curl_msnprintf(buf, bufsz, "LDAP/1");
+#ifdef __APPLE__
+  static const char *flavor = "/Apple";
+#else
+  static const char *flavor = "";
+#endif
+  LDAPAPIInfo api;
+  api.ldapai_info_version = LDAP_API_INFO_VERSION;
+
+  if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
+    unsigned int patch = (unsigned int)(api.ldapai_vendor_version % 100);
+    unsigned int major = (unsigned int)(api.ldapai_vendor_version / 10000);
+    unsigned int minor =
+      (((unsigned int)api.ldapai_vendor_version - major * 10000)
+       - patch) / 100;
+    curl_msnprintf(buf, bufsz, "%s/%u.%u.%u%s",
+                   api.ldapai_vendor_name, major, minor, patch, flavor);
+    ldap_memfree(api.ldapai_vendor_name);
+    ber_memvfree((void **)api.ldapai_extensions);
+  }
+  else
+    curl_msnprintf(buf, bufsz, "LDAP/1");
 #endif
 }