Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * oauth-utils.c
4 : : *
5 : : * "Glue" helpers providing a copy of some internal APIs from libpq. At
6 : : * some point in the future, we might be able to deduplicate.
7 : : *
8 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
9 : : * Portions Copyright (c) 1994, Regents of the University of California
10 : : *
11 : : * IDENTIFICATION
12 : : * src/interfaces/libpq-oauth/oauth-utils.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : : #include "postgres_fe.h"
18 : :
19 : : #include <signal.h>
20 : :
21 : : #include "oauth-utils.h"
22 : :
23 : : #ifndef USE_DYNAMIC_OAUTH
24 : : #error oauth-utils.c is not supported in static builds
25 : : #endif
26 : :
27 : : #ifdef LIBPQ_INT_H
28 : : #error do not rely on libpq-int.h in dynamic builds of libpq-oauth
29 : : #endif
30 : :
31 : : /*
32 : : * Function pointers set by libpq_oauth_init().
33 : : */
34 : :
35 : : pgthreadlock_t pg_g_threadlock;
36 : : static libpq_gettext_func libpq_gettext_impl;
37 : :
38 : : /*-
39 : : * Initializes libpq-oauth by setting necessary callbacks.
40 : : *
41 : : * The current implementation relies on libpq_gettext to translate error
42 : : * messages using libpq's message domain, so libpq injects it here. We also use
43 : : * this chance to initialize our threadlock.
44 : : */
45 : : void
53 jchampion@postgresql 46 :GNC 57 : libpq_oauth_init(libpq_gettext_func gettext_impl)
47 : : {
48 : 57 : pg_g_threadlock = PQgetThreadLock();
369 jchampion@postgresql 49 :CBC 57 : libpq_gettext_impl = gettext_impl;
369 jchampion@postgresql 50 :GIC 57 : }
51 : :
52 : : #ifdef ENABLE_NLS
53 : :
54 : : /*
55 : : * A shim that defers to the actual libpq_gettext().
56 : : */
57 : : char *
369 jchampion@postgresql 58 :CBC 420 : libpq_gettext(const char *msgid)
59 : : {
60 [ - + ]: 420 : if (!libpq_gettext_impl)
61 : : {
62 : : /*
63 : : * Possible if the libpq build didn't enable NLS but the libpq-oauth
64 : : * build did. That's an odd mismatch, but we can handle it.
65 : : *
66 : : * Note that callers of libpq_gettext() have to treat the return value
67 : : * as if it were const, because builds without NLS simply pass through
68 : : * their argument.
69 : : */
369 jchampion@postgresql 70 :UBC 0 : return unconstify(char *, msgid);
71 : : }
72 : :
369 jchampion@postgresql 73 :CBC 420 : return libpq_gettext_impl(msgid);
74 : : }
75 : :
76 : : #endif /* ENABLE_NLS */
77 : :
78 : : /*
79 : : * Duplicate SOCK_ERRNO* definitions from libpq-int.h, for use by
80 : : * pq_block/reset_sigpipe().
81 : : */
82 : : #ifdef WIN32
83 : : #define SOCK_ERRNO (WSAGetLastError())
84 : : #define SOCK_ERRNO_SET(e) WSASetLastError(e)
85 : : #else
86 : : #define SOCK_ERRNO errno
87 : : #define SOCK_ERRNO_SET(e) (errno = (e))
88 : : #endif
89 : :
90 : : /*
91 : : * Block SIGPIPE for this thread. This is a copy of libpq's internal API.
92 : : */
93 : : int
94 : 340362 : pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending)
95 : : {
96 : : sigset_t sigpipe_sigset;
97 : : sigset_t sigset;
98 : :
99 : 340362 : sigemptyset(&sigpipe_sigset);
100 : 340362 : sigaddset(&sigpipe_sigset, SIGPIPE);
101 : :
102 : : /* Block SIGPIPE and save previous mask for later reset */
103 : 340362 : SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset));
104 [ - + ]: 340362 : if (SOCK_ERRNO)
369 jchampion@postgresql 105 :UBC 0 : return -1;
106 : :
107 : : /* We can have a pending SIGPIPE only if it was blocked before */
369 jchampion@postgresql 108 [ - + ]:CBC 340362 : if (sigismember(osigset, SIGPIPE))
109 : : {
110 : : /* Is there a pending SIGPIPE? */
369 jchampion@postgresql 111 [ # # ]:UBC 0 : if (sigpending(&sigset) != 0)
112 : 0 : return -1;
113 : :
114 [ # # ]: 0 : if (sigismember(&sigset, SIGPIPE))
115 : 0 : *sigpipe_pending = true;
116 : : else
117 : 0 : *sigpipe_pending = false;
118 : : }
119 : : else
369 jchampion@postgresql 120 :CBC 340362 : *sigpipe_pending = false;
121 : :
122 : 340362 : return 0;
123 : : }
124 : :
125 : : /*
126 : : * Discard any pending SIGPIPE and reset the signal mask. This is a copy of
127 : : * libpq's internal API.
128 : : */
129 : : void
130 : 340362 : pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe)
131 : : {
132 : 340362 : int save_errno = SOCK_ERRNO;
133 : : int signo;
134 : : sigset_t sigset;
135 : :
136 : : /* Clear SIGPIPE only if none was pending */
137 [ + - + - ]: 340362 : if (got_epipe && !sigpipe_pending)
138 : : {
139 [ + - - + ]: 680724 : if (sigpending(&sigset) == 0 &&
140 : 340362 : sigismember(&sigset, SIGPIPE))
141 : : {
142 : : sigset_t sigpipe_sigset;
143 : :
369 jchampion@postgresql 144 :UBC 0 : sigemptyset(&sigpipe_sigset);
145 : 0 : sigaddset(&sigpipe_sigset, SIGPIPE);
146 : :
147 : 0 : sigwait(&sigpipe_sigset, &signo);
148 : : }
149 : : }
150 : :
151 : : /* Restore saved block mask */
369 jchampion@postgresql 152 :CBC 340362 : pthread_sigmask(SIG_SETMASK, osigset, NULL);
153 : :
154 : 340362 : SOCK_ERRNO_SET(save_errno);
155 : 340362 : }
|