aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq-oauth/oauth-utils.h
diff options
context:
space:
mode:
authorJacob Champion <jchampion@postgresql.org>2025-05-01 09:14:30 -0700
committerJacob Champion <jchampion@postgresql.org>2025-05-01 09:14:30 -0700
commitb0635bfda0535a7fc36cd11d10eecec4e2a96330 (patch)
tree13a39de30ba014942dc006a023102a6d9bf2fa51 /src/interfaces/libpq-oauth/oauth-utils.h
parenta3ef0b570c56f7bb15e4aa5caf0125fff92a557a (diff)
downloadpostgresql-b0635bfda0535a7fc36cd11d10eecec4e2a96330.tar.gz
postgresql-b0635bfda0535a7fc36cd11d10eecec4e2a96330.zip
oauth: Move the builtin flow into a separate module
The additional packaging footprint of the OAuth Curl dependency, as well as the existence of libcurl in the address space even if OAuth isn't ever used by a client, has raised some concerns. Split off this dependency into a separate loadable module called libpq-oauth. When configured using --with-libcurl, libpq.so searches for this new module via dlopen(). End users may choose not to install the libpq-oauth module, in which case the default flow is disabled. For static applications using libpq.a, the libpq-oauth staticlib is a mandatory link-time dependency for --with-libcurl builds. libpq.pc has been updated accordingly. The default flow relies on some libpq internals. Some of these can be safely duplicated (such as the SIGPIPE handlers), but others need to be shared between libpq and libpq-oauth for thread-safety. To avoid exporting these internals to all libpq clients forever, these dependencies are instead injected from the libpq side via an initialization function. This also lets libpq communicate the offsets of PGconn struct members to libpq-oauth, so that we can function without crashing if the module on the search path came from a different build of Postgres. (A minor-version upgrade could swap the libpq-oauth module out from under a long-running libpq client before it does its first load of the OAuth flow.) This ABI is considered "private". The module has no SONAME or version symlinks, and it's named libpq-oauth-<major>.so to avoid mixing and matching across Postgres versions. (Future improvements may promote this "OAuth flow plugin" to a first-class concept, at which point we would need a public API to replace this anyway.) Additionally, NLS support for error messages in b3f0be788a was incomplete, because the new error macros weren't being scanned by xgettext. Fix that now. Per request from Tom Lane and Bruce Momjian. Based on an initial patch by Daniel Gustafsson, who also contributed docs changes. The "bare" dlopen() concept came from Thomas Munro. Many people reviewed the design and implementation; thank you! Co-authored-by: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Andres Freund <andres@anarazel.de> Reviewed-by: Christoph Berg <myon@debian.org> Reviewed-by: Daniel Gustafsson <daniel@yesql.se> Reviewed-by: Jelte Fennema-Nio <postgres@jeltef.nl> Reviewed-by: Peter Eisentraut <peter@eisentraut.org> Reviewed-by: Wolfgang Walther <walther@technowledgy.de> Discussion: https://postgr.es/m/641687.1742360249%40sss.pgh.pa.us
Diffstat (limited to 'src/interfaces/libpq-oauth/oauth-utils.h')
-rw-r--r--src/interfaces/libpq-oauth/oauth-utils.h94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/interfaces/libpq-oauth/oauth-utils.h b/src/interfaces/libpq-oauth/oauth-utils.h
new file mode 100644
index 00000000000..f4ffefef208
--- /dev/null
+++ b/src/interfaces/libpq-oauth/oauth-utils.h
@@ -0,0 +1,94 @@
+/*-------------------------------------------------------------------------
+ *
+ * oauth-utils.h
+ *
+ * Definitions providing missing libpq internal APIs
+ *
+ * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/interfaces/libpq-oauth/oauth-utils.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef OAUTH_UTILS_H
+#define OAUTH_UTILS_H
+
+#include "fe-auth-oauth.h"
+#include "libpq-fe.h"
+#include "pqexpbuffer.h"
+
+/*
+ * A bank of callbacks to safely access members of PGconn, which are all passed
+ * to libpq_oauth_init() by libpq.
+ *
+ * Keep these aligned with the definitions in fe-auth-oauth.c as well as the
+ * static declarations in oauth-curl.c.
+ */
+#define DECLARE_GETTER(TYPE, MEMBER) \
+ typedef TYPE (*conn_ ## MEMBER ## _func) (PGconn *conn); \
+ extern conn_ ## MEMBER ## _func conn_ ## MEMBER;
+
+#define DECLARE_SETTER(TYPE, MEMBER) \
+ typedef void (*set_conn_ ## MEMBER ## _func) (PGconn *conn, TYPE val); \
+ extern set_conn_ ## MEMBER ## _func set_conn_ ## MEMBER;
+
+DECLARE_GETTER(PQExpBuffer, errorMessage);
+DECLARE_GETTER(char *, oauth_client_id);
+DECLARE_GETTER(char *, oauth_client_secret);
+DECLARE_GETTER(char *, oauth_discovery_uri);
+DECLARE_GETTER(char *, oauth_issuer_id);
+DECLARE_GETTER(char *, oauth_scope);
+DECLARE_GETTER(fe_oauth_state *, sasl_state);
+
+DECLARE_SETTER(pgsocket, altsock);
+DECLARE_SETTER(char *, oauth_token);
+
+#undef DECLARE_GETTER
+#undef DECLARE_SETTER
+
+typedef char *(*libpq_gettext_func) (const char *msgid);
+
+/* Initializes libpq-oauth. */
+extern PGDLLEXPORT void libpq_oauth_init(pgthreadlock_t threadlock,
+ 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);
+
+/*
+ * Duplicated APIs, copied from libpq (primarily libpq-int.h, which we cannot
+ * depend on here).
+ */
+
+typedef enum
+{
+ PG_BOOL_UNKNOWN = 0, /* Currently unknown */
+ PG_BOOL_YES, /* Yes (true) */
+ PG_BOOL_NO /* No (false) */
+} PGTernaryBool;
+
+extern void libpq_append_conn_error(PGconn *conn, const char *fmt,...) pg_attribute_printf(2, 3);
+extern bool oauth_unsafe_debugging_enabled(void);
+extern int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending);
+extern void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe);
+
+#ifdef ENABLE_NLS
+extern char *libpq_gettext(const char *msgid) pg_attribute_format_arg(1);
+#else
+#define libpq_gettext(x) (x)
+#endif
+
+extern pgthreadlock_t pg_g_threadlock;
+
+#define pglock_thread() pg_g_threadlock(true)
+#define pgunlock_thread() pg_g_threadlock(false)
+
+#endif /* OAUTH_UTILS_H */