diff options
author | Daniel Gustafsson <dgustafsson@postgresql.org> | 2025-02-06 22:19:21 +0100 |
---|---|---|
committer | Daniel Gustafsson <dgustafsson@postgresql.org> | 2025-02-06 22:19:21 +0100 |
commit | a99a32e43ed72bd4fdb0950d2359fa4aa50fab76 (patch) | |
tree | 0239205eb286521400354bec2baf7b800f62473e /src/interfaces/libpq/fe-misc.c | |
parent | 44ec09575145e908be8130de701e5c83995d1abe (diff) | |
download | postgresql-a99a32e43ed72bd4fdb0950d2359fa4aa50fab76.tar.gz postgresql-a99a32e43ed72bd4fdb0950d2359fa4aa50fab76.zip |
libpq: Handle asynchronous actions during SASL
This adds the ability for a SASL mechanism to signal PQconnectPoll()
that some arbitrary work, external to the Postgres connection, is
required for authentication to continue. There is no consumer for
this capability as part of this commit, it is infrastructure which
is required for future work on supporting the OAUTHBEARER mechanism.
To ensure that threads are not blocked waiting for the SASL mechanism
to make long-running calls, the mechanism communicates with the top-
level client via the "altsock": a file or socket descriptor, opaque to
this layer of libpq, which is signaled when work is ready to be done
again. The altsock temporarily replaces the regular connection
descriptor, so existing PQsocket() clients should continue to operate
correctly using their existing polling implementations.
For a mechanism to use this it should set an authentication callback,
conn->async_auth(), and a cleanup callback, conn->cleanup_async_auth(),
and return SASL_ASYNC during the exchange. It should then assign
conn->altsock during the first call to async_auth(). When the cleanup
callback is called, either because authentication has succeeded or
because the connection is being dropped, the altsock must be released
and disconnected from the PGconn object.
This was extracted from the larger OAUTHBEARER patchset which has
been developed, and reviewed by many, over several years and it is
thus likely that some reviewer credit of much earlier versions has
been accidentally omitted.
Author: Jacob Champion <jacob.champion@enterprisedb.com>
Reviewed-by: Daniel Gustafsson <daniel@yesql.se>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Reviewed-by: Antonin Houska <ah@cybertec.at>
Discussion: https://postgr.es/m/CAOYmi+kJqzo6XsR9TEhvVfeVNQ-TyFM5LATypm9yoQVYk=4Wrw@mail.gmail.com
Diffstat (limited to 'src/interfaces/libpq/fe-misc.c')
-rw-r--r-- | src/interfaces/libpq/fe-misc.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index 2c60eb5b569..d78445c70af 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -1049,34 +1049,43 @@ pqWriteReady(PGconn *conn) * or both. Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. * - * If SSL is in use, the SSL buffer is checked prior to checking the socket - * for read data directly. + * If an altsock is set for asynchronous authentication, that will be used in + * preference to the "server" socket. Otherwise, if SSL is in use, the SSL + * buffer is checked prior to checking the socket for read data directly. */ static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, pg_usec_time_t end_time) { int result; + pgsocket sock; if (!conn) return -1; - if (conn->sock == PGINVALID_SOCKET) + + if (conn->altsock != PGINVALID_SOCKET) + sock = conn->altsock; + else { - libpq_append_conn_error(conn, "invalid socket"); - return -1; - } + sock = conn->sock; + if (sock == PGINVALID_SOCKET) + { + libpq_append_conn_error(conn, "invalid socket"); + return -1; + } #ifdef USE_SSL - /* Check for SSL library buffering read bytes */ - if (forRead && conn->ssl_in_use && pgtls_read_pending(conn)) - { - /* short-circuit the select */ - return 1; - } + /* Check for SSL library buffering read bytes */ + if (forRead && conn->ssl_in_use && pgtls_read_pending(conn)) + { + /* short-circuit the select */ + return 1; + } #endif + } /* We will retry as long as we get EINTR */ do - result = PQsocketPoll(conn->sock, forRead, forWrite, end_time); + result = PQsocketPoll(sock, forRead, forWrite, end_time); while (result < 0 && SOCK_ERRNO == EINTR); if (result < 0) |