1/*-------------------------------------------------------------------------
5 * "Glue" helpers providing a copy of some internal APIs from libpq. At
6 * some point in the future, we might be able to deduplicate.
8 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/interfaces/libpq-oauth/oauth-utils.c
14 *-------------------------------------------------------------------------
23#ifndef USE_DYNAMIC_OAUTH
24#error oauth-utils.c is not supported in static builds
28#error do not rely on libpq-int.h in dynamic builds of libpq-oauth
32 * Function pointers set by libpq_oauth_init().
50 * Initializes libpq-oauth by setting necessary callbacks.
52 * The current implementation relies on the following private implementation
55 * - pg_g_threadlock: protects libcurl initialization if the underlying Curl
56 * installation is not threadsafe
58 * - libpq_gettext: translates error messages using libpq's message domain
60 * The implementation also needs access to several members of the PGconn struct,
61 * which are not guaranteed to stay in place across minor versions. Accessors
62 * (named conn_*) and mutators (named set_conn_*) are injected here.
67 conn_errorMessage_func errmsg_impl,
68 conn_oauth_client_id_func clientid_impl,
69 conn_oauth_client_secret_func clientsecret_impl,
70 conn_oauth_discovery_uri_func discoveryuri_impl,
71 conn_oauth_issuer_id_func issuerid_impl,
72 conn_oauth_scope_func scope_impl,
73 conn_sasl_state_func saslstate_impl,
74 set_conn_altsock_func setaltsock_impl,
75 set_conn_oauth_token_func settoken_impl)
91 * Append a formatted string to the error message buffer of the given
92 * connection, after translating it. This is a copy of libpq's internal API.
97 int save_errno = errno;
102 Assert(fmt[strlen(fmt) - 1] !=
'\n');
105 return;
/* already failed */
107 /* Loop in case we have to retry after enlarging the buffer. */
122 * A shim that defers to the actual libpq_gettext().
130 * Possible if the libpq build didn't enable NLS but the libpq-oauth
131 * build did. That's an odd mismatch, but we can handle it.
133 * Note that callers of libpq_gettext() have to treat the return value
134 * as if it were const, because builds without NLS simply pass through
143#endif /* ENABLE_NLS */
146 * Returns true if the PGOAUTHDEBUG=UNSAFE flag is set in the environment.
151 const char *env = getenv(
"PGOAUTHDEBUG");
153 return (env && strcmp(env,
"UNSAFE") == 0);
157 * Duplicate SOCK_ERRNO* definitions from libpq-int.h, for use by
158 * pq_block/reset_sigpipe().
161#define SOCK_ERRNO (WSAGetLastError())
162#define SOCK_ERRNO_SET(e) WSASetLastError(e)
164 #define SOCK_ERRNO errno
165 #define SOCK_ERRNO_SET(e) (errno = (e))
169 * Block SIGPIPE for this thread. This is a copy of libpq's internal API.
174 sigset_t sigpipe_sigset;
177 sigemptyset(&sigpipe_sigset);
178 sigaddset(&sigpipe_sigset,
SIGPIPE);
180 /* Block SIGPIPE and save previous mask for later reset */
181 SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset));
185 /* We can have a pending SIGPIPE only if it was blocked before */
186 if (sigismember(osigset,
SIGPIPE))
188 /* Is there a pending SIGPIPE? */
189 if (sigpending(&sigset) != 0)
192 if (sigismember(&sigset,
SIGPIPE))
193 *sigpipe_pending =
true;
195 *sigpipe_pending =
false;
198 *sigpipe_pending =
false;
204 * Discard any pending SIGPIPE and reset the signal mask. This is a copy of
205 * libpq's internal API.
214 /* Clear SIGPIPE only if none was pending */
215 if (got_epipe && !sigpipe_pending)
217 if (sigpending(&sigset) == 0 &&
220 sigset_t sigpipe_sigset;
222 sigemptyset(&sigpipe_sigset);
223 sigaddset(&sigpipe_sigset,
SIGPIPE);
225 sigwait(&sigpipe_sigset, &signo);
229 /* Restore saved block mask */
230 pthread_sigmask(SIG_SETMASK, osigset, NULL);
#define unconstify(underlying_type, expr)
Assert(PointerIsAligned(start, uint64))
void(* pgthreadlock_t)(int acquire)
set_conn_oauth_token_func set_conn_oauth_token
void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
conn_oauth_client_secret_func conn_oauth_client_secret
conn_sasl_state_func conn_sasl_state
conn_oauth_client_id_func conn_oauth_client_id
int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending)
void libpq_oauth_init(pgthreadlock_t threadlock_impl, libpq_gettext_func gettext_impl, conn_errorMessage_func errmsg_impl, conn_oauth_client_id_func clientid_impl, conn_oauth_client_secret_func clientsecret_impl, conn_oauth_discovery_uri_func discoveryuri_impl, conn_oauth_issuer_id_func issuerid_impl, conn_oauth_scope_func scope_impl, conn_sasl_state_func saslstate_impl, set_conn_altsock_func setaltsock_impl, set_conn_oauth_token_func settoken_impl)
conn_oauth_scope_func conn_oauth_scope
static libpq_gettext_func libpq_gettext_impl
pgthreadlock_t pg_g_threadlock
conn_oauth_issuer_id_func conn_oauth_issuer_id
set_conn_altsock_func set_conn_altsock
conn_oauth_discovery_uri_func conn_oauth_discovery_uri
#define SOCK_ERRNO_SET(e)
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
conn_errorMessage_func conn_errorMessage
bool oauth_unsafe_debugging_enabled(void)
char *(* libpq_gettext_func)(const char *msgid)
bool appendPQExpBufferVA(PQExpBuffer str, const char *fmt, va_list args)
void appendPQExpBufferChar(PQExpBuffer str, char ch)
#define PQExpBufferBroken(str)