1: 5853d79e0d4 ! 1: e51f717e07c Split PGOAUTHDEBUG=UNSAFE into multiple options
@@ Commit message
Split PGOAUTHDEBUG=UNSAFE into multiple options
## doc/src/sgml/libpq.sgml ##
-@@ doc/src/sgml/libpq.sgml: typedef struct PGoauthBearerRequest
-
Debugging and Developer Settings
+@@ doc/src/sgml/libpq.sgml: typedef struct
+
- A "dangerous debugging mode" may be enabled by setting the environment
@@ doc/src/sgml/libpq.sgml: typedef struct PGoauthBearerRequest
-
-
-
-- allows the system's trusted CA list to be completely replaced using the
-- PGOAUTHCAFILE environment variable
--
--
--
--
- prints HTTP traffic (containing several critical secrets) to standard
- error during the OAuth flow
-
@@ doc/src/sgml/libpq.sgml: typedef struct PGoauthBearerRequest
+
+
+
-+ custom-ca (unsafe)
-+
-+
-+ Allows the system's trusted CA list to be completely replaced using the
-+ PGOAUTHCAFILE environment variable. This can facilitate
-+ man-in-the-middle attacks when testing with self-signed certificates.
-+
-+
-+
-+
-+
+ fast-retry (safe)
+
+
@@ doc/src/sgml/libpq.sgml: typedef struct PGoauthBearerRequest
+
+
+
-+ Unsafe options (http, trace,
-+ custom-ca) require the UNSAFE: prefix.
++ Unsafe options (http, trace)
++ require the UNSAFE: prefix.
+ If unsafe options are specified without this prefix, a warning is printed
+ to standard error and that option is ignored. Other valid options in the
+ list continue to work. Safe options (fast-retry,
+ poll-counts, print-plugin-errors) can
+ be used without the prefix.
-+
+
+
+
+ Unrecognized option names will also trigger a warning and be ignored, while
+ valid options continue to work. This helps catch typos in the environment
+ variable configuration without breaking the debugging of valid options.
-
++
+
+
+ Examples:
+
+PGOAUTHDEBUG=fast-retry,poll-counts safe options only
+PGOAUTHDEBUG=UNSAFE:http,trace enable HTTP and traffic logging
-+PGOAUTHDEBUG=UNSAFE:http,custom-ca,poll-counts mix of unsafe and safe
++PGOAUTHDEBUG=UNSAFE:http,poll-counts mix of unsafe and safe
+PGOAUTHDEBUG=UNSAFE legacy; enables all options
+
+
@@ src/interfaces/libpq/meson.build
'fe-cancel.c',
## src/interfaces/libpq-oauth/Makefile ##
-@@ src/interfaces/libpq-oauth/Makefile: override CFLAGS += $(PTHREAD_CFLAGS)
+@@ src/interfaces/libpq-oauth/Makefile: override CPPFLAGS_SHLIB += -DUSE_PRIVATE_ENCODING_FUNCS
OBJS = \
$(WIN32RES)
@@ src/interfaces/libpq-oauth/Makefile: override CFLAGS += $(PTHREAD_CFLAGS)
oauth-utils.o \
+ fe-auth-oauth-debug_shlib.o
- oauth-utils.o: override CPPFLAGS += -DUSE_DYNAMIC_OAUTH
- oauth-curl_shlib.o: override CPPFLAGS_SHLIB += -DUSE_DYNAMIC_OAUTH
-+fe-auth-oauth-debug_shlib.o: override CPPFLAGS_SHLIB += -DUSE_DYNAMIC_OAUTH
-+
+ oauth-utils.o: override CPPFLAGS += $(CPPFLAGS_SHLIB)
+
+fe-auth-oauth-debug.o: $(libpq_srcdir)/fe-auth-oauth-debug.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@
+
-+fe-auth-oauth-debug_shlib.o: $(libpq_srcdir)/fe-auth-oauth-debug.c
++fe-auth-oauth-debug_shlib.o: $(libpq_srcdir)/fe-auth-oauth-debug.c fe-auth-oauth-debug.o
+ $(CC) $(CFLAGS) $(CFLAGS_SL) $(CPPFLAGS) $(CPPFLAGS_SHLIB) -c $< -o $@
-
++
# Add shlib-/stlib-specific objects.
$(shlib): override OBJS += $(OBJS_SHLIB)
+ $(shlib): $(OBJS_SHLIB)
## src/interfaces/libpq/Makefile ##
@@ src/interfaces/libpq/Makefile: OBJS = \
@@ src/interfaces/libpq/Makefile: OBJS = \
ifneq ($(with_ssl),no)
## 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"
+
@@ src/interfaces/libpq-oauth/oauth-utils.h: typedef enum
+ 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 oauth_debug_flags oauth_get_debug_flags(void);
extern int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending);
@@ src/interfaces/libpq/fe-auth-oauth.h: typedef struct
+ /* UNSAFE features - require UNSAFE: prefix */
+ bool http; /* allow HTTP (unencrypted) connections */
+ bool trace; /* log HTTP traffic (exposes secrets) */
-+ bool custom_ca; /* allow custom CA certificate file */
+
+ /* SAFE features - allowed without UNSAFE: prefix */
+ bool fast_retry; /* allow zero-second retry intervals */
@@ src/interfaces/libpq/fe-auth-oauth.h: typedef struct
extern void pqClearOAuthToken(PGconn *conn);
-extern bool oauth_unsafe_debugging_enabled(void);
+extern oauth_debug_flags oauth_get_debug_flags(void);
- extern bool use_builtin_flow(PGconn *conn, fe_oauth_state *state);
/* Mechanisms in fe-auth-oauth.c */
+ extern const pg_fe_sasl_mech pg_oauth_mech;
## src/interfaces/libpq-oauth/oauth-curl.c ##
@@ src/interfaces/libpq-oauth/oauth-curl.c: struct async_ctx
@@ src/interfaces/libpq-oauth/oauth-curl.c: setup_curl_handles(struct async_ctx *ac
protos = unsafe;
CHECK_SETOPT(actx, popt, protos, return false);
-@@ src/interfaces/libpq-oauth/oauth-curl.c: setup_curl_handles(struct async_ctx *actx)
- * the flow to work at all, so any changes to the roots are likely to be
- * done system-wide.
- */
-- if (actx->debugging)
-+ if (actx->debug_flags.custom_ca)
- {
- const char *env;
-
@@ src/interfaces/libpq-oauth/oauth-curl.c: check_for_device_flow(struct async_ctx *actx)
* decent time to bail out if we're not using HTTPS for the endpoints
* we'll use for the flow.
@@ src/interfaces/libpq-oauth/oauth-curl.c: check_for_device_flow(struct async_ctx
{
if (pg_strncasecmp(provider->device_authorization_endpoint,
HTTPS_SCHEME, strlen(HTTPS_SCHEME)) != 0)
-@@ src/interfaces/libpq-oauth/oauth-curl.c: pg_fe_run_oauth_flow_impl(PGconn *conn)
- actx->mux = PGINVALID_SOCKET;
- actx->timerfd = -1;
-
-- /* Should we enable unsafe features? */
-- actx->debugging = oauth_unsafe_debugging_enabled();
-+ /* Parse debug flags from environment */
-+ actx->debug_flags = oauth_get_debug_flags();
-
- state->async_ctx = actx;
-
-@@ src/interfaces/libpq-oauth/oauth-curl.c: pg_fe_run_oauth_flow(PGconn *conn)
- actx = state->async_ctx;
- Assert(actx || result == PGRES_POLLING_FAILED);
-
-- if (actx && actx->debugging)
+@@ src/interfaces/libpq-oauth/oauth-curl.c: pg_fe_run_oauth_flow(PGconn *conn, struct PGoauthBearerRequest *request,
+ * drain_timer_events(), when we're in debug mode, track the total number
+ * of calls to this function and print that at the end of the flow.
+ */
+- if (actx->debugging)
+ if (actx && actx->debug_flags.poll_counts)
{
actx->dbg_num_calls++;
if (result == PGRES_POLLING_OK || result == PGRES_POLLING_FAILED)
+@@ src/interfaces/libpq-oauth/oauth-curl.c: pg_start_oauthbearer(PGconn *conn, PGoauthBearerRequestV2 *request)
+ * Now finish filling in the actx.
+ */
+
+- /* Should we enable unsafe features? */
+- actx->debugging = oauth_unsafe_debugging_enabled();
++ /* Parse debug flags from the environment. */
++ actx->debug_flags = oauth_get_debug_flags();
+
+ initPQExpBuffer(&actx->work_data);
+ initPQExpBuffer(&actx->errbuf);
## src/interfaces/libpq-oauth/oauth-utils.c ##
@@ src/interfaces/libpq-oauth/oauth-utils.c: libpq_gettext(const char *msgid)
@@ src/interfaces/libpq-oauth/test-oauth-curl.c: init_test_actx(void)
- actx->debugging = true;
+ actx->debug_flags.http = true;
+ actx->debug_flags.trace = true;
-+ actx->debug_flags.custom_ca = true;
-+ actx->debug_flags.issuer_mismatch = true;
+ actx->debug_flags.fast_retry = true;
+ actx->debug_flags.poll_counts = true;
+ actx->debug_flags.print_plugin_errors = true;
@@ src/interfaces/libpq/fe-auth-oauth-debug.c (new)
+ *is_unsafe = true;
+ return true;
+ }
-+ else if (strcmp(option, "custom-ca") == 0)
-+ {
-+ flags->custom_ca = true;
-+ *is_unsafe = true;
-+ return true;
-+ }
+ /* Safe options */
+ else if (strcmp(option, "fast-retry") == 0)
+ {
@@ src/interfaces/libpq/fe-auth-oauth-debug.c (new)
+ {
+ flags.http = true;
+ flags.trace = true;
-+ flags.custom_ca = true;
+ flags.fast_retry = true;
+ flags.poll_counts = true;
+ flags.print_plugin_errors = true;
@@ src/interfaces/libpq/fe-auth-oauth.c: issuer_from_well_known_uri(PGconn *conn, c
&& pg_strncasecmp(wkuri, HTTP_SCHEME, strlen(HTTP_SCHEME)) == 0)
{
/* Allow http:// for testing only. */
-@@ src/interfaces/libpq/fe-auth-oauth.c: use_builtin_flow(PGconn *conn, fe_oauth_state *state)
+@@ src/interfaces/libpq/fe-auth-oauth.c: use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re
*
* Note that POSIX dlerror() isn't guaranteed to be threadsafe.
*/
@@ src/interfaces/libpq/fe-auth-oauth.c: use_builtin_flow(PGconn *conn, fe_oauth_st
+ if (oauth_get_debug_flags().print_plugin_errors)
fprintf(stderr, "failed dlopen for libpq-oauth: %s\n", dlerror());
- return false;
-@@ src/interfaces/libpq/fe-auth-oauth.c: use_builtin_flow(PGconn *conn, fe_oauth_state *state)
- * This is more of an error condition than the one above, but due to
- * the dlerror() threadsafety issue, lock it behind PGOAUTHDEBUG too.
+ return 0;
+@@ src/interfaces/libpq/fe-auth-oauth.c: use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re
+ * cause is still locked behind PGOAUTHDEBUG due to the dlerror()
+ * threadsafety issue.
*/
- if (oauth_unsafe_debugging_enabled())
+ if (oauth_get_debug_flags().print_plugin_errors)
2: 5fc7a19876b ! 2: 933f6432f87 Add new PGOAUTHDEBUG option: issuer-mismatch
@@ doc/src/sgml/libpq.sgml: PGOAUTHDEBUG=UNSAFE legacy format; e
fast-retry (safe)
@@ doc/src/sgml/libpq.sgml: PGOAUTHDEBUG=UNSAFE legacy format; enables all options
- Unsafe options (http, trace,
-- custom-ca) require the UNSAFE: prefix.
-+ custom-ca, issuer-mismatch) require the UNSAFE: prefix.
+- Unsafe options (http, trace)
+- require the UNSAFE: prefix.
++ Unsafe options (http, trace,
++ issuer-mismatch) require the UNSAFE: prefix.
If unsafe options are specified without this prefix, a warning is printed
to standard error and that option is ignored. Other valid options in the
list continue to work. Safe options (fast-retry,
## src/interfaces/libpq/fe-auth-oauth.h ##
@@ src/interfaces/libpq/fe-auth-oauth.h: typedef struct oauth_debug_flags
+ /* UNSAFE features - require UNSAFE: prefix */
bool http; /* allow HTTP (unencrypted) connections */
bool trace; /* log HTTP traffic (exposes secrets) */
- bool custom_ca; /* allow custom CA certificate file */
+ bool issuer_mismatch; /* tolerate issuer mismatch */
/* SAFE features - allowed without UNSAFE: prefix */
@@ src/interfaces/libpq-oauth/oauth-curl.c: check_issuer(struct async_ctx *actx, PG
return true;
+ ## src/interfaces/libpq-oauth/test-oauth-curl.c ##
+@@ src/interfaces/libpq-oauth/test-oauth-curl.c: init_test_actx(void)
+ actx->timerfd = -1;
+ actx->debug_flags.http = true;
+ actx->debug_flags.trace = true;
++ actx->debug_flags.issuer_mismatch = true;
+ actx->debug_flags.fast_retry = true;
+ actx->debug_flags.poll_counts = true;
+ actx->debug_flags.print_plugin_errors = true;
+
## src/interfaces/libpq/fe-auth-oauth-debug.c ##
@@ src/interfaces/libpq/fe-auth-oauth-debug.c: parse_debug_option(const char *option, oauth_debug_flags *flags, bool *is_unsafe
*is_unsafe = true;
@@ src/interfaces/libpq/fe-auth-oauth-debug.c: parse_debug_option(const char *optio
else if (strcmp(option, "fast-retry") == 0)
{
@@ src/interfaces/libpq/fe-auth-oauth-debug.c: oauth_get_debug_flags(void)
+ {
flags.http = true;
flags.trace = true;
- flags.custom_ca = true;
+ flags.issuer_mismatch = true;
flags.fast_retry = true;
flags.poll_counts = true;