From 595362ef2c16bbca684a5d8e9fd6c416894444b0 Mon Sep 17 00:00:00 2001
From: Jacob Champion <jacob.champion@enterprisedb.com>
Date: Tue, 4 Feb 2025 11:37:44 -0800
Subject: [PATCH v47 05/11] fixup! Add OAUTHBEARER SASL mechanism

---
 config/programs.m4                        | 23 ++++++++++
 configure                                 | 53 +++++++++++++++++++++++
 meson.build                               | 34 +++++++++++++++
 src/interfaces/libpq/fe-auth-oauth-curl.c | 15 ++-----
 4 files changed, 114 insertions(+), 11 deletions(-)

diff --git a/config/programs.m4 b/config/programs.m4
index 86a3750f9e5..ead427046f5 100644
--- a/config/programs.m4
+++ b/config/programs.m4
@@ -315,4 +315,27 @@ AC_DEFUN([PGAC_CHECK_LIBCURL],
     AC_DEFINE(HAVE_THREADSAFE_CURL_GLOBAL_INIT, 1,
               [Define to 1 if curl_global_init() is guaranteed to be threadsafe.])
   fi
+
+  # Warn if a thread-friendly DNS resolver isn't built.
+  AC_CACHE_CHECK([for curl support for asynchronous DNS], [pgac_cv__libcurl_async_dns],
+  [AC_RUN_IFELSE([AC_LANG_PROGRAM([
+#include <curl/curl.h>
+],[
+    curl_version_info_data *info;
+
+    if (curl_global_init(CURL_GLOBAL_ALL))
+        return -1;
+
+    info = curl_version_info(CURLVERSION_NOW);
+    return (info->features & CURL_VERSION_ASYNCHDNS) ? 0 : 1;
+])],
+  [pgac_cv__libcurl_async_dns=yes],
+  [pgac_cv__libcurl_async_dns=no],
+  [pgac_cv__libcurl_async_dns=unknown])])
+  if test x"$pgac_cv__libcurl_async_dns" != xyes ; then
+    AC_MSG_WARN([
+*** The installed version of libcurl does not support asynchronous DNS
+*** lookups. Connection timeouts will not be honored during DNS resolution,
+*** which may lead to hangs in client programs.])
+  fi
 ])# PGAC_CHECK_LIBCURL
diff --git a/configure b/configure
index 33422d24112..93fddd69981 100755
--- a/configure
+++ b/configure
@@ -12493,6 +12493,59 @@ $as_echo "#define HAVE_THREADSAFE_CURL_GLOBAL_INIT 1" >>confdefs.h
 
   fi
 
+  # Warn if a thread-friendly DNS resolver isn't built.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for curl support for asynchronous DNS" >&5
+$as_echo_n "checking for curl support for asynchronous DNS... " >&6; }
+if ${pgac_cv__libcurl_async_dns+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  pgac_cv__libcurl_async_dns=unknown
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <curl/curl.h>
+
+int
+main ()
+{
+
+    curl_version_info_data *info;
+
+    if (curl_global_init(CURL_GLOBAL_ALL))
+        return -1;
+
+    info = curl_version_info(CURLVERSION_NOW);
+    return (info->features & CURL_VERSION_ASYNCHDNS) ? 0 : 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  pgac_cv__libcurl_async_dns=yes
+else
+  pgac_cv__libcurl_async_dns=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv__libcurl_async_dns" >&5
+$as_echo "$pgac_cv__libcurl_async_dns" >&6; }
+  if test x"$pgac_cv__libcurl_async_dns" != xyes ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+*** The installed version of libcurl does not support asynchronous DNS
+*** lookups. Connection timeouts will not be honored during DNS resolution,
+*** which may lead to hangs in client programs." >&5
+$as_echo "$as_me: WARNING:
+*** The installed version of libcurl does not support asynchronous DNS
+*** lookups. Connection timeouts will not be honored during DNS resolution,
+*** which may lead to hangs in client programs." >&2;}
+  fi
+
 fi
 
 if test "$with_gssapi" = yes ; then
diff --git a/meson.build b/meson.build
index 80a6b1d57d6..96e5f0f6434 100644
--- a/meson.build
+++ b/meson.build
@@ -907,6 +907,40 @@ if not libcurlopt.disabled()
     if libcurl_threadsafe_init
       cdata.set('HAVE_THREADSAFE_CURL_GLOBAL_INIT', 1)
     endif
+
+    # Warn if a thread-friendly DNS resolver isn't built.
+    libcurl_async_dns = false
+
+    if not meson.is_cross_build()
+      r = cc.run('''
+        #include <curl/curl.h>
+
+        int main(void)
+        {
+            curl_version_info_data *info;
+
+            if (curl_global_init(CURL_GLOBAL_ALL))
+                return -1;
+
+            info = curl_version_info(CURLVERSION_NOW);
+            return (info->features & CURL_VERSION_ASYNCHDNS) ? 0 : 1;
+        }''',
+        name: 'test for curl support for asynchronous DNS',
+        dependencies: libcurl,
+      )
+
+      assert(r.compiled())
+      if r.returncode() == 0
+        libcurl_async_dns = true
+      endif
+    endif
+
+    if not libcurl_async_dns
+      warning('''
+*** The installed version of libcurl does not support asynchronous DNS
+*** lookups. Connection timeouts will not be honored during DNS resolution,
+*** which may lead to hangs in client programs.''')
+    endif
   endif
 
 else
diff --git a/src/interfaces/libpq/fe-auth-oauth-curl.c b/src/interfaces/libpq/fe-auth-oauth-curl.c
index dc47a7bdf11..b6255834f00 100644
--- a/src/interfaces/libpq/fe-auth-oauth-curl.c
+++ b/src/interfaces/libpq/fe-auth-oauth-curl.c
@@ -1339,8 +1339,6 @@ debug_callback(CURL *handle, curl_infotype type, char *data, size_t size,
 static bool
 setup_curl_handles(struct async_ctx *actx)
 {
-	curl_version_info_data *curl_info;
-
 	/*
 	 * Create our multi handle. This encapsulates the entire conversation with
 	 * libcurl for this connection.
@@ -1353,11 +1351,6 @@ setup_curl_handles(struct async_ctx *actx)
 		return false;
 	}
 
-	/*
-	 * Extract information about the libcurl we are linked against.
-	 */
-	curl_info = curl_version_info(CURLVERSION_NOW);
-
 	/*
 	 * The multi handle tells us what to wait on using two callbacks. These
 	 * will manipulate actx->mux as needed.
@@ -1382,12 +1375,12 @@ setup_curl_handles(struct async_ctx *actx)
 	 * Multi-threaded applications must set CURLOPT_NOSIGNAL. This requires us
 	 * to handle the possibility of SIGPIPE ourselves using pq_block_sigpipe;
 	 * see pg_fe_run_oauth_flow().
+	 *
+	 * NB: If libcurl is not built against a friendly DNS resolver (c-ares or
+	 * threaded), setting this option prevents DNS lookups from timing out
+	 * correctly. We warn about this situation at configure time.
 	 */
 	CHECK_SETOPT(actx, CURLOPT_NOSIGNAL, 1L, return false);
-	if (!curl_info->ares_num)
-	{
-		/* No alternative resolver, TODO: warn about timeouts */
-	}
 
 	if (actx->debugging)
 	{
-- 
2.34.1

