22#if defined(HAVE_SYS_EPOLL_H)
24#include <sys/timerfd.h>
25#elif defined(HAVE_SYS_EVENT_H)
28#error libpq-oauth is not supported on this platform
36#ifdef USE_DYNAMIC_OAUTH
53#define conn_errorMessage(CONN) (&CONN->errorMessage)
54#define conn_oauth_client_id(CONN) (CONN->oauth_client_id)
55#define conn_oauth_client_secret(CONN) (CONN->oauth_client_secret)
56#define conn_oauth_discovery_uri(CONN) (CONN->oauth_discovery_uri)
57#define conn_oauth_issuer_id(CONN) (CONN->oauth_issuer_id)
58#define conn_oauth_scope(CONN) (CONN->oauth_scope)
59#define conn_sasl_state(CONN) (CONN->sasl_state)
61#define set_conn_altsock(CONN, VAL) do { CONN->altsock = VAL; } while (0)
62#define set_conn_oauth_token(CONN, VAL) do { CONN->oauth_token = VAL; } while (0)
67#if defined(USE_DYNAMIC_OAUTH) && defined(LIBPQ_INT_H)
68#error do not rely on libpq-int.h in dynamic builds of libpq-oauth
83#define MAX_OAUTH_RESPONSE_SIZE (256 * 1024)
97#define MAX_OAUTH_NESTING_LEVEL 16
303 CURLMcode
err = curl_multi_remove_handle(actx->
curlm, actx->
curl);
307 "libcurl easy handle removal failed: %s",
308 curl_multi_strerror(
err));
318 curl_easy_cleanup(actx->
curl);
323 CURLMcode
err = curl_multi_cleanup(actx->
curlm);
327 "libcurl multi handle cleanup failed: %s",
328 curl_multi_strerror(
err));
334 curl_slist_free_all(actx->
headers);
359 if (
state->async_ctx)
362 state->async_ctx = NULL;
374#define actx_error(ACTX, FMT, ...) \
375 appendPQExpBuffer(&(ACTX)->errbuf, libpq_gettext(FMT), ##__VA_ARGS__)
377#define actx_error_str(ACTX, S) \
378 appendPQExpBufferStr(&(ACTX)->errbuf, S)
385#define CHECK_MSETOPT(ACTX, OPT, VAL, FAILACTION) \
387 struct async_ctx *_actx = (ACTX); \
388 CURLMcode _setopterr = curl_multi_setopt(_actx->curlm, OPT, VAL); \
390 actx_error(_actx, "failed to set %s on OAuth connection: %s",\
391 #OPT, curl_multi_strerror(_setopterr)); \
396#define CHECK_SETOPT(ACTX, OPT, VAL, FAILACTION) \
398 struct async_ctx *_actx = (ACTX); \
399 CURLcode _setopterr = curl_easy_setopt(_actx->curl, OPT, VAL); \
401 actx_error(_actx, "failed to set %s on OAuth connection: %s",\
402 #OPT, curl_easy_strerror(_setopterr)); \
407#define CHECK_GETINFO(ACTX, INFO, OUT, FAILACTION) \
409 struct async_ctx *_actx = (ACTX); \
410 CURLcode _getinfoerr = curl_easy_getinfo(_actx->curl, INFO, OUT); \
412 actx_error(_actx, "failed to get %s from OAuth response: %s",\
413 #INFO, curl_easy_strerror(_getinfoerr)); \
448#define PG_OAUTH_REQUIRED true
449#define PG_OAUTH_OPTIONAL false
461#define oauth_parse_set_error(ctx, fmt, ...) \
462 appendPQExpBuffer((ctx)->errbuf, libpq_gettext(fmt), ##__VA_ARGS__)
478 msgfmt =
"field \"%s\" must be a string";
482 msgfmt =
"field \"%s\" must be a number";
486 msgfmt =
"field \"%s\" must be an array of strings";
491 msgfmt =
"field \"%s\" has unexpected type";
540 "internal error: started field '%s' before field '%s' was finished",
592 "internal error: field '%s' still active at end of object",
648 "internal error: found unexpected array end while parsing field '%s'",
690 if (
type != expected)
703 "internal error: scalar target found at nesting level %d",
713 "internal error: scalar field '%s' would be assigned twice",
728 struct curl_slist *temp;
735 "internal error: array member found at nesting level %d",
763 const size_t type_len = strlen(
type);
766 CHECK_GETINFO(actx, CURLINFO_CONTENT_TYPE, &content_type,
return false);
770 actx_error(actx,
"no content type was provided");
782 Assert(strlen(content_type) >= type_len);
783 if (content_type[type_len] ==
'\0')
791 for (
size_t i = type_len; content_type[
i]; ++
i)
793 switch (content_type[
i])
809 actx_error(actx,
"unexpected content type: \"%s\"", content_type);
832 if (strlen(resp->
data) != resp->
len)
834 actx_error(actx,
"response contains embedded NULLs");
844 actx_error(actx,
"response is not valid UTF-8");
947 cnt = sscanf(s,
"%lf", &parsed);
978 parsed = ceil(parsed);
983 else if (parsed >= INT_MAX)
1004 parsed = floor(parsed);
1006 if (parsed >= INT_MAX)
1008 else if (parsed <= INT_MIN)
1090 actx->
errctx =
"failed to parse token error response";
1102 if (
err->error_description)
1113 CHECK_GETINFO(actx, CURLINFO_RESPONSE_CODE, &response_code, response_code = 0);
1115 if (response_code == 401)
1118 ?
"provider rejected the oauth_client_secret"
1119 :
"provider requires client authentication, and no oauth_client_secret is set");
1176#if defined(HAVE_SYS_EPOLL_H)
1177 struct epoll_event ev = {.events = EPOLLIN};
1179 actx->
mux = epoll_create1(EPOLL_CLOEXEC);
1182 actx_error(actx,
"failed to create epoll set: %m");
1186 actx->
timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
1189 actx_error(actx,
"failed to create timerfd: %m");
1193 if (epoll_ctl(actx->
mux, EPOLL_CTL_ADD, actx->
timerfd, &ev) < 0)
1195 actx_error(actx,
"failed to add timerfd to epoll set: %m");
1200#elif defined(HAVE_SYS_EVENT_H)
1201 actx->
mux = kqueue();
1205 actx_error(actx,
"failed to create kqueue: %m");
1218 actx_error(actx,
"failed to create timer kqueue: %m");
1224#error setup_multiplexer is not implemented on this platform
1238#if defined(HAVE_SYS_EPOLL_H)
1239 struct epoll_event ev = {0};
1241 int op = EPOLL_CTL_ADD;
1246 ev.events = EPOLLIN;
1250 ev.events = EPOLLOUT;
1253 case CURL_POLL_INOUT:
1254 ev.events = EPOLLIN | EPOLLOUT;
1257 case CURL_POLL_REMOVE:
1262 actx_error(actx,
"unknown libcurl socket operation: %d", what);
1266 res = epoll_ctl(actx->
mux, op,
socket, &ev);
1267 if (res < 0 && errno == EEXIST)
1271 res = epoll_ctl(actx->
mux, op,
socket, &ev);
1279 actx_error(actx,
"could not add to epoll set: %m");
1283 actx_error(actx,
"could not delete from epoll set: %m");
1287 actx_error(actx,
"could not update epoll set: %m");
1294#elif defined(HAVE_SYS_EVENT_H)
1295 struct kevent ev[2];
1296 struct kevent ev_out[2];
1297 struct timespec timeout = {0};
1309 EV_SET(&ev[nev],
socket, EVFILT_READ, EV_ADD | EV_RECEIPT, 0, 0, 0);
1311 EV_SET(&ev[nev],
socket, EVFILT_WRITE, EV_DELETE | EV_RECEIPT, 0, 0, 0);
1316 EV_SET(&ev[nev],
socket, EVFILT_WRITE, EV_ADD | EV_RECEIPT, 0, 0, 0);
1318 EV_SET(&ev[nev],
socket, EVFILT_READ, EV_DELETE | EV_RECEIPT, 0, 0, 0);
1322 case CURL_POLL_INOUT:
1323 EV_SET(&ev[nev],
socket, EVFILT_READ, EV_ADD | EV_RECEIPT, 0, 0, 0);
1325 EV_SET(&ev[nev],
socket, EVFILT_WRITE, EV_ADD | EV_RECEIPT, 0, 0, 0);
1329 case CURL_POLL_REMOVE:
1330 EV_SET(&ev[nev],
socket, EVFILT_READ, EV_DELETE | EV_RECEIPT, 0, 0, 0);
1332 EV_SET(&ev[nev],
socket, EVFILT_WRITE, EV_DELETE | EV_RECEIPT, 0, 0, 0);
1337 actx_error(actx,
"unknown libcurl socket operation: %d", what);
1344 res = kevent(actx->
mux, ev, nev, ev_out, nev, &timeout);
1347 actx_error(actx,
"could not modify kqueue: %m");
1356 for (
int i = 0;
i < res; ++
i)
1363 Assert(ev_out[
i].flags & EV_ERROR);
1365 errno = ev_out[
i].data;
1366 if (errno && errno != ENOENT)
1370 case CURL_POLL_REMOVE:
1371 actx_error(actx,
"could not delete from kqueue: %m");
1374 actx_error(actx,
"could not add to kqueue: %m");
1382#error register_socket is not implemented on this platform
1401#if defined(HAVE_SYS_EPOLL_H)
1404#elif defined(HAVE_SYS_EVENT_H)
1405 struct timespec timeout = {0};
1421 if (kevent(actx->
mux, NULL, 0, &ev, 1, &timeout) < 0)
1423 actx_error(actx,
"could not comb kqueue: %m");
1429#error comb_multiplexer is not implemented on this platform
1449#if defined(HAVE_SYS_EPOLL_H)
1450 struct itimerspec spec = {0};
1456 else if (timeout == 0)
1463 spec.it_value.tv_nsec = 1;
1467 spec.it_value.tv_sec = timeout / 1000;
1468 spec.it_value.tv_nsec = (timeout % 1000) * 1000000;
1471 if (timerfd_settime(actx->
timerfd, 0 , &spec, NULL) < 0)
1473 actx_error(actx,
"setting timerfd to %ld: %m", timeout);
1478#elif defined(HAVE_SYS_EVENT_H)
1500 EV_SET(&ev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, 0);
1501 if (kevent(actx->
timerfd, &ev, 1, NULL, 0, NULL) < 0 && errno != ENOENT)
1503 actx_error(actx,
"deleting kqueue timer: %m");
1507 EV_SET(&ev, actx->
timerfd, EVFILT_READ, EV_DELETE, 0, 0, 0);
1508 if (kevent(actx->
mux, &ev, 1, NULL, 0, NULL) < 0 && errno != ENOENT)
1510 actx_error(actx,
"removing kqueue timer from multiplexer: %m");
1518 EV_SET(&ev, 1, EVFILT_TIMER, (EV_ADD | EV_ONESHOT), 0, timeout, 0);
1519 if (kevent(actx->
timerfd, &ev, 1, NULL, 0, NULL) < 0)
1521 actx_error(actx,
"setting kqueue timer to %ld: %m", timeout);
1525 EV_SET(&ev, actx->
timerfd, EVFILT_READ, EV_ADD, 0, 0, 0);
1526 if (kevent(actx->
mux, &ev, 1, NULL, 0, NULL) < 0)
1528 actx_error(actx,
"adding kqueue timer to multiplexer: %m");
1534#error set_timer is not implemented on this platform
1546#if defined(HAVE_SYS_EPOLL_H) || defined(HAVE_SYS_EVENT_H)
1553 actx_error(actx,
"checking timer expiration: %m");
1559#error timer_expired is not implemented on this platform
1610 *was_expired = (res > 0);
1626 bool printed_prefix =
false;
1636 case CURLINFO_HEADER_IN:
1637 case CURLINFO_DATA_IN:
1641 case CURLINFO_HEADER_OUT:
1642 case CURLINFO_DATA_OUT:
1657 for (
int i = 0;
i < size;
i++)
1661 if (!printed_prefix)
1664 printed_prefix =
true;
1667 if (
c >= 0x20 &&
c <= 0x7E)
1669 else if ((
type == CURLINFO_HEADER_IN
1670 ||
type == CURLINFO_HEADER_OUT
1671 ||
type == CURLINFO_TEXT)
1672 && (
c ==
'\r' ||
c ==
'\n'))
1685 printed_prefix =
false;
1711 actx->
curlm = curl_multi_init();
1715 actx_error(actx,
"failed to create libcurl multi handle");
1724 CHECK_MSETOPT(actx, CURLMOPT_SOCKETDATA, actx,
return false);
1726 CHECK_MSETOPT(actx, CURLMOPT_TIMERDATA, actx,
return false);
1732 actx->
curl = curl_easy_init();
1735 actx_error(actx,
"failed to create libcurl handle");
1754 CHECK_SETOPT(actx, CURLOPT_NOSIGNAL, 1L,
return false);
1778#if CURL_AT_LEAST_VERSION(7, 85, 0)
1779 const CURLoption popt = CURLOPT_PROTOCOLS_STR;
1780 const char *protos =
"https";
1781 const char *
const unsafe =
"https,http";
1783 const CURLoption popt = CURLOPT_PROTOCOLS;
1784 long protos = CURLPROTO_HTTPS;
1785 const long unsafe = CURLPROTO_HTTPS | CURLPROTO_HTTP;
1806 if ((env = getenv(
"PGOAUTHCAFILE")) != NULL)
1842 size_t len = size * nmemb;
1884 CHECK_SETOPT(actx, CURLOPT_WRITEDATA, actx,
return false);
1889 actx_error(actx,
"failed to queue HTTP request: %s",
1890 curl_multi_strerror(
err));
1903 err = curl_multi_socket_action(actx->
curlm, CURL_SOCKET_TIMEOUT, 0, &actx->
running);
1906 actx_error(actx,
"asynchronous HTTP request failed: %s",
1907 curl_multi_strerror(
err));
1918#ifndef CURL_IGNORE_DEPRECATION
1919#define CURL_IGNORE_DEPRECATION(x) x
1959 actx_error(actx,
"asynchronous HTTP request failed: %s",
1960 curl_multi_strerror(
err));
1972 while ((msg = curl_multi_info_read(actx->
curlm, &msgs_left)) != NULL)
1974 if (msg->msg != CURLMSG_DONE)
1984 if (msg->data.result != CURLE_OK)
1997 err = curl_multi_remove_handle(actx->
curlm, msg->easy_handle);
2000 actx_error(actx,
"libcurl easy handle removal failed: %s",
2001 curl_multi_strerror(
err));
2011 actx_error(actx,
"no result was retrieved for the finished handle");
2034 escaped = curl_easy_escape(NULL, s, 0);
2049 while ((match = strstr(haystack,
"%20")) != NULL)
2056 haystack = match + 3 ;
2117 CHECK_SETOPT(actx, CURLOPT_URL, discovery_uri,
return false);
2140 CHECK_GETINFO(actx, CURLINFO_RESPONSE_CODE, &response_code,
return false);
2142 if (response_code != 200)
2144 actx_error(actx,
"unexpected response code %ld", response_code);
2151 actx->
errctx =
"failed to parse OpenID discovery document";
2165 temp = curl_slist_append(temp,
"authorization_code");
2168 temp = curl_slist_append(temp,
"implicit");
2216 "the issuer identifier (%s) does not match oauth_issuer (%s)",
2224#define HTTPS_SCHEME "https://"
2225#define OAUTH_GRANT_TYPE_DEVICE_CODE "urn:ietf:params:oauth:grant-type:device_code"
2243 "issuer \"%s\" does not provide a device authorization endpoint",
2269 "device authorization endpoint \"%s\" must use HTTPS",
2278 "token endpoint \"%s\" must use HTTPS",
2301 if (oauth_client_secret)
2383 Assert(device_authz_uri);
2387 if (oauth_scope && oauth_scope[0])
2400 CHECK_SETOPT(actx, CURLOPT_URL, device_authz_uri,
return false);
2401 CHECK_SETOPT(actx, CURLOPT_COPYPOSTFIELDS, work_buffer->
data,
return false);
2411 CHECK_GETINFO(actx, CURLINFO_RESPONSE_CODE, &response_code,
return false);
2417 if (response_code == 200)
2419 actx->
errctx =
"failed to parse device authorization";
2432 if (response_code == 400 || response_code == 401)
2450 actx_error(actx,
"unexpected response code %ld", response_code);
2489 CHECK_SETOPT(actx, CURLOPT_URL, token_uri,
return false);
2490 CHECK_SETOPT(actx, CURLOPT_COPYPOSTFIELDS, work_buffer->
data,
return false);
2500 CHECK_GETINFO(actx, CURLINFO_RESPONSE_CODE, &response_code,
return false);
2505 if (response_code == 200)
2507 actx->
errctx =
"failed to parse access token response";
2520 if (response_code == 400 || response_code == 401)
2529 actx_error(actx,
"unexpected response code %ld", response_code);
2546 struct token tok = {0};
2569 if (strcmp(
err->error,
"authorization_pending") != 0 &&
2570 strcmp(
err->error,
"slow_down") != 0)
2580 if (strcmp(
err->error,
"slow_down") == 0)
2587 actx_error(actx,
"slow_down interval overflow");
2658#if HAVE_THREADSAFE_CURL_GLOBAL_INIT
2659 curl_version_info_data *info;
2662#if !HAVE_THREADSAFE_CURL_GLOBAL_INIT
2684 "curl_global_init previously failed during OAuth setup");
2700 if (curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_WIN32) != CURLE_OK)
2703 "curl_global_init failed during OAuth setup");
2708#if HAVE_THREADSAFE_CURL_GLOBAL_INIT
2717 info = curl_version_info(CURLVERSION_NOW);
2718 if (!(info->features & CURL_VERSION_THREADSAFE))
2725 "\tCurl initialization was reported thread-safe when libpq\n"
2726 "\twas compiled, but the currently installed version of\n"
2727 "\tlibcurl reports that it is not. Recompile libpq against\n"
2728 "\tthe installed version of libcurl.");
2737#if !HAVE_THREADSAFE_CURL_GLOBAL_INIT
2762 char *oauth_token = NULL;
2768 if (!
state->async_ctx)
2775 actx =
calloc(1,
sizeof(*actx));
2788 state->async_ctx = actx;
2800 actx =
state->async_ctx;
2886 actx->
errctx =
"failed to fetch OpenID discovery document";
2900 actx->
errctx =
"cannot run OAuth device authorization";
2904 actx->
errctx =
"failed to obtain device authorization";
2915 actx->
errctx =
"failed to obtain access token";
2966 actx->
errctx =
"failed to obtain access token";
2979 }
while (!oauth_token && !actx->
running);
3029 bool sigpipe_pending;
3063 actx =
state->async_ctx;
3070 fprintf(stderr,
"[libpq] total number of polls: %d\n",
static void cleanup(void)
#define fprintf(file, fmt, msg)
void err(int eval, const char *fmt,...)
PQauthDataHook_type PQgetAuthDataHook(void)
int PQsocketPoll(int sock, int forRead, int forWrite, pg_usec_time_t end_time)
Assert(PointerIsAligned(start, uint64))
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
void setJsonLexContextOwnsTokens(JsonLexContext *lex, bool owned_by_context)
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
void freeJsonLexContext(JsonLexContext *lex)
int(* PQauthDataHook_type)(PGauthData type, PGconn *conn, void *data)
PostgresPollingStatusType
@ PQAUTHDATA_PROMPT_OAUTH_DEVICE
PostgresPollingStatusType pg_fe_run_oauth_flow(PGconn *conn)
static bool drain_timer_events(struct async_ctx *actx, bool *was_expired)
static char * urlencode(const char *s)
static bool setup_multiplexer(struct async_ctx *actx)
static bool finish_token_request(struct async_ctx *actx, struct token *tok)
static JsonParseErrorType oauth_json_array_end(void *state)
static void append_urlencoded(PQExpBuffer buf, const char *s)
static bool start_token_request(struct async_ctx *actx, PGconn *conn)
static bool initialize_curl(PGconn *conn)
#define MAX_OAUTH_RESPONSE_SIZE
static bool parse_token_error(struct async_ctx *actx, struct token_error *err)
void pg_fe_cleanup_oauth_flow(PGconn *conn)
static bool add_client_identification(struct async_ctx *actx, PQExpBuffer reqbody, PGconn *conn)
static int parse_interval(struct async_ctx *actx, const char *interval_str)
static void free_provider(struct provider *provider)
static void build_urlencoded(PQExpBuffer buf, const char *key, const char *value)
#define conn_oauth_issuer_id(CONN)
static void record_token_error(struct async_ctx *actx, const struct token_error *err)
static bool parse_device_authz(struct async_ctx *actx, struct device_authz *authz)
static void report_type_mismatch(struct oauth_parse *ctx)
static int register_socket(CURL *curl, curl_socket_t socket, int what, void *ctx, void *socketp)
#define PG_OAUTH_OPTIONAL
static bool set_timer(struct async_ctx *actx, long timeout)
static bool parse_access_token(struct async_ctx *actx, struct token *tok)
static int timer_expired(struct async_ctx *actx)
static PostgresPollingStatusType drive_request(struct async_ctx *actx)
static bool start_device_authz(struct async_ctx *actx, PGconn *conn)
static bool prompt_user(struct async_ctx *actx, PGconn *conn)
#define CHECK_MSETOPT(ACTX, OPT, VAL, FAILACTION)
static bool finish_discovery(struct async_ctx *actx)
static double parse_json_number(const char *s)
#define conn_oauth_discovery_uri(CONN)
static bool start_discovery(struct async_ctx *actx, const char *discovery_uri)
static JsonParseErrorType oauth_json_object_field_start(void *state, char *name, bool isnull)
static JsonParseErrorType oauth_json_scalar(void *state, char *token, JsonTokenType type)
static void free_token_error(struct token_error *err)
#define actx_error_str(ACTX, S)
static bool finish_device_authz(struct async_ctx *actx)
#define conn_oauth_scope(CONN)
static size_t append_data(char *buf, size_t size, size_t nmemb, void *userdata)
#define CHECK_SETOPT(ACTX, OPT, VAL, FAILACTION)
static PostgresPollingStatusType pg_fe_run_oauth_flow_impl(PGconn *conn)
static bool parse_oauth_json(struct async_ctx *actx, const struct json_field *fields)
#define MAX_OAUTH_NESTING_LEVEL
#define OAUTH_GRANT_TYPE_DEVICE_CODE
#define conn_oauth_client_id(CONN)
#define CURL_IGNORE_DEPRECATION(x)
static JsonParseErrorType oauth_json_array_start(void *state)
static JsonParseErrorType oauth_json_object_end(void *state)
#define set_conn_altsock(CONN, VAL)
static int debug_callback(CURL *handle, curl_infotype type, char *data, size_t size, void *clientp)
static void free_token(struct token *tok)
#define oauth_parse_set_error(ctx, fmt,...)
static bool comb_multiplexer(struct async_ctx *actx)
@ OAUTH_STEP_DEVICE_AUTHORIZATION
@ OAUTH_STEP_WAIT_INTERVAL
@ OAUTH_STEP_TOKEN_REQUEST
static int register_timer(CURLM *curlm, long timeout, void *ctx)
#define conn_oauth_client_secret(CONN)
#define set_conn_oauth_token(CONN, VAL)
#define CHECK_GETINFO(ACTX, INFO, OUT, FAILACTION)
static bool check_content_type(struct async_ctx *actx, const char *type)
static bool check_issuer(struct async_ctx *actx, PGconn *conn)
#define actx_error(ACTX, FMT,...)
static bool parse_provider(struct async_ctx *actx, struct provider *provider)
static bool start_request(struct async_ctx *actx)
static int parse_expires_in(struct async_ctx *actx, const char *expires_in_str)
static void free_async_ctx(PGconn *conn, struct async_ctx *actx)
static void free_device_authz(struct device_authz *authz)
#define conn_sasl_state(CONN)
#define conn_errorMessage(CONN)
static bool handle_token_response(struct async_ctx *actx, char **token)
static JsonParseErrorType oauth_json_object_start(void *state)
#define PG_OAUTH_REQUIRED
static bool check_for_device_flow(struct async_ctx *actx)
static bool setup_curl_handles(struct async_ctx *actx)
void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending)
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
bool oauth_unsafe_debugging_enabled(void)
#define pgunlock_thread()
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
void initPQExpBuffer(PQExpBuffer str)
void resetPQExpBuffer(PQExpBuffer str)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void appendBinaryPQExpBuffer(PQExpBuffer str, const char *data, size_t datalen)
void appendPQExpBufferChar(PQExpBuffer str, char ch)
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
void termPQExpBuffer(PQExpBuffer str)
#define PQExpBufferBroken(str)
#define PQExpBufferDataBroken(buf)
json_struct_action array_end
json_struct_action object_start
json_ofield_action object_field_start
json_scalar_action scalar
json_struct_action array_start
json_struct_action object_end
const char * verification_uri
struct device_authz authz
PQExpBufferData work_data
char curl_err[CURL_ERROR_SIZE]
struct curl_slist * headers
char * verification_uri_complete
struct curl_slist ** array
union json_field::@189 target
const struct json_field * active
const struct json_field * fields
char * device_authorization_endpoint
struct curl_slist * grant_types_supported
int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len)
#define socket(af, type, protocol)