From: Jacob Champion Date: Tue, 31 Mar 2026 18:47:26 +0000 (-0700) Subject: libpq: Allow developers to reimplement libpq-oauth X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=09532b4040ed4c313351366166f55e810f152d6a;p=thirdparty%2Fpostgresql.git libpq: Allow developers to reimplement libpq-oauth For PG19, since we won't have the ability to officially switch out flow plugins, relax the flow-loading code to not require the internal init function. Modules that don't have one will be treated as custom user flows in error messages. This will let bleeding-edge developers more easily test out the API and provide feedback for PG20, by telling the runtime linker to find a different libpq-oauth. It remains undocumented for end users. Reviewed-by: Zsolt Parragi Reviewed-by: Chao Li Discussion: https://postgr.es/m/CAOYmi%2BmrGg%2Bn_X2MOLgeWcj3v_M00gR8uz_D7mM8z%3DdX1JYVbg%40mail.gmail.com --- diff --git a/src/interfaces/libpq/fe-auth-oauth.c b/src/interfaces/libpq/fe-auth-oauth.c index 10e995f2c4d..ac03d1d4f9d 100644 --- a/src/interfaces/libpq/fe-auth-oauth.c +++ b/src/interfaces/libpq/fe-auth-oauth.c @@ -890,8 +890,8 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re "libpq-oauth" DLSUFFIX; #endif - state->builtin_flow = dlopen(module_name, RTLD_NOW | RTLD_LOCAL); - if (!state->builtin_flow) + state->flow_module = dlopen(module_name, RTLD_NOW | RTLD_LOCAL); + if (!state->flow_module) { /* * For end users, this probably isn't an error condition, it just @@ -906,8 +906,16 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re return 0; } - if ((init = dlsym(state->builtin_flow, "libpq_oauth_init")) == NULL - || (start_flow = dlsym(state->builtin_flow, "pg_start_oauthbearer")) == NULL) + /* + * Our libpq-oauth.so provides a special initialization function for libpq + * integration. If we don't find this, assume that a custom module is in + * use instead. + */ + init = dlsym(state->flow_module, "libpq_oauth_init"); + if (!init) + state->builtin = false; /* adjust our error messages */ + + if ((start_flow = dlsym(state->flow_module, "pg_start_oauthbearer")) == NULL) { /* * This is more of an error condition than the one above, but the @@ -917,8 +925,8 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re if (oauth_unsafe_debugging_enabled()) fprintf(stderr, "failed dlsym for libpq-oauth: %s\n", dlerror()); - dlclose(state->builtin_flow); - state->builtin_flow = NULL; + dlclose(state->flow_module); + state->flow_module = NULL; request->error = libpq_gettext("could not find entry point for libpq-oauth"); return -1; @@ -929,39 +937,42 @@ use_builtin_flow(PGconn *conn, fe_oauth_state *state, PGoauthBearerRequestV2 *re * permanently. */ - /* - * We need to inject necessary function pointers into the module. This - * only needs to be done once -- even if the pointers are constant, - * assigning them while another thread is executing the flows feels like - * tempting fate. - */ - if ((lockerr = pthread_mutex_lock(&init_mutex)) != 0) + if (init) { - /* Should not happen... but don't continue if it does. */ - Assert(false); + /* + * We need to inject necessary function pointers into the module. This + * only needs to be done once -- even if the pointers are constant, + * assigning them while another thread is executing the flows feels + * like tempting fate. + */ + if ((lockerr = pthread_mutex_lock(&init_mutex)) != 0) + { + /* Should not happen... but don't continue if it does. */ + Assert(false); - appendPQExpBuffer(&conn->errorMessage, - "use_builtin_flow: failed to lock mutex (%d)\n", - lockerr); + appendPQExpBuffer(&conn->errorMessage, + "use_builtin_flow: failed to lock mutex (%d)\n", + lockerr); - request->error = ""; /* satisfy report_flow_error() */ - return -1; - } + request->error = ""; /* satisfy report_flow_error() */ + return -1; + } - if (!initialized) - { - init( + if (!initialized) + { + init( #ifdef ENABLE_NLS - libpq_gettext + libpq_gettext #else - NULL + NULL #endif - ); + ); - initialized = true; - } + initialized = true; + } - pthread_mutex_unlock(&init_mutex); + pthread_mutex_unlock(&init_mutex); + } return (start_flow(conn, request) == 0) ? 1 : -1; } diff --git a/src/interfaces/libpq/fe-auth-oauth.h b/src/interfaces/libpq/fe-auth-oauth.h index 2b22d23ffde..872f5df551a 100644 --- a/src/interfaces/libpq/fe-auth-oauth.h +++ b/src/interfaces/libpq/fe-auth-oauth.h @@ -36,7 +36,7 @@ typedef struct bool v1; bool builtin; - void *builtin_flow; + void *flow_module; } fe_oauth_state; extern void pqClearOAuthToken(PGconn *conn);