Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * fe-connect.c
4 : : * functions related to setting up a connection to the backend
5 : : *
6 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/interfaces/libpq/fe-connect.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : :
16 : : #include "postgres_fe.h"
17 : :
18 : : #include <sys/stat.h>
19 : : #include <fcntl.h>
20 : : #include <ctype.h>
21 : : #include <netdb.h>
22 : : #include <time.h>
23 : : #include <unistd.h>
24 : :
25 : : #include "common/ip.h"
26 : : #include "common/link-canary.h"
27 : : #include "common/scram-common.h"
28 : : #include "common/string.h"
29 : : #include "fe-auth.h"
30 : : #include "libpq-fe.h"
31 : : #include "libpq-int.h"
32 : : #include "mb/pg_wchar.h"
33 : : #include "pg_config_paths.h"
34 : : #include "port/pg_bswap.h"
35 : :
36 : : #ifdef WIN32
37 : : #include "win32.h"
38 : : #ifdef _WIN32_IE
39 : : #undef _WIN32_IE
40 : : #endif
41 : : #define _WIN32_IE 0x0500
42 : : #ifdef near
43 : : #undef near
44 : : #endif
45 : : #define near
46 : : #include <shlobj.h>
47 : : #include <mstcpip.h>
48 : : #else
49 : : #include <sys/socket.h>
50 : : #include <netdb.h>
51 : : #include <netinet/in.h>
52 : : #include <netinet/tcp.h>
53 : : #endif
54 : :
55 : : #ifdef WIN32
56 : : #include "pthread-win32.h"
57 : : #else
58 : : #include <pthread.h>
59 : : #endif
60 : :
61 : : #ifdef USE_LDAP
62 : : #ifdef WIN32
63 : : #include <winldap.h>
64 : : #else
65 : : /* OpenLDAP deprecates RFC 1823, but we want standard conformance */
66 : : #define LDAP_DEPRECATED 1
67 : : #include <ldap.h>
68 : : typedef struct timeval LDAP_TIMEVAL;
69 : : #endif
70 : : static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
71 : : PQExpBuffer errorMessage);
72 : : #endif
73 : :
74 : : #ifndef WIN32
75 : : #define PGPASSFILE ".pgpass"
76 : : #else
77 : : #define PGPASSFILE "pgpass.conf"
78 : : #endif
79 : :
80 : : /*
81 : : * Pre-9.0 servers will return this SQLSTATE if asked to set
82 : : * application_name in a startup packet. We hard-wire the value rather
83 : : * than looking into errcodes.h since it reflects historical behavior
84 : : * rather than that of the current code.
85 : : */
86 : : #define ERRCODE_APPNAME_UNKNOWN "42704"
87 : :
88 : : /* This is part of the protocol so just define it */
89 : : #define ERRCODE_INVALID_PASSWORD "28P01"
90 : : /* This too */
91 : : #define ERRCODE_CANNOT_CONNECT_NOW "57P03"
92 : :
93 : : /*
94 : : * Cope with the various platform-specific ways to spell TCP keepalive socket
95 : : * options. This doesn't cover Windows, which as usual does its own thing.
96 : : */
97 : : #if defined(TCP_KEEPIDLE)
98 : : /* TCP_KEEPIDLE is the name of this option on Linux and *BSD */
99 : : #define PG_TCP_KEEPALIVE_IDLE TCP_KEEPIDLE
100 : : #define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPIDLE"
101 : : #elif defined(TCP_KEEPALIVE_THRESHOLD)
102 : : /* TCP_KEEPALIVE_THRESHOLD is the name of this option on Solaris >= 11 */
103 : : #define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE_THRESHOLD
104 : : #define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE_THRESHOLD"
105 : : #elif defined(TCP_KEEPALIVE) && defined(__darwin__)
106 : : /* TCP_KEEPALIVE is the name of this option on macOS */
107 : : /* Caution: Solaris has this symbol but it means something different */
108 : : #define PG_TCP_KEEPALIVE_IDLE TCP_KEEPALIVE
109 : : #define PG_TCP_KEEPALIVE_IDLE_STR "TCP_KEEPALIVE"
110 : : #endif
111 : :
112 : : /*
113 : : * fall back options if they are not specified by arguments or defined
114 : : * by environment variables
115 : : */
116 : : #define DefaultHost "localhost"
117 : : #define DefaultOption ""
118 : : #ifdef USE_SSL
119 : : #define DefaultChannelBinding "prefer"
120 : : #else
121 : : #define DefaultChannelBinding "disable"
122 : : #endif
123 : : #define DefaultTargetSessionAttrs "any"
124 : : #define DefaultLoadBalanceHosts "disable"
125 : : #ifdef USE_SSL
126 : : #define DefaultSSLMode "prefer"
127 : : #define DefaultSSLCertMode "allow"
128 : : #else
129 : : #define DefaultSSLMode "disable"
130 : : #define DefaultSSLCertMode "disable"
131 : : #endif
132 : : #define DefaultSSLNegotiation "postgres"
133 : : #ifdef ENABLE_GSS
134 : : #include "fe-gssapi-common.h"
135 : : #define DefaultGSSMode "prefer"
136 : : #else
137 : : #define DefaultGSSMode "disable"
138 : : #endif
139 : :
140 : : /* ----------
141 : : * Definition of the conninfo parameters and their fallback resources.
142 : : *
143 : : * If Environment-Var and Compiled-in are specified as NULL, no
144 : : * fallback is available. If after all no value can be determined
145 : : * for an option, an error is returned.
146 : : *
147 : : * The value for the username is treated specially in conninfo_add_defaults.
148 : : * If the value is not obtained any other way, the username is determined
149 : : * by pg_fe_getauthname().
150 : : *
151 : : * The Label and Disp-Char entries are provided for applications that
152 : : * want to use PQconndefaults() to create a generic database connection
153 : : * dialog. Disp-Char is defined as follows:
154 : : * "" Normal input field
155 : : * "*" Password field - hide value
156 : : * "D" Debug option - don't show by default
157 : : *
158 : : * PQconninfoOptions[] is a constant static array that we use to initialize
159 : : * a dynamically allocated working copy. All the "val" fields in
160 : : * PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val"
161 : : * fields point to malloc'd strings that should be freed when the working
162 : : * array is freed (see PQconninfoFree).
163 : : *
164 : : * The first part of each struct is identical to the one in libpq-fe.h,
165 : : * which is required since we memcpy() data between the two!
166 : : * ----------
167 : : */
168 : : typedef struct _internalPQconninfoOption
169 : : {
170 : : char *keyword; /* The keyword of the option */
171 : : char *envvar; /* Fallback environment variable name */
172 : : char *compiled; /* Fallback compiled in default value */
173 : : char *val; /* Option's current value, or NULL */
174 : : char *label; /* Label for field in connect dialog */
175 : : char *dispchar; /* Indicates how to display this field in a
176 : : * connect dialog. Values are: "" Display
177 : : * entered value as is "*" Password field -
178 : : * hide value "D" Debug option - don't show
179 : : * by default */
180 : : int dispsize; /* Field size in characters for dialog */
181 : : /* ---
182 : : * Anything above this comment must be synchronized with
183 : : * PQconninfoOption in libpq-fe.h, since we memcpy() data
184 : : * between them!
185 : : * ---
186 : : */
187 : : off_t connofs; /* Offset into PGconn struct, -1 if not there */
188 : : } internalPQconninfoOption;
189 : :
190 : : static const internalPQconninfoOption PQconninfoOptions[] = {
191 : : {"service", "PGSERVICE", NULL, NULL,
192 : : "Database-Service", "", 20, -1},
193 : :
194 : : {"user", "PGUSER", NULL, NULL,
195 : : "Database-User", "", 20,
196 : : offsetof(struct pg_conn, pguser)},
197 : :
198 : : {"password", "PGPASSWORD", NULL, NULL,
199 : : "Database-Password", "*", 20,
200 : : offsetof(struct pg_conn, pgpass)},
201 : :
202 : : {"passfile", "PGPASSFILE", NULL, NULL,
203 : : "Database-Password-File", "", 64,
204 : : offsetof(struct pg_conn, pgpassfile)},
205 : :
206 : : {"channel_binding", "PGCHANNELBINDING", DefaultChannelBinding, NULL,
207 : : "Channel-Binding", "", 8, /* sizeof("require") == 8 */
208 : : offsetof(struct pg_conn, channel_binding)},
209 : :
210 : : {"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
211 : : "Connect-timeout", "", 10, /* strlen(INT32_MAX) == 10 */
212 : : offsetof(struct pg_conn, connect_timeout)},
213 : :
214 : : {"dbname", "PGDATABASE", NULL, NULL,
215 : : "Database-Name", "", 20,
216 : : offsetof(struct pg_conn, dbName)},
217 : :
218 : : {"host", "PGHOST", NULL, NULL,
219 : : "Database-Host", "", 40,
220 : : offsetof(struct pg_conn, pghost)},
221 : :
222 : : {"hostaddr", "PGHOSTADDR", NULL, NULL,
223 : : "Database-Host-IP-Address", "", 45,
224 : : offsetof(struct pg_conn, pghostaddr)},
225 : :
226 : : {"port", "PGPORT", DEF_PGPORT_STR, NULL,
227 : : "Database-Port", "", 6,
228 : : offsetof(struct pg_conn, pgport)},
229 : :
230 : : {"client_encoding", "PGCLIENTENCODING", NULL, NULL,
231 : : "Client-Encoding", "", 10,
232 : : offsetof(struct pg_conn, client_encoding_initial)},
233 : :
234 : : {"options", "PGOPTIONS", DefaultOption, NULL,
235 : : "Backend-Options", "", 40,
236 : : offsetof(struct pg_conn, pgoptions)},
237 : :
238 : : {"application_name", "PGAPPNAME", NULL, NULL,
239 : : "Application-Name", "", 64,
240 : : offsetof(struct pg_conn, appname)},
241 : :
242 : : {"fallback_application_name", NULL, NULL, NULL,
243 : : "Fallback-Application-Name", "", 64,
244 : : offsetof(struct pg_conn, fbappname)},
245 : :
246 : : {"keepalives", NULL, NULL, NULL,
247 : : "TCP-Keepalives", "", 1, /* should be just '0' or '1' */
248 : : offsetof(struct pg_conn, keepalives)},
249 : :
250 : : {"keepalives_idle", NULL, NULL, NULL,
251 : : "TCP-Keepalives-Idle", "", 10, /* strlen(INT32_MAX) == 10 */
252 : : offsetof(struct pg_conn, keepalives_idle)},
253 : :
254 : : {"keepalives_interval", NULL, NULL, NULL,
255 : : "TCP-Keepalives-Interval", "", 10, /* strlen(INT32_MAX) == 10 */
256 : : offsetof(struct pg_conn, keepalives_interval)},
257 : :
258 : : {"keepalives_count", NULL, NULL, NULL,
259 : : "TCP-Keepalives-Count", "", 10, /* strlen(INT32_MAX) == 10 */
260 : : offsetof(struct pg_conn, keepalives_count)},
261 : :
262 : : {"tcp_user_timeout", NULL, NULL, NULL,
263 : : "TCP-User-Timeout", "", 10, /* strlen(INT32_MAX) == 10 */
264 : : offsetof(struct pg_conn, pgtcp_user_timeout)},
265 : :
266 : : /*
267 : : * ssl options are allowed even without client SSL support because the
268 : : * client can still handle SSL modes "disable" and "allow". Other
269 : : * parameters have no effect on non-SSL connections, so there is no reason
270 : : * to exclude them since none of them are mandatory.
271 : : */
272 : : {"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
273 : : "SSL-Mode", "", 12, /* sizeof("verify-full") == 12 */
274 : : offsetof(struct pg_conn, sslmode)},
275 : :
276 : : {"sslnegotiation", "PGSSLNEGOTIATION", DefaultSSLNegotiation, NULL,
277 : : "SSL-Negotiation", "", 14, /* sizeof("requiredirect") == 14 */
278 : : offsetof(struct pg_conn, sslnegotiation)},
279 : :
280 : : {"sslcompression", "PGSSLCOMPRESSION", "0", NULL,
281 : : "SSL-Compression", "", 1,
282 : : offsetof(struct pg_conn, sslcompression)},
283 : :
284 : : {"sslcert", "PGSSLCERT", NULL, NULL,
285 : : "SSL-Client-Cert", "", 64,
286 : : offsetof(struct pg_conn, sslcert)},
287 : :
288 : : {"sslkey", "PGSSLKEY", NULL, NULL,
289 : : "SSL-Client-Key", "", 64,
290 : : offsetof(struct pg_conn, sslkey)},
291 : :
292 : : {"sslcertmode", "PGSSLCERTMODE", NULL, NULL,
293 : : "SSL-Client-Cert-Mode", "", 8, /* sizeof("disable") == 8 */
294 : : offsetof(struct pg_conn, sslcertmode)},
295 : :
296 : : {"sslpassword", NULL, NULL, NULL,
297 : : "SSL-Client-Key-Password", "*", 20,
298 : : offsetof(struct pg_conn, sslpassword)},
299 : :
300 : : {"sslrootcert", "PGSSLROOTCERT", NULL, NULL,
301 : : "SSL-Root-Certificate", "", 64,
302 : : offsetof(struct pg_conn, sslrootcert)},
303 : :
304 : : {"sslcrl", "PGSSLCRL", NULL, NULL,
305 : : "SSL-Revocation-List", "", 64,
306 : : offsetof(struct pg_conn, sslcrl)},
307 : :
308 : : {"sslcrldir", "PGSSLCRLDIR", NULL, NULL,
309 : : "SSL-Revocation-List-Dir", "", 64,
310 : : offsetof(struct pg_conn, sslcrldir)},
311 : :
312 : : {"sslsni", "PGSSLSNI", "1", NULL,
313 : : "SSL-SNI", "", 1,
314 : : offsetof(struct pg_conn, sslsni)},
315 : :
316 : : {"requirepeer", "PGREQUIREPEER", NULL, NULL,
317 : : "Require-Peer", "", 10,
318 : : offsetof(struct pg_conn, requirepeer)},
319 : :
320 : : {"require_auth", "PGREQUIREAUTH", NULL, NULL,
321 : : "Require-Auth", "", 14, /* sizeof("scram-sha-256") == 14 */
322 : : offsetof(struct pg_conn, require_auth)},
323 : :
324 : : {"ssl_min_protocol_version", "PGSSLMINPROTOCOLVERSION", "TLSv1.2", NULL,
325 : : "SSL-Minimum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */
326 : : offsetof(struct pg_conn, ssl_min_protocol_version)},
327 : :
328 : : {"ssl_max_protocol_version", "PGSSLMAXPROTOCOLVERSION", NULL, NULL,
329 : : "SSL-Maximum-Protocol-Version", "", 8, /* sizeof("TLSv1.x") == 8 */
330 : : offsetof(struct pg_conn, ssl_max_protocol_version)},
331 : :
332 : : /*
333 : : * As with SSL, all GSS options are exposed even in builds that don't have
334 : : * support.
335 : : */
336 : : {"gssencmode", "PGGSSENCMODE", DefaultGSSMode, NULL,
337 : : "GSSENC-Mode", "", 8, /* sizeof("disable") == 8 */
338 : : offsetof(struct pg_conn, gssencmode)},
339 : :
340 : : /* Kerberos and GSSAPI authentication support specifying the service name */
341 : : {"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
342 : : "Kerberos-service-name", "", 20,
343 : : offsetof(struct pg_conn, krbsrvname)},
344 : :
345 : : {"gsslib", "PGGSSLIB", NULL, NULL,
346 : : "GSS-library", "", 7, /* sizeof("gssapi") == 7 */
347 : : offsetof(struct pg_conn, gsslib)},
348 : :
349 : : {"gssdelegation", "PGGSSDELEGATION", "0", NULL,
350 : : "GSS-delegation", "", 1,
351 : : offsetof(struct pg_conn, gssdelegation)},
352 : :
353 : : {"replication", NULL, NULL, NULL,
354 : : "Replication", "D", 5,
355 : : offsetof(struct pg_conn, replication)},
356 : :
357 : : {"target_session_attrs", "PGTARGETSESSIONATTRS",
358 : : DefaultTargetSessionAttrs, NULL,
359 : : "Target-Session-Attrs", "", 15, /* sizeof("prefer-standby") = 15 */
360 : : offsetof(struct pg_conn, target_session_attrs)},
361 : :
362 : : {"load_balance_hosts", "PGLOADBALANCEHOSTS",
363 : : DefaultLoadBalanceHosts, NULL,
364 : : "Load-Balance-Hosts", "", 8, /* sizeof("disable") = 8 */
365 : : offsetof(struct pg_conn, load_balance_hosts)},
366 : :
367 : : /* Terminating entry --- MUST BE LAST */
368 : : {NULL, NULL, NULL, NULL,
369 : : NULL, NULL, 0}
370 : : };
371 : :
372 : : static const PQEnvironmentOption EnvironmentOptions[] =
373 : : {
374 : : /* common user-interface settings */
375 : : {
376 : : "PGDATESTYLE", "datestyle"
377 : : },
378 : : {
379 : : "PGTZ", "timezone"
380 : : },
381 : : /* internal performance-related settings */
382 : : {
383 : : "PGGEQO", "geqo"
384 : : },
385 : : {
386 : : NULL, NULL
387 : : }
388 : : };
389 : :
390 : : /* The connection URI must start with either of the following designators: */
391 : : static const char uri_designator[] = "postgresql://";
392 : : static const char short_uri_designator[] = "postgres://";
393 : :
394 : : static bool connectOptions1(PGconn *conn, const char *conninfo);
395 : : static bool init_allowed_encryption_methods(PGconn *conn);
396 : : #if defined(USE_SSL) || defined(ENABLE_GSS)
397 : : static int encryption_negotiation_failed(PGconn *conn);
398 : : #endif
399 : : static bool connection_failed(PGconn *conn);
400 : : static bool select_next_encryption_method(PGconn *conn, bool negotiation_failure);
401 : : static PGPing internal_ping(PGconn *conn);
402 : : static void pqFreeCommandQueue(PGcmdQueueEntry *queue);
403 : : static bool fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
404 : : static void freePGconn(PGconn *conn);
405 : : static void release_conn_addrinfo(PGconn *conn);
406 : : static int store_conn_addrinfo(PGconn *conn, struct addrinfo *addrlist);
407 : : static void sendTerminateConn(PGconn *conn);
408 : : static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
409 : : static PQconninfoOption *parse_connection_string(const char *connstr,
410 : : PQExpBuffer errorMessage, bool use_defaults);
411 : : static int uri_prefix_length(const char *connstr);
412 : : static bool recognized_connection_string(const char *connstr);
413 : : static PQconninfoOption *conninfo_parse(const char *conninfo,
414 : : PQExpBuffer errorMessage, bool use_defaults);
415 : : static PQconninfoOption *conninfo_array_parse(const char *const *keywords,
416 : : const char *const *values, PQExpBuffer errorMessage,
417 : : bool use_defaults, int expand_dbname);
418 : : static bool conninfo_add_defaults(PQconninfoOption *options,
419 : : PQExpBuffer errorMessage);
420 : : static PQconninfoOption *conninfo_uri_parse(const char *uri,
421 : : PQExpBuffer errorMessage, bool use_defaults);
422 : : static bool conninfo_uri_parse_options(PQconninfoOption *options,
423 : : const char *uri, PQExpBuffer errorMessage);
424 : : static bool conninfo_uri_parse_params(char *params,
425 : : PQconninfoOption *connOptions,
426 : : PQExpBuffer errorMessage);
427 : : static char *conninfo_uri_decode(const char *str, PQExpBuffer errorMessage);
428 : : static bool get_hexdigit(char digit, int *value);
429 : : static const char *conninfo_getval(PQconninfoOption *connOptions,
430 : : const char *keyword);
431 : : static PQconninfoOption *conninfo_storeval(PQconninfoOption *connOptions,
432 : : const char *keyword, const char *value,
433 : : PQExpBuffer errorMessage, bool ignoreMissing, bool uri_decode);
434 : : static PQconninfoOption *conninfo_find(PQconninfoOption *connOptions,
435 : : const char *keyword);
436 : : static void defaultNoticeReceiver(void *arg, const PGresult *res);
437 : : static void defaultNoticeProcessor(void *arg, const char *message);
438 : : static int parseServiceInfo(PQconninfoOption *options,
439 : : PQExpBuffer errorMessage);
440 : : static int parseServiceFile(const char *serviceFile,
441 : : const char *service,
442 : : PQconninfoOption *options,
443 : : PQExpBuffer errorMessage,
444 : : bool *group_found);
445 : : static char *pwdfMatchesString(char *buf, const char *token);
446 : : static char *passwordFromFile(const char *hostname, const char *port, const char *dbname,
447 : : const char *username, const char *pgpassfile);
448 : : static void pgpassfileWarning(PGconn *conn);
449 : : static void default_threadlock(int acquire);
450 : : static bool sslVerifyProtocolVersion(const char *version);
451 : : static bool sslVerifyProtocolRange(const char *min, const char *max);
452 : :
453 : :
454 : : /* global variable because fe-auth.c needs to access it */
455 : : pgthreadlock_t pg_g_threadlock = default_threadlock;
456 : :
457 : :
458 : : /*
459 : : * pqDropConnection
460 : : *
461 : : * Close any physical connection to the server, and reset associated
462 : : * state inside the connection object. We don't release state that
463 : : * would be needed to reconnect, though, nor local state that might still
464 : : * be useful later.
465 : : *
466 : : * We can always flush the output buffer, since there's no longer any hope
467 : : * of sending that data. However, unprocessed input data might still be
468 : : * valuable, so the caller must tell us whether to flush that or not.
469 : : */
470 : : void
3076 tgl@sss.pgh.pa.us 471 :CBC 24883 : pqDropConnection(PGconn *conn, bool flushInput)
472 : : {
473 : : /* Drop any SSL state */
4237 474 : 24883 : pqsecure_close(conn);
475 : :
476 : : /* Close the socket itself */
3651 bruce@momjian.us 477 [ + + ]: 24883 : if (conn->sock != PGINVALID_SOCKET)
4237 tgl@sss.pgh.pa.us 478 : 12009 : closesocket(conn->sock);
3651 bruce@momjian.us 479 : 24883 : conn->sock = PGINVALID_SOCKET;
480 : :
481 : : /* Optionally discard any unread data */
3076 tgl@sss.pgh.pa.us 482 [ + + ]: 24883 : if (flushInput)
483 : 24773 : conn->inStart = conn->inCursor = conn->inEnd = 0;
484 : :
485 : : /* Always discard any unsent data */
4237 486 : 24883 : conn->outCount = 0;
487 : :
488 : : /* Likewise, discard any pending pipelined commands */
703 489 : 24883 : pqFreeCommandQueue(conn->cmd_queue_head);
490 : 24883 : conn->cmd_queue_head = conn->cmd_queue_tail = NULL;
491 : 24883 : pqFreeCommandQueue(conn->cmd_queue_recycle);
492 : 24883 : conn->cmd_queue_recycle = NULL;
493 : :
494 : : /* Free authentication/encryption state */
495 : : #ifdef ENABLE_GSS
496 : : {
497 : : OM_uint32 min_s;
498 : :
1371 499 [ + + ]: 24883 : if (conn->gcred != GSS_C_NO_CREDENTIAL)
500 : : {
501 : 10 : gss_release_cred(&min_s, &conn->gcred);
502 : 10 : conn->gcred = GSS_C_NO_CREDENTIAL;
503 : : }
2503 heikki.linnakangas@i 504 [ + + ]: 24883 : if (conn->gctx)
505 : 242 : gss_delete_sec_context(&min_s, &conn->gctx, GSS_C_NO_BUFFER);
506 [ + + ]: 24883 : if (conn->gtarg_nam)
507 : 232 : gss_release_name(&min_s, &conn->gtarg_nam);
1555 tgl@sss.pgh.pa.us 508 [ + + ]: 24883 : if (conn->gss_SendBuffer)
509 : : {
510 : 232 : free(conn->gss_SendBuffer);
511 : 232 : conn->gss_SendBuffer = NULL;
512 : : }
513 [ + + ]: 24883 : if (conn->gss_RecvBuffer)
514 : : {
515 : 232 : free(conn->gss_RecvBuffer);
516 : 232 : conn->gss_RecvBuffer = NULL;
517 : : }
518 [ + + ]: 24883 : if (conn->gss_ResultBuffer)
519 : : {
520 : 232 : free(conn->gss_ResultBuffer);
521 : 232 : conn->gss_ResultBuffer = NULL;
522 : : }
1371 523 : 24883 : conn->gssenc = false;
524 : : }
525 : : #endif
526 : : #ifdef ENABLE_SSPI
527 : : if (conn->sspitarget)
528 : : {
529 : : free(conn->sspitarget);
530 : : conn->sspitarget = NULL;
531 : : }
532 : : if (conn->sspicred)
533 : : {
534 : : FreeCredentialsHandle(conn->sspicred);
535 : : free(conn->sspicred);
536 : : conn->sspicred = NULL;
537 : : }
538 : : if (conn->sspictx)
539 : : {
540 : : DeleteSecurityContext(conn->sspictx);
541 : : free(conn->sspictx);
542 : : conn->sspictx = NULL;
543 : : }
544 : : conn->usesspi = 0;
545 : : #endif
2503 heikki.linnakangas@i 546 [ + + ]: 24883 : if (conn->sasl_state)
547 : : {
1012 michael@paquier.xyz 548 : 43 : conn->sasl->free(conn->sasl_state);
2503 heikki.linnakangas@i 549 : 43 : conn->sasl_state = NULL;
550 : : }
4237 tgl@sss.pgh.pa.us 551 : 24883 : }
552 : :
553 : : /*
554 : : * pqFreeCommandQueue
555 : : * Free all the entries of PGcmdQueueEntry queue passed.
556 : : */
557 : : static void
1126 alvherre@alvh.no-ip. 558 : 49766 : pqFreeCommandQueue(PGcmdQueueEntry *queue)
559 : : {
560 [ + + ]: 61696 : while (queue != NULL)
561 : : {
562 : 11930 : PGcmdQueueEntry *cur = queue;
563 : :
564 : 11930 : queue = cur->next;
668 peter@eisentraut.org 565 : 11930 : free(cur->query);
1126 alvherre@alvh.no-ip. 566 : 11930 : free(cur);
567 : : }
568 : 49766 : }
569 : :
570 : : /*
571 : : * pqDropServerData
572 : : *
573 : : * Clear all connection state data that was received from (or deduced about)
574 : : * the server. This is essential to do between connection attempts to
575 : : * different servers, else we may incorrectly hold over some data from the
576 : : * old server.
577 : : *
578 : : * It would be better to merge this into pqDropConnection, perhaps, but
579 : : * right now we cannot because that function is called immediately on
580 : : * detection of connection loss (cf. pqReadData, for instance). This data
581 : : * should be kept until we are actually starting a new connection.
582 : : */
583 : : static void
2078 tgl@sss.pgh.pa.us 584 : 24432 : pqDropServerData(PGconn *conn)
585 : : {
586 : : PGnotify *notify;
587 : : pgParameterStatus *pstatus;
588 : :
589 : : /* Forget pending notifies */
590 : 24432 : notify = conn->notifyHead;
591 [ - + ]: 24432 : while (notify != NULL)
592 : : {
2078 tgl@sss.pgh.pa.us 593 :UBC 0 : PGnotify *prev = notify;
594 : :
595 : 0 : notify = notify->next;
596 : 0 : free(prev);
597 : : }
2078 tgl@sss.pgh.pa.us 598 :CBC 24432 : conn->notifyHead = conn->notifyTail = NULL;
599 : :
600 : : /* Reset ParameterStatus data, as well as variables deduced from it */
601 : 24432 : pstatus = conn->pstatus;
602 [ + + ]: 181624 : while (pstatus != NULL)
603 : : {
604 : 157192 : pgParameterStatus *prev = pstatus;
605 : :
606 : 157192 : pstatus = pstatus->next;
607 : 157192 : free(prev);
608 : : }
609 : 24432 : conn->pstatus = NULL;
610 : 24432 : conn->client_encoding = PG_SQL_ASCII;
611 : 24432 : conn->std_strings = false;
1139 612 : 24432 : conn->default_transaction_read_only = PG_BOOL_UNKNOWN;
613 : 24432 : conn->in_hot_standby = PG_BOOL_UNKNOWN;
384 dgustafsson@postgres 614 : 24432 : conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
2078 tgl@sss.pgh.pa.us 615 : 24432 : conn->sversion = 0;
616 : :
617 : : /* Drop large-object lookup data */
668 peter@eisentraut.org 618 : 24432 : free(conn->lobjfuncs);
2078 tgl@sss.pgh.pa.us 619 : 24432 : conn->lobjfuncs = NULL;
620 : :
621 : : /* Reset assorted other per-connection state */
622 : 24432 : conn->last_sqlstate[0] = '\0';
623 : 24432 : conn->auth_req_received = false;
397 michael@paquier.xyz 624 : 24432 : conn->client_finished_auth = false;
2078 tgl@sss.pgh.pa.us 625 : 24432 : conn->password_needed = false;
367 sfrost@snowman.net 626 : 24432 : conn->gssapi_used = false;
1853 tgl@sss.pgh.pa.us 627 : 24432 : conn->write_failed = false;
668 peter@eisentraut.org 628 : 24432 : free(conn->write_err_msg);
1853 tgl@sss.pgh.pa.us 629 : 24432 : conn->write_err_msg = NULL;
630 : :
631 : : /*
632 : : * Cancel connections need to retain their be_pid and be_key across
633 : : * PQcancelReset invocations, otherwise they would not have access to the
634 : : * secret token of the connection they are supposed to cancel.
635 : : */
33 alvherre@alvh.no-ip. 636 [ + + ]:GNC 24432 : if (!conn->cancelRequest)
637 : : {
638 : 24426 : conn->be_pid = 0;
639 : 24426 : conn->be_key = 0;
640 : : }
2078 tgl@sss.pgh.pa.us 641 :CBC 24432 : }
642 : :
643 : :
644 : : /*
645 : : * Connecting to a Database
646 : : *
647 : : * There are now six different ways a user of this API can connect to the
648 : : * database. Two are not recommended for use in new code, because of their
649 : : * lack of extensibility with respect to the passing of options to the
650 : : * backend. These are PQsetdb and PQsetdbLogin (the former now being a macro
651 : : * to the latter).
652 : : *
653 : : * If it is desired to connect in a synchronous (blocking) manner, use the
654 : : * function PQconnectdb or PQconnectdbParams. The former accepts a string of
655 : : * option = value pairs (or a URI) which must be parsed; the latter takes two
656 : : * NULL terminated arrays instead.
657 : : *
658 : : * To connect in an asynchronous (non-blocking) manner, use the functions
659 : : * PQconnectStart or PQconnectStartParams (which differ in the same way as
660 : : * PQconnectdb and PQconnectdbParams) and PQconnectPoll.
661 : : *
662 : : * The non-exported functions pqConnectDBStart, pqConnectDBComplete are
663 : : * part of the connection procedure implementation.
664 : : */
665 : :
666 : : /*
667 : : * PQconnectdbParams
668 : : *
669 : : * establishes a connection to a postgres backend through the postmaster
670 : : * using connection information in two arrays.
671 : : *
672 : : * The keywords array is defined as
673 : : *
674 : : * const char *params[] = {"option1", "option2", NULL}
675 : : *
676 : : * The values array is defined as
677 : : *
678 : : * const char *values[] = {"value1", "value2", NULL}
679 : : *
680 : : * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL
681 : : * if a memory allocation failed.
682 : : * If the status field of the connection returned is CONNECTION_BAD,
683 : : * then some fields may be null'ed out instead of having valid values.
684 : : *
685 : : * You should call PQfinish (if conn is not NULL) regardless of whether this
686 : : * call succeeded.
687 : : */
688 : : PGconn *
2489 689 : 9828 : PQconnectdbParams(const char *const *keywords,
690 : : const char *const *values,
691 : : int expand_dbname)
692 : : {
5182 mail@joeconway.com 693 : 9828 : PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname);
694 : :
5190 695 [ + - + + ]: 9828 : if (conn && conn->status != CONNECTION_BAD)
70 alvherre@alvh.no-ip. 696 :GNC 9802 : (void) pqConnectDBComplete(conn);
697 : :
5190 mail@joeconway.com 698 :CBC 9828 : return conn;
699 : : }
700 : :
701 : : /*
702 : : * PQpingParams
703 : : *
704 : : * check server status, accepting parameters identical to PQconnectdbParams
705 : : */
706 : : PGPing
2489 tgl@sss.pgh.pa.us 707 : 281 : PQpingParams(const char *const *keywords,
708 : : const char *const *values,
709 : : int expand_dbname)
710 : : {
4889 bruce@momjian.us 711 : 281 : PGconn *conn = PQconnectStartParams(keywords, values, expand_dbname);
712 : : PGPing ret;
713 : :
714 : 281 : ret = internal_ping(conn);
715 : 281 : PQfinish(conn);
716 : :
717 : 281 : return ret;
718 : : }
719 : :
720 : : /*
721 : : * PQconnectdb
722 : : *
723 : : * establishes a connection to a postgres backend through the postmaster
724 : : * using connection information in a string.
725 : : *
726 : : * The conninfo string is either a whitespace-separated list of
727 : : *
728 : : * option = value
729 : : *
730 : : * definitions or a URI (refer to the documentation for details.) Value
731 : : * might be a single value containing no whitespaces or a single quoted
732 : : * string. If a single quote should appear anywhere in the value, it must be
733 : : * escaped with a backslash like \'
734 : : *
735 : : * Returns a PGconn* which is needed for all subsequent libpq calls, or NULL
736 : : * if a memory allocation failed.
737 : : * If the status field of the connection returned is CONNECTION_BAD,
738 : : * then some fields may be null'ed out instead of having valid values.
739 : : *
740 : : * You should call PQfinish (if conn is not NULL) regardless of whether this
741 : : * call succeeded.
742 : : */
743 : : PGconn *
10018 scrappy@hub.org 744 : 829 : PQconnectdb(const char *conninfo)
745 : : {
8768 bruce@momjian.us 746 : 829 : PGconn *conn = PQconnectStart(conninfo);
747 : :
8857 tgl@sss.pgh.pa.us 748 [ + - + - ]: 829 : if (conn && conn->status != CONNECTION_BAD)
70 alvherre@alvh.no-ip. 749 :GNC 829 : (void) pqConnectDBComplete(conn);
750 : :
8902 bruce@momjian.us 751 :CBC 829 : return conn;
752 : : }
753 : :
754 : : /*
755 : : * PQping
756 : : *
757 : : * check server status, accepting parameters identical to PQconnectdb
758 : : */
759 : : PGPing
4889 bruce@momjian.us 760 :UBC 0 : PQping(const char *conninfo)
761 : : {
762 : 0 : PGconn *conn = PQconnectStart(conninfo);
763 : : PGPing ret;
764 : :
765 : 0 : ret = internal_ping(conn);
766 : 0 : PQfinish(conn);
767 : :
768 : 0 : return ret;
769 : : }
770 : :
771 : : /*
772 : : * PQconnectStartParams
773 : : *
774 : : * Begins the establishment of a connection to a postgres backend through the
775 : : * postmaster using connection information in a struct.
776 : : *
777 : : * See comment for PQconnectdbParams for the definition of the string format.
778 : : *
779 : : * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and
780 : : * you should not attempt to proceed with this connection. If the status
781 : : * field of the connection returned is CONNECTION_BAD, an error has
782 : : * occurred. In this case you should call PQfinish on the result, (perhaps
783 : : * inspecting the error message first). Other fields of the structure may not
784 : : * be valid if that occurs. If the status field is not CONNECTION_BAD, then
785 : : * this stage has succeeded - call PQconnectPoll, using select(2) to see when
786 : : * this is necessary.
787 : : *
788 : : * See PQconnectPoll for more info.
789 : : */
790 : : PGconn *
2489 tgl@sss.pgh.pa.us 791 :CBC 11237 : PQconnectStartParams(const char *const *keywords,
792 : : const char *const *values,
793 : : int expand_dbname)
794 : : {
795 : : PGconn *conn;
796 : : PQconninfoOption *connOptions;
797 : :
798 : : /*
799 : : * Allocate memory for the conn structure. Note that we also expect this
800 : : * to initialize conn->errorMessage to empty. All subsequent steps during
801 : : * connection initialization will only append to that buffer.
802 : : */
70 alvherre@alvh.no-ip. 803 :GNC 11237 : conn = pqMakeEmptyPGconn();
9716 bruce@momjian.us 804 [ - + ]:CBC 11237 : if (conn == NULL)
7403 neilc@samurai.com 805 :UBC 0 : return NULL;
806 : :
807 : : /*
808 : : * Parse the conninfo arrays
809 : : */
5190 mail@joeconway.com 810 :CBC 11237 : connOptions = conninfo_array_parse(keywords, values,
811 : : &conn->errorMessage,
812 : : true, expand_dbname);
813 [ - + ]: 11237 : if (connOptions == NULL)
814 : : {
5190 mail@joeconway.com 815 :UBC 0 : conn->status = CONNECTION_BAD;
816 : : /* errorMessage is already set */
4761 tgl@sss.pgh.pa.us 817 : 0 : return conn;
818 : : }
819 : :
820 : : /*
821 : : * Move option values into conn structure
822 : : */
3428 heikki.linnakangas@i 823 [ - + ]:CBC 11237 : if (!fillPGconn(conn, connOptions))
824 : : {
3428 heikki.linnakangas@i 825 :UBC 0 : PQconninfoFree(connOptions);
826 : 0 : return conn;
827 : : }
828 : :
829 : : /*
830 : : * Free the option info - all is in conn now
831 : : */
5190 mail@joeconway.com 832 :CBC 11237 : PQconninfoFree(connOptions);
833 : :
834 : : /*
835 : : * Compute derived options
836 : : */
70 alvherre@alvh.no-ip. 837 [ + + ]:GNC 11237 : if (!pqConnectOptions2(conn))
7657 tgl@sss.pgh.pa.us 838 :CBC 13 : return conn;
839 : :
840 : : /*
841 : : * Connect to the database
842 : : */
70 alvherre@alvh.no-ip. 843 [ + + ]:GNC 11224 : if (!pqConnectDBStart(conn))
844 : : {
845 : : /* Just in case we failed to set it in pqConnectDBStart */
7657 tgl@sss.pgh.pa.us 846 :CBC 341 : conn->status = CONNECTION_BAD;
847 : : }
848 : :
849 : 11224 : return conn;
850 : : }
851 : :
852 : : /*
853 : : * PQconnectStart
854 : : *
855 : : * Begins the establishment of a connection to a postgres backend through the
856 : : * postmaster using connection information in a string.
857 : : *
858 : : * See comment for PQconnectdb for the definition of the string format.
859 : : *
860 : : * Returns a PGconn*. If NULL is returned, a malloc error has occurred, and
861 : : * you should not attempt to proceed with this connection. If the status
862 : : * field of the connection returned is CONNECTION_BAD, an error has
863 : : * occurred. In this case you should call PQfinish on the result, (perhaps
864 : : * inspecting the error message first). Other fields of the structure may not
865 : : * be valid if that occurs. If the status field is not CONNECTION_BAD, then
866 : : * this stage has succeeded - call PQconnectPoll, using select(2) to see when
867 : : * this is necessary.
868 : : *
869 : : * See PQconnectPoll for more info.
870 : : */
871 : : PGconn *
5190 mail@joeconway.com 872 : 853 : PQconnectStart(const char *conninfo)
873 : : {
874 : : PGconn *conn;
875 : :
876 : : /*
877 : : * Allocate memory for the conn structure. Note that we also expect this
878 : : * to initialize conn->errorMessage to empty. All subsequent steps during
879 : : * connection initialization will only append to that buffer.
880 : : */
70 alvherre@alvh.no-ip. 881 :GNC 853 : conn = pqMakeEmptyPGconn();
5190 mail@joeconway.com 882 [ - + ]:CBC 853 : if (conn == NULL)
5190 mail@joeconway.com 883 :UBC 0 : return NULL;
884 : :
885 : : /*
886 : : * Parse the conninfo string
887 : : */
5190 mail@joeconway.com 888 [ + + ]:CBC 853 : if (!connectOptions1(conn, conninfo))
889 : 2 : return conn;
890 : :
891 : : /*
892 : : * Compute derived options
893 : : */
70 alvherre@alvh.no-ip. 894 [ - + ]:GNC 851 : if (!pqConnectOptions2(conn))
5190 mail@joeconway.com 895 :UBC 0 : return conn;
896 : :
897 : : /*
898 : : * Connect to the database
899 : : */
70 alvherre@alvh.no-ip. 900 [ - + ]:GNC 851 : if (!pqConnectDBStart(conn))
901 : : {
902 : : /* Just in case we failed to set it in pqConnectDBStart */
9716 bruce@momjian.us 903 :UBC 0 : conn->status = CONNECTION_BAD;
904 : : }
905 : :
5190 mail@joeconway.com 906 :CBC 851 : return conn;
907 : : }
908 : :
909 : : /*
910 : : * Move option values into conn structure
911 : : *
912 : : * Don't put anything cute here --- intelligence should be in
913 : : * pqConnectOptions2 ...
914 : : *
915 : : * Returns true on success. On failure, returns false and sets error message.
916 : : */
917 : : static bool
918 : 12088 : fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
919 : : {
920 : : const internalPQconninfoOption *option;
921 : :
4153 magnus@hagander.net 922 [ + + ]: 507696 : for (option = PQconninfoOptions; option->keyword; option++)
923 : : {
3423 tgl@sss.pgh.pa.us 924 [ + + ]: 495608 : if (option->connofs >= 0)
925 : : {
926 : 483520 : const char *tmp = conninfo_getval(connOptions, option->keyword);
927 : :
3428 heikki.linnakangas@i 928 [ + + ]: 483520 : if (tmp)
929 : : {
3423 tgl@sss.pgh.pa.us 930 : 219488 : char **connmember = (char **) ((char *) conn + option->connofs);
931 : :
668 peter@eisentraut.org 932 : 219488 : free(*connmember);
3428 heikki.linnakangas@i 933 : 219488 : *connmember = strdup(tmp);
934 [ - + ]: 219488 : if (*connmember == NULL)
935 : : {
516 peter@eisentraut.org 936 :UBC 0 : libpq_append_conn_error(conn, "out of memory");
3428 heikki.linnakangas@i 937 : 0 : return false;
938 : : }
939 : : }
940 : : }
941 : : }
942 : :
3428 heikki.linnakangas@i 943 :CBC 12088 : return true;
944 : : }
945 : :
946 : : /*
947 : : * Copy over option values from srcConn to dstConn
948 : : *
949 : : * Don't put anything cute here --- intelligence should be in
950 : : * connectOptions2 ...
951 : : *
952 : : * Returns true on success. On failure, returns false and sets error message of
953 : : * dstConn.
954 : : */
955 : : bool
33 alvherre@alvh.no-ip. 956 :GNC 5 : pqCopyPGconn(PGconn *srcConn, PGconn *dstConn)
957 : : {
958 : : const internalPQconninfoOption *option;
959 : :
960 : : /* copy over connection options */
961 [ + + ]: 210 : for (option = PQconninfoOptions; option->keyword; option++)
962 : : {
963 [ + + ]: 205 : if (option->connofs >= 0)
964 : : {
965 : 200 : const char **tmp = (const char **) ((char *) srcConn + option->connofs);
966 : :
967 [ + + ]: 200 : if (*tmp)
968 : : {
969 : 99 : char **dstConnmember = (char **) ((char *) dstConn + option->connofs);
970 : :
971 [ - + ]: 99 : if (*dstConnmember)
33 alvherre@alvh.no-ip. 972 :UNC 0 : free(*dstConnmember);
33 alvherre@alvh.no-ip. 973 :GNC 99 : *dstConnmember = strdup(*tmp);
974 [ - + ]: 99 : if (*dstConnmember == NULL)
975 : : {
33 alvherre@alvh.no-ip. 976 :UNC 0 : libpq_append_conn_error(dstConn, "out of memory");
977 : 0 : return false;
978 : : }
979 : : }
980 : : }
981 : : }
33 alvherre@alvh.no-ip. 982 :GNC 5 : return true;
983 : : }
984 : :
985 : : /*
986 : : * connectOptions1
987 : : *
988 : : * Internal subroutine to set up connection parameters given an already-
989 : : * created PGconn and a conninfo string. Derived settings should be
990 : : * processed by calling pqConnectOptions2 next. (We split them because
991 : : * PQsetdbLogin overrides defaults in between.)
992 : : *
993 : : * Returns true if OK, false if trouble (in which case errorMessage is set
994 : : * and so is conn->status).
995 : : */
996 : : static bool
5190 mail@joeconway.com 997 :CBC 853 : connectOptions1(PGconn *conn, const char *conninfo)
998 : : {
999 : : PQconninfoOption *connOptions;
1000 : :
1001 : : /*
1002 : : * Parse the conninfo string
1003 : : */
4386 alvherre@alvh.no-ip. 1004 : 853 : connOptions = parse_connection_string(conninfo, &conn->errorMessage, true);
5190 mail@joeconway.com 1005 [ + + ]: 853 : if (connOptions == NULL)
1006 : : {
1007 : 2 : conn->status = CONNECTION_BAD;
1008 : : /* errorMessage is already set */
1009 : 2 : return false;
1010 : : }
1011 : :
1012 : : /*
1013 : : * Move option values into conn structure
1014 : : */
3428 heikki.linnakangas@i 1015 [ - + ]: 851 : if (!fillPGconn(conn, connOptions))
1016 : : {
3428 heikki.linnakangas@i 1017 :UBC 0 : conn->status = CONNECTION_BAD;
1018 : 0 : PQconninfoFree(connOptions);
1019 : 0 : return false;
1020 : : }
1021 : :
1022 : : /*
1023 : : * Free the option info - all is in conn now
1024 : : */
8800 tgl@sss.pgh.pa.us 1025 :CBC 851 : PQconninfoFree(connOptions);
1026 : :
7657 1027 : 851 : return true;
1028 : : }
1029 : :
1030 : : /*
1031 : : * Count the number of elements in a simple comma-separated list.
1032 : : */
1033 : : static int
2470 heikki.linnakangas@i 1034 : 12093 : count_comma_separated_elems(const char *input)
1035 : : {
1036 : : int n;
1037 : :
1038 : 12093 : n = 1;
1039 [ + + ]: 204571 : for (; *input != '\0'; input++)
1040 : : {
1041 [ + + ]: 192478 : if (*input == ',')
1042 : 133 : n++;
1043 : : }
1044 : :
1045 : 12093 : return n;
1046 : : }
1047 : :
1048 : : /*
1049 : : * Parse a simple comma-separated list.
1050 : : *
1051 : : * On each call, returns a malloc'd copy of the next element, and sets *more
1052 : : * to indicate whether there are any more elements in the list after this,
1053 : : * and updates *startptr to point to the next element, if any.
1054 : : *
1055 : : * On out of memory, returns NULL.
1056 : : */
1057 : : static char *
1058 : 25063 : parse_comma_separated_list(char **startptr, bool *more)
1059 : : {
1060 : : char *p;
1061 : 25063 : char *s = *startptr;
1062 : : char *e;
1063 : : int len;
1064 : :
1065 : : /*
1066 : : * Search for the end of the current element; a comma or end-of-string
1067 : : * acts as a terminator.
1068 : : */
1069 : 25063 : e = s;
1070 [ + + + + ]: 297923 : while (*e != '\0' && *e != ',')
1071 : 272860 : ++e;
1072 : 25063 : *more = (*e == ',');
1073 : :
1074 : 25063 : len = e - s;
1075 : 25063 : p = (char *) malloc(sizeof(char) * (len + 1));
1076 [ + - ]: 25063 : if (p)
1077 : : {
1078 : 25063 : memcpy(p, s, len);
1079 : 25063 : p[len] = '\0';
1080 : : }
1081 : 25063 : *startptr = e + 1;
1082 : :
1083 : 25063 : return p;
1084 : : }
1085 : :
1086 : : /*
1087 : : * Initializes the prng_state field of the connection. We want something
1088 : : * unpredictable, so if possible, use high-quality random bits for the
1089 : : * seed. Otherwise, fall back to a seed based on the connection address,
1090 : : * timestamp and PID.
1091 : : */
1092 : : static void
382 dgustafsson@postgres 1093 : 110 : libpq_prng_init(PGconn *conn)
1094 : : {
1095 : : uint64 rseed;
1096 : 110 : struct timeval tval = {0};
1097 : :
1098 [ + - + - ]: 110 : if (pg_prng_strong_seed(&conn->prng_state))
1099 : 110 : return;
1100 : :
382 dgustafsson@postgres 1101 :UBC 0 : gettimeofday(&tval, NULL);
1102 : :
381 1103 : 0 : rseed = ((uintptr_t) conn) ^
331 tgl@sss.pgh.pa.us 1104 : 0 : ((uint64) getpid()) ^
1105 : 0 : ((uint64) tval.tv_usec) ^
1106 : 0 : ((uint64) tval.tv_sec);
1107 : :
382 dgustafsson@postgres 1108 : 0 : pg_prng_seed(&conn->prng_state, rseed);
1109 : : }
1110 : :
1111 : : /*
1112 : : * pqConnectOptions2
1113 : : *
1114 : : * Compute derived connection options after absorbing all user-supplied info.
1115 : : *
1116 : : * Returns true if OK, false if trouble (in which case errorMessage is set
1117 : : * and so is conn->status).
1118 : : */
1119 : : bool
70 alvherre@alvh.no-ip. 1120 :GNC 12093 : pqConnectOptions2(PGconn *conn)
1121 : : {
1122 : : int i;
1123 : :
1124 : : /*
1125 : : * Allocate memory for details about each host to which we might possibly
1126 : : * try to connect. For that, count the number of elements in the hostaddr
1127 : : * or host options. If neither is given, assume one host.
1128 : : */
2719 rhaas@postgresql.org 1129 :CBC 12093 : conn->whichhost = 0;
2470 heikki.linnakangas@i 1130 [ + + + - ]: 12093 : if (conn->pghostaddr && conn->pghostaddr[0] != '\0')
1131 : 528 : conn->nconnhost = count_comma_separated_elems(conn->pghostaddr);
1132 [ + - + - ]: 11565 : else if (conn->pghost && conn->pghost[0] != '\0')
1133 : 11565 : conn->nconnhost = count_comma_separated_elems(conn->pghost);
1134 : : else
2470 heikki.linnakangas@i 1135 :UBC 0 : conn->nconnhost = 1;
2719 rhaas@postgresql.org 1136 :CBC 12093 : conn->connhost = (pg_conn_host *)
1137 : 12093 : calloc(conn->nconnhost, sizeof(pg_conn_host));
1138 [ - + ]: 12093 : if (conn->connhost == NULL)
2719 rhaas@postgresql.org 1139 :UBC 0 : goto oom_error;
1140 : :
1141 : : /*
1142 : : * We now have one pg_conn_host structure per possible host. Fill in the
1143 : : * host and hostaddr fields for each, by splitting the parameter strings.
1144 : : */
2719 rhaas@postgresql.org 1145 [ + + + - ]:CBC 12093 : if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
1146 : : {
2470 heikki.linnakangas@i 1147 : 528 : char *s = conn->pghostaddr;
1148 : 528 : bool more = true;
1149 : :
1150 [ + + + - ]: 1056 : for (i = 0; i < conn->nconnhost && more; i++)
1151 : : {
1152 : 528 : conn->connhost[i].hostaddr = parse_comma_separated_list(&s, &more);
1153 [ - + ]: 528 : if (conn->connhost[i].hostaddr == NULL)
2470 heikki.linnakangas@i 1154 :UBC 0 : goto oom_error;
1155 : : }
1156 : :
1157 : : /*
1158 : : * If hostaddr was given, the array was allocated according to the
1159 : : * number of elements in the hostaddr list, so it really should be the
1160 : : * right size.
1161 : : */
2470 heikki.linnakangas@i 1162 [ - + ]:CBC 528 : Assert(!more);
1163 [ - + ]: 528 : Assert(i == conn->nconnhost);
1164 : : }
1165 : :
1166 [ + - + - ]: 12093 : if (conn->pghost != NULL && conn->pghost[0] != '\0')
1167 : : {
2524 bruce@momjian.us 1168 : 12093 : char *s = conn->pghost;
2470 heikki.linnakangas@i 1169 : 12093 : bool more = true;
1170 : :
1171 [ + + + - ]: 24319 : for (i = 0; i < conn->nconnhost && more; i++)
1172 : : {
1173 : 12226 : conn->connhost[i].host = parse_comma_separated_list(&s, &more);
2719 rhaas@postgresql.org 1174 [ - + ]: 12226 : if (conn->connhost[i].host == NULL)
2719 rhaas@postgresql.org 1175 :UBC 0 : goto oom_error;
1176 : : }
1177 : :
1178 : : /* Check for wrong number of host items. */
2470 heikki.linnakangas@i 1179 [ + - - + ]:CBC 12093 : if (more || i != conn->nconnhost)
1180 : : {
2470 heikki.linnakangas@i 1181 :UBC 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1182 : 0 : libpq_append_conn_error(conn, "could not match %d host names to %d hostaddr values",
402 michael@paquier.xyz 1183 : 0 : count_comma_separated_elems(conn->pghost), conn->nconnhost);
2470 heikki.linnakangas@i 1184 : 0 : return false;
1185 : : }
1186 : : }
1187 : :
1188 : : /*
1189 : : * Now, for each host slot, identify the type of address spec, and fill in
1190 : : * the default address if nothing was given.
1191 : : */
2083 tgl@sss.pgh.pa.us 1192 [ + + ]:CBC 24319 : for (i = 0; i < conn->nconnhost; i++)
1193 : : {
1194 : 12226 : pg_conn_host *ch = &conn->connhost[i];
1195 : :
1196 [ + + + - ]: 12226 : if (ch->hostaddr != NULL && ch->hostaddr[0] != '\0')
1197 : 528 : ch->type = CHT_HOST_ADDRESS;
1198 [ + - + - ]: 11698 : else if (ch->host != NULL && ch->host[0] != '\0')
1199 : : {
1200 : 11698 : ch->type = CHT_HOST_NAME;
1236 peter@eisentraut.org 1201 [ + + ]: 23339 : if (is_unixsock_path(ch->host))
2083 tgl@sss.pgh.pa.us 1202 : 11641 : ch->type = CHT_UNIX_SOCKET;
1203 : : }
1204 : : else
1205 : : {
668 peter@eisentraut.org 1206 :UBC 0 : free(ch->host);
1207 : :
1208 : : /*
1209 : : * This bit selects the default host location. If you change
1210 : : * this, see also pg_regress.
1211 : : */
1535 1212 [ # # ]: 0 : if (DEFAULT_PGSOCKET_DIR[0])
1213 : : {
1214 : 0 : ch->host = strdup(DEFAULT_PGSOCKET_DIR);
1215 : 0 : ch->type = CHT_UNIX_SOCKET;
1216 : : }
1217 : : else
1218 : : {
1219 : 0 : ch->host = strdup(DefaultHost);
1220 : 0 : ch->type = CHT_HOST_NAME;
1221 : : }
2083 tgl@sss.pgh.pa.us 1222 [ # # ]: 0 : if (ch->host == NULL)
1223 : 0 : goto oom_error;
1224 : : }
1225 : : }
1226 : :
1227 : : /*
1228 : : * Next, work out the port number corresponding to each host name.
1229 : : *
1230 : : * Note: unlike the above for host names, this could leave the port fields
1231 : : * as null or empty strings. We will substitute DEF_PGPORT whenever we
1232 : : * read such a port field.
1233 : : */
2719 rhaas@postgresql.org 1234 [ + - + - ]:CBC 12093 : if (conn->pgport != NULL && conn->pgport[0] != '\0')
1235 : : {
2524 bruce@momjian.us 1236 : 12093 : char *s = conn->pgport;
2470 heikki.linnakangas@i 1237 : 12093 : bool more = true;
1238 : :
1239 [ + + + - ]: 24319 : for (i = 0; i < conn->nconnhost && more; i++)
1240 : : {
1241 : 12226 : conn->connhost[i].port = parse_comma_separated_list(&s, &more);
1242 [ - + ]: 12226 : if (conn->connhost[i].port == NULL)
2470 heikki.linnakangas@i 1243 :UBC 0 : goto oom_error;
1244 : : }
1245 : :
1246 : : /*
1247 : : * If exactly one port was given, use it for every host. Otherwise,
1248 : : * there must be exactly as many ports as there were hosts.
1249 : : */
2470 heikki.linnakangas@i 1250 [ + + + - ]:CBC 12093 : if (i == 1 && !more)
1251 : : {
1252 [ - + ]: 12018 : for (i = 1; i < conn->nconnhost; i++)
1253 : : {
2470 heikki.linnakangas@i 1254 :UBC 0 : conn->connhost[i].port = strdup(conn->connhost[0].port);
2719 rhaas@postgresql.org 1255 [ # # ]: 0 : if (conn->connhost[i].port == NULL)
1256 : 0 : goto oom_error;
1257 : : }
1258 : : }
2470 heikki.linnakangas@i 1259 [ + - - + ]:CBC 75 : else if (more || i != conn->nconnhost)
1260 : : {
2719 rhaas@postgresql.org 1261 :UBC 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1262 : 0 : libpq_append_conn_error(conn, "could not match %d port numbers to %d hosts",
402 michael@paquier.xyz 1263 : 0 : count_comma_separated_elems(conn->pgport), conn->nconnhost);
2719 rhaas@postgresql.org 1264 : 0 : return false;
1265 : : }
1266 : : }
1267 : :
1268 : : /*
1269 : : * If user name was not given, fetch it. (Most likely, the fetch will
1270 : : * fail, since the only way we get here is if pg_fe_getauthname() failed
1271 : : * during conninfo_add_defaults(). But now we want an error message.)
1272 : : */
3381 tgl@sss.pgh.pa.us 1273 [ + - - + ]:CBC 12093 : if (conn->pguser == NULL || conn->pguser[0] == '\0')
1274 : : {
668 peter@eisentraut.org 1275 :UBC 0 : free(conn->pguser);
3381 tgl@sss.pgh.pa.us 1276 : 0 : conn->pguser = pg_fe_getauthname(&conn->errorMessage);
1277 [ # # ]: 0 : if (!conn->pguser)
1278 : : {
1279 : 0 : conn->status = CONNECTION_BAD;
1280 : 0 : return false;
1281 : : }
1282 : : }
1283 : :
1284 : : /*
1285 : : * If database name was not given, default it to equal user name
1286 : : */
3381 tgl@sss.pgh.pa.us 1287 [ + + + + ]:CBC 12093 : if (conn->dbName == NULL || conn->dbName[0] == '\0')
1288 : : {
668 peter@eisentraut.org 1289 : 3 : free(conn->dbName);
7650 tgl@sss.pgh.pa.us 1290 : 3 : conn->dbName = strdup(conn->pguser);
3428 heikki.linnakangas@i 1291 [ - + ]: 3 : if (!conn->dbName)
3428 heikki.linnakangas@i 1292 :UBC 0 : goto oom_error;
1293 : : }
1294 : :
1295 : : /*
1296 : : * If password was not given, try to look it up in password file. Note
1297 : : * that the result might be different for each host/port pair.
1298 : : */
7657 tgl@sss.pgh.pa.us 1299 [ + + + + ]:CBC 12093 : if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
1300 : : {
1301 : : /* If password file wasn't specified, use ~/PGPASSFILE */
2637 1302 [ + + - + ]: 11946 : if (conn->pgpassfile == NULL || conn->pgpassfile[0] == '\0')
1303 : : {
1304 : : char homedir[MAXPGPATH];
1305 : :
2363 1306 [ + - ]: 11779 : if (pqGetHomeDirectory(homedir, sizeof(homedir)))
1307 : : {
668 peter@eisentraut.org 1308 : 11779 : free(conn->pgpassfile);
2363 tgl@sss.pgh.pa.us 1309 : 11779 : conn->pgpassfile = malloc(MAXPGPATH);
1310 [ - + ]: 11779 : if (!conn->pgpassfile)
2363 tgl@sss.pgh.pa.us 1311 :UBC 0 : goto oom_error;
2363 tgl@sss.pgh.pa.us 1312 :CBC 11779 : snprintf(conn->pgpassfile, MAXPGPATH, "%s/%s",
1313 : : homedir, PGPASSFILE);
1314 : : }
1315 : : }
1316 : :
1317 [ + - + - ]: 11946 : if (conn->pgpassfile != NULL && conn->pgpassfile[0] != '\0')
1318 : : {
1319 [ + + ]: 24025 : for (i = 0; i < conn->nconnhost; i++)
1320 : : {
1321 : : /*
1322 : : * Try to get a password for this host from file. We use host
1323 : : * for the hostname search key if given, else hostaddr (at
1324 : : * least one of them is guaranteed nonempty by now).
1325 : : */
2083 1326 : 12079 : const char *pwhost = conn->connhost[i].host;
1327 : :
1328 [ + - - + ]: 12079 : if (pwhost == NULL || pwhost[0] == '\0')
2363 tgl@sss.pgh.pa.us 1329 :UBC 0 : pwhost = conn->connhost[i].hostaddr;
1330 : :
2363 tgl@sss.pgh.pa.us 1331 :CBC 12079 : conn->connhost[i].password =
1332 : 12079 : passwordFromFile(pwhost,
1333 : 12079 : conn->connhost[i].port,
1334 : 12079 : conn->dbName,
1335 : 12079 : conn->pguser,
1336 : 12079 : conn->pgpassfile);
1337 : : }
1338 : : }
1339 : : }
1340 : :
1341 : : /*
1342 : : * parse and validate require_auth option
1343 : : */
397 michael@paquier.xyz 1344 [ + + + + ]: 12093 : if (conn->require_auth && conn->require_auth[0])
1345 : : {
1346 : 56 : char *s = conn->require_auth;
1347 : : bool first,
1348 : : more;
1349 : 56 : bool negated = false;
1350 : :
1351 : : /*
1352 : : * By default, start from an empty set of allowed options and add to
1353 : : * it.
1354 : : */
1355 : 56 : conn->auth_required = true;
1356 : 56 : conn->allowed_auth_methods = 0;
1357 : :
1358 [ + + ]: 132 : for (first = true, more = true; more; first = false)
1359 : 64 : {
1360 : : char *method,
1361 : : *part;
1362 : : uint32 bits;
1363 : :
1364 : 83 : part = parse_comma_separated_list(&s, &more);
1365 [ - + ]: 83 : if (part == NULL)
397 michael@paquier.xyz 1366 :UBC 0 : goto oom_error;
1367 : :
1368 : : /*
1369 : : * Check for negation, e.g. '!password'. If one element is
1370 : : * negated, they all have to be.
1371 : : */
397 michael@paquier.xyz 1372 :CBC 83 : method = part;
1373 [ + + ]: 83 : if (*method == '!')
1374 : : {
1375 [ + + ]: 32 : if (first)
1376 : : {
1377 : : /*
1378 : : * Switch to a permissive set of allowed options, and
1379 : : * subtract from it.
1380 : : */
1381 : 19 : conn->auth_required = false;
1382 : 19 : conn->allowed_auth_methods = -1;
1383 : : }
1384 [ + + ]: 13 : else if (!negated)
1385 : : {
1386 : 1 : conn->status = CONNECTION_BAD;
1387 : 1 : libpq_append_conn_error(conn, "negative require_auth method \"%s\" cannot be mixed with non-negative methods",
1388 : : method);
1389 : :
1390 : 1 : free(part);
1391 : 7 : return false;
1392 : : }
1393 : :
1394 : 31 : negated = true;
1395 : 31 : method++;
1396 : : }
1397 [ + + ]: 51 : else if (negated)
1398 : : {
1399 : 1 : conn->status = CONNECTION_BAD;
1400 : 1 : libpq_append_conn_error(conn, "require_auth method \"%s\" cannot be mixed with negative methods",
1401 : : method);
1402 : :
1403 : 1 : free(part);
1404 : 1 : return false;
1405 : : }
1406 : :
1407 [ + + ]: 81 : if (strcmp(method, "password") == 0)
1408 : : {
1409 : 20 : bits = (1 << AUTH_REQ_PASSWORD);
1410 : : }
1411 [ + + ]: 61 : else if (strcmp(method, "md5") == 0)
1412 : : {
1413 : 16 : bits = (1 << AUTH_REQ_MD5);
1414 : : }
1415 [ + + ]: 45 : else if (strcmp(method, "gss") == 0)
1416 : : {
1417 : 6 : bits = (1 << AUTH_REQ_GSS);
1418 : 6 : bits |= (1 << AUTH_REQ_GSS_CONT);
1419 : : }
1420 [ + + ]: 39 : else if (strcmp(method, "sspi") == 0)
1421 : : {
1422 : 4 : bits = (1 << AUTH_REQ_SSPI);
1423 : 4 : bits |= (1 << AUTH_REQ_GSS_CONT);
1424 : : }
1425 [ + + ]: 35 : else if (strcmp(method, "scram-sha-256") == 0)
1426 : : {
1427 : : /* This currently assumes that SCRAM is the only SASL method. */
1428 : 20 : bits = (1 << AUTH_REQ_SASL);
1429 : 20 : bits |= (1 << AUTH_REQ_SASL_CONT);
1430 : 20 : bits |= (1 << AUTH_REQ_SASL_FIN);
1431 : : }
1432 [ + + ]: 15 : else if (strcmp(method, "none") == 0)
1433 : : {
1434 : : /*
1435 : : * Special case: let the user explicitly allow (or disallow)
1436 : : * connections where the server does not send an explicit
1437 : : * authentication challenge, such as "trust" and "cert" auth.
1438 : : */
1439 [ + + ]: 14 : if (negated) /* "!none" */
1440 : : {
1441 [ + + ]: 7 : if (conn->auth_required)
1442 : 1 : goto duplicate;
1443 : :
1444 : 6 : conn->auth_required = true;
1445 : : }
1446 : : else /* "none" */
1447 : : {
1448 [ + + ]: 7 : if (!conn->auth_required)
1449 : 1 : goto duplicate;
1450 : :
1451 : 6 : conn->auth_required = false;
1452 : : }
1453 : :
1454 : 12 : free(part);
1455 : 12 : continue; /* avoid the bitmask manipulation below */
1456 : : }
1457 : : else
1458 : : {
1459 : 1 : conn->status = CONNECTION_BAD;
359 dgustafsson@postgres 1460 : 1 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1461 : : "require_auth", method);
1462 : :
397 michael@paquier.xyz 1463 : 1 : free(part);
1464 : 1 : return false;
1465 : : }
1466 : :
1467 : : /* Update the bitmask. */
1468 [ + + ]: 66 : if (negated)
1469 : : {
1470 [ + + ]: 24 : if ((conn->allowed_auth_methods & bits) == 0)
1471 : 1 : goto duplicate;
1472 : :
1473 : 23 : conn->allowed_auth_methods &= ~bits;
1474 : : }
1475 : : else
1476 : : {
1477 [ + + ]: 42 : if ((conn->allowed_auth_methods & bits) == bits)
1478 : 1 : goto duplicate;
1479 : :
1480 : 41 : conn->allowed_auth_methods |= bits;
1481 : : }
1482 : :
1483 : 64 : free(part);
1484 : 64 : continue;
1485 : :
1486 : 4 : duplicate:
1487 : :
1488 : : /*
1489 : : * A duplicated method probably indicates a typo in a setting
1490 : : * where typos are extremely risky.
1491 : : */
1492 : 4 : conn->status = CONNECTION_BAD;
1493 : 4 : libpq_append_conn_error(conn, "require_auth method \"%s\" is specified more than once",
1494 : : part);
1495 : :
1496 : 4 : free(part);
1497 : 4 : return false;
1498 : : }
1499 : : }
1500 : :
1501 : : /*
1502 : : * validate channel_binding option
1503 : : */
1665 jdavis@postgresql.or 1504 [ + - ]: 12086 : if (conn->channel_binding)
1505 : : {
1506 [ + + ]: 12086 : if (strcmp(conn->channel_binding, "disable") != 0
1507 [ + + ]: 12084 : && strcmp(conn->channel_binding, "prefer") != 0
1508 [ + + ]: 9 : && strcmp(conn->channel_binding, "require") != 0)
1509 : : {
1510 : 1 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1511 : 1 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1512 : : "channel_binding", conn->channel_binding);
1665 jdavis@postgresql.or 1513 : 1 : return false;
1514 : : }
1515 : : }
1516 : : else
1517 : : {
1665 jdavis@postgresql.or 1518 :UBC 0 : conn->channel_binding = strdup(DefaultChannelBinding);
1519 [ # # ]: 0 : if (!conn->channel_binding)
1520 : 0 : goto oom_error;
1521 : : }
1522 : :
1523 : : #ifndef USE_SSL
1524 : :
1525 : : /*
1526 : : * sslrootcert=system is not supported. Since setting this changes the
1527 : : * default sslmode, check this _before_ we validate sslmode, to avoid
1528 : : * confusing the user with errors for an option they may not have set.
1529 : : */
1530 : : if (conn->sslrootcert
1531 : : && strcmp(conn->sslrootcert, "system") == 0)
1532 : : {
1533 : : conn->status = CONNECTION_BAD;
1534 : : libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in",
1535 : : "sslrootcert", conn->sslrootcert);
1536 : : return false;
1537 : : }
1538 : : #endif
1539 : :
1540 : : /*
1541 : : * validate sslmode option
1542 : : */
7568 bruce@momjian.us 1543 [ + - ]:CBC 12085 : if (conn->sslmode)
1544 : : {
1545 [ + + ]: 12085 : if (strcmp(conn->sslmode, "disable") != 0
1546 [ + + ]: 11986 : && strcmp(conn->sslmode, "allow") != 0
1547 [ + + ]: 11896 : && strcmp(conn->sslmode, "prefer") != 0
5469 magnus@hagander.net 1548 [ + + ]: 205 : && strcmp(conn->sslmode, "require") != 0
1549 [ + + ]: 56 : && strcmp(conn->sslmode, "verify-ca") != 0
1550 [ - + ]: 39 : && strcmp(conn->sslmode, "verify-full") != 0)
1551 : : {
7568 bruce@momjian.us 1552 :UBC 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1553 : 0 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1554 : : "sslmode", conn->sslmode);
7568 bruce@momjian.us 1555 : 0 : return false;
1556 : : }
1557 : :
1558 : : #ifndef USE_SSL
1559 : : switch (conn->sslmode[0])
1560 : : {
1561 : : case 'a': /* "allow" */
1562 : : case 'p': /* "prefer" */
1563 : :
1564 : : /*
1565 : : * warn user that an SSL connection will never be negotiated
1566 : : * since SSL was not compiled in?
1567 : : */
1568 : : break;
1569 : :
1570 : : case 'r': /* "require" */
1571 : : case 'v': /* "verify-ca" or "verify-full" */
1572 : : conn->status = CONNECTION_BAD;
1573 : : libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in",
1574 : : "sslmode", conn->sslmode);
1575 : : return false;
1576 : : }
1577 : : #endif
1578 : : }
1579 : : else
1580 : : {
0 heikki.linnakangas@i 1581 : 0 : conn->sslmode = strdup(DefaultSSLMode);
1582 [ # # ]: 0 : if (!conn->sslmode)
1583 : 0 : goto oom_error;
1584 : : }
1585 : :
1586 : : /*
1587 : : * validate sslnegotiation option, default is "postgres" for the postgres
1588 : : * style negotiated connection with an extra round trip but more options.
1589 : : */
6 heikki.linnakangas@i 1590 [ + - ]:GNC 12085 : if (conn->sslnegotiation)
1591 : : {
1592 [ + + ]: 12085 : if (strcmp(conn->sslnegotiation, "postgres") != 0
1593 [ + + ]: 240 : && strcmp(conn->sslnegotiation, "direct") != 0
1594 [ - + ]: 120 : && strcmp(conn->sslnegotiation, "requiredirect") != 0)
1595 : : {
6 heikki.linnakangas@i 1596 :UNC 0 : conn->status = CONNECTION_BAD;
1597 : 0 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1598 : : "sslnegotiation", conn->sslnegotiation);
1599 : 0 : return false;
1600 : : }
1601 : :
1602 : : #ifndef USE_SSL
1603 : : if (conn->sslnegotiation[0] != 'p')
1604 : : {
1605 : : conn->status = CONNECTION_BAD;
1606 : : libpq_append_conn_error(conn, "sslnegotiation value \"%s\" invalid when SSL support is not compiled in",
1607 : : conn->sslnegotiation);
1608 : : return false;
1609 : : }
1610 : : #endif
1611 : : }
1612 : : else
1613 : : {
1614 : 0 : conn->sslnegotiation = strdup(DefaultSSLNegotiation);
1615 [ # # ]: 0 : if (!conn->sslnegotiation)
1616 : 0 : goto oom_error;
1617 : : }
1618 : :
1619 : : #ifdef USE_SSL
1620 : :
1621 : : /*
1622 : : * If sslrootcert=system, make sure our chosen sslmode is compatible.
1623 : : */
375 dgustafsson@postgres 1624 [ + + ]:CBC 12085 : if (conn->sslrootcert
1625 [ + + ]: 121 : && strcmp(conn->sslrootcert, "system") == 0
1626 [ + + ]: 4 : && strcmp(conn->sslmode, "verify-full") != 0)
1627 : : {
1628 : 1 : conn->status = CONNECTION_BAD;
331 peter@eisentraut.org 1629 : 1 : libpq_append_conn_error(conn, "weak sslmode \"%s\" may not be used with sslrootcert=system (use \"verify-full\")",
1630 : : conn->sslmode);
375 dgustafsson@postgres 1631 : 1 : return false;
1632 : : }
1633 : : #endif
1634 : :
1635 : : /*
1636 : : * Validate TLS protocol versions for ssl_min_protocol_version and
1637 : : * ssl_max_protocol_version.
1638 : : */
1445 michael@paquier.xyz 1639 [ + + ]: 12084 : if (!sslVerifyProtocolVersion(conn->ssl_min_protocol_version))
1640 : : {
1533 tgl@sss.pgh.pa.us 1641 : 1 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1642 : 1 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1643 : : "ssl_min_protocol_version",
1644 : : conn->ssl_min_protocol_version);
1538 michael@paquier.xyz 1645 : 1 : return false;
1646 : : }
1445 1647 [ + + ]: 12083 : if (!sslVerifyProtocolVersion(conn->ssl_max_protocol_version))
1648 : : {
1533 tgl@sss.pgh.pa.us 1649 : 1 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1650 : 1 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1651 : : "ssl_max_protocol_version",
1652 : : conn->ssl_max_protocol_version);
1538 michael@paquier.xyz 1653 : 1 : return false;
1654 : : }
1655 : :
1656 : : /*
1657 : : * Check if the range of SSL protocols defined is correct. This is done
1658 : : * at this early step because this is independent of the SSL
1659 : : * implementation used, and this avoids unnecessary cycles with an
1660 : : * already-built SSL context when the connection is being established, as
1661 : : * it would be doomed anyway.
1662 : : */
1445 1663 [ + + ]: 12082 : if (!sslVerifyProtocolRange(conn->ssl_min_protocol_version,
1664 : 12082 : conn->ssl_max_protocol_version))
1665 : : {
1533 tgl@sss.pgh.pa.us 1666 : 1 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1667 : 1 : libpq_append_conn_error(conn, "invalid SSL protocol version range");
1538 michael@paquier.xyz 1668 : 1 : return false;
1669 : : }
1670 : :
1671 : : /*
1672 : : * validate sslcertmode option
1673 : : */
387 1674 [ + + ]: 12081 : if (conn->sslcertmode)
1675 : : {
1676 [ + + ]: 167 : if (strcmp(conn->sslcertmode, "disable") != 0 &&
1677 [ + + ]: 164 : strcmp(conn->sslcertmode, "allow") != 0 &&
1678 [ - + ]: 3 : strcmp(conn->sslcertmode, "require") != 0)
1679 : : {
387 michael@paquier.xyz 1680 :UBC 0 : conn->status = CONNECTION_BAD;
1681 : 0 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1682 : : "sslcertmode", conn->sslcertmode);
1683 : 0 : return false;
1684 : : }
1685 : : #ifndef USE_SSL
1686 : : if (strcmp(conn->sslcertmode, "require") == 0)
1687 : : {
1688 : : conn->status = CONNECTION_BAD;
1689 : : libpq_append_conn_error(conn, "%s value \"%s\" invalid when SSL support is not compiled in",
1690 : : "sslcertmode", conn->sslcertmode);
1691 : : return false;
1692 : : }
1693 : : #endif
1694 : : #ifndef HAVE_SSL_CTX_SET_CERT_CB
1695 : :
1696 : : /*
1697 : : * Without a certificate callback, the current implementation can't
1698 : : * figure out if a certificate was actually requested, so "require" is
1699 : : * useless.
1700 : : */
1701 : : if (strcmp(conn->sslcertmode, "require") == 0)
1702 : : {
1703 : : conn->status = CONNECTION_BAD;
1704 : : libpq_append_conn_error(conn, "%s value \"%s\" is not supported (check OpenSSL version)",
1705 : : "sslcertmode", conn->sslcertmode);
1706 : : return false;
1707 : : }
1708 : : #endif
1709 : : }
1710 : : else
1711 : : {
387 michael@paquier.xyz 1712 :CBC 11914 : conn->sslcertmode = strdup(DefaultSSLCertMode);
1713 [ - + ]: 11914 : if (!conn->sslcertmode)
387 michael@paquier.xyz 1714 :UBC 0 : goto oom_error;
1715 : : }
1716 : :
1717 : : /*
1718 : : * validate gssencmode option
1719 : : */
1838 sfrost@snowman.net 1720 [ + - ]:CBC 12081 : if (conn->gssencmode)
1721 : : {
1722 [ + + ]: 12081 : if (strcmp(conn->gssencmode, "disable") != 0 &&
1723 [ + + ]: 11932 : strcmp(conn->gssencmode, "prefer") != 0 &&
1724 [ - + ]: 130 : strcmp(conn->gssencmode, "require") != 0)
1725 : : {
1838 sfrost@snowman.net 1726 :UBC 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1727 : 0 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"", "gssencmode", conn->gssencmode);
1838 sfrost@snowman.net 1728 : 0 : return false;
1729 : : }
1730 : : #ifndef ENABLE_GSS
1731 : : if (strcmp(conn->gssencmode, "require") == 0)
1732 : : {
1733 : : conn->status = CONNECTION_BAD;
1734 : : libpq_append_conn_error(conn, "gssencmode value \"%s\" invalid when GSSAPI support is not compiled in",
1735 : : conn->gssencmode);
1736 : : return false;
1737 : : }
1738 : : #endif
1739 : : }
1740 : : else
1741 : : {
1742 : 0 : conn->gssencmode = strdup(DefaultGSSMode);
1743 [ # # ]: 0 : if (!conn->gssencmode)
1744 : 0 : goto oom_error;
1745 : : }
1746 : :
1747 : : /*
1748 : : * validate target_session_attrs option, and set target_server_type
1749 : : */
2693 rhaas@postgresql.org 1750 [ + - ]:CBC 12081 : if (conn->target_session_attrs)
1751 : : {
1139 tgl@sss.pgh.pa.us 1752 [ + + ]: 12081 : if (strcmp(conn->target_session_attrs, "any") == 0)
1753 : 12066 : conn->target_server_type = SERVER_TYPE_ANY;
1754 [ + + ]: 15 : else if (strcmp(conn->target_session_attrs, "read-write") == 0)
1755 : 3 : conn->target_server_type = SERVER_TYPE_READ_WRITE;
1756 [ + + ]: 12 : else if (strcmp(conn->target_session_attrs, "read-only") == 0)
1757 : 3 : conn->target_server_type = SERVER_TYPE_READ_ONLY;
1758 [ + + ]: 9 : else if (strcmp(conn->target_session_attrs, "primary") == 0)
1759 : 3 : conn->target_server_type = SERVER_TYPE_PRIMARY;
1760 [ + + ]: 6 : else if (strcmp(conn->target_session_attrs, "standby") == 0)
1761 : 3 : conn->target_server_type = SERVER_TYPE_STANDBY;
1762 [ + - ]: 3 : else if (strcmp(conn->target_session_attrs, "prefer-standby") == 0)
1763 : 3 : conn->target_server_type = SERVER_TYPE_PREFER_STANDBY;
1764 : : else
1765 : : {
2693 rhaas@postgresql.org 1766 :UBC 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1767 : 0 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1768 : : "target_session_attrs",
1769 : : conn->target_session_attrs);
2693 rhaas@postgresql.org 1770 : 0 : return false;
1771 : : }
1772 : : }
1773 : : else
1139 tgl@sss.pgh.pa.us 1774 : 0 : conn->target_server_type = SERVER_TYPE_ANY;
1775 : :
1776 : : /*
1777 : : * validate load_balance_hosts option, and set load_balance_type
1778 : : */
382 dgustafsson@postgres 1779 [ + - ]:CBC 12081 : if (conn->load_balance_hosts)
1780 : : {
1781 [ + + ]: 12081 : if (strcmp(conn->load_balance_hosts, "disable") == 0)
1782 : 11970 : conn->load_balance_type = LOAD_BALANCE_DISABLE;
1783 [ + + ]: 111 : else if (strcmp(conn->load_balance_hosts, "random") == 0)
1784 : 110 : conn->load_balance_type = LOAD_BALANCE_RANDOM;
1785 : : else
1786 : : {
1787 : 1 : conn->status = CONNECTION_BAD;
1788 : 1 : libpq_append_conn_error(conn, "invalid %s value: \"%s\"",
1789 : : "load_balance_hosts",
1790 : : conn->load_balance_hosts);
1791 : 1 : return false;
1792 : : }
1793 : : }
1794 : : else
382 dgustafsson@postgres 1795 :UBC 0 : conn->load_balance_type = LOAD_BALANCE_DISABLE;
1796 : :
382 dgustafsson@postgres 1797 [ + + ]:CBC 12080 : if (conn->load_balance_type == LOAD_BALANCE_RANDOM)
1798 : : {
1799 : 110 : libpq_prng_init(conn);
1800 : :
1801 : : /*
1802 : : * This is the "inside-out" variant of the Fisher-Yates shuffle
1803 : : * algorithm. Notionally, we append each new value to the array and
1804 : : * then swap it with a randomly-chosen array element (possibly
1805 : : * including itself, else we fail to generate permutations with the
1806 : : * last integer last). The swap step can be optimized by combining it
1807 : : * with the insertion.
1808 : : */
1809 [ + + ]: 220 : for (i = 1; i < conn->nconnhost; i++)
1810 : : {
1811 : 110 : int j = pg_prng_uint64_range(&conn->prng_state, 0, i);
1812 : 110 : pg_conn_host temp = conn->connhost[j];
1813 : :
1814 : 110 : conn->connhost[j] = conn->connhost[i];
1815 : 110 : conn->connhost[i] = temp;
1816 : : }
1817 : : }
1818 : :
1819 : : /*
1820 : : * Resolve special "auto" client_encoding from the locale
1821 : : */
1139 tgl@sss.pgh.pa.us 1822 [ + + ]: 12080 : if (conn->client_encoding_initial &&
1823 [ + + ]: 772 : strcmp(conn->client_encoding_initial, "auto") == 0)
1824 : : {
1825 : 2 : free(conn->client_encoding_initial);
1826 : 2 : conn->client_encoding_initial = strdup(pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true)));
1827 [ - + ]: 2 : if (!conn->client_encoding_initial)
1139 tgl@sss.pgh.pa.us 1828 :UBC 0 : goto oom_error;
1829 : : }
1830 : :
1831 : : /*
1832 : : * Only if we get this far is it appropriate to try to connect. (We need a
1833 : : * state flag, rather than just the boolean result of this function, in
1834 : : * case someone tries to PQreset() the PGconn.)
1835 : : */
6635 tgl@sss.pgh.pa.us 1836 :CBC 12080 : conn->options_valid = true;
1837 : :
7657 1838 : 12080 : return true;
1839 : :
3428 heikki.linnakangas@i 1840 :UBC 0 : oom_error:
1841 : 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 1842 : 0 : libpq_append_conn_error(conn, "out of memory");
3428 heikki.linnakangas@i 1843 : 0 : return false;
1844 : : }
1845 : :
1846 : : /*
1847 : : * PQconndefaults
1848 : : *
1849 : : * Construct a default connection options array, which identifies all the
1850 : : * available options and shows any default values that are available from the
1851 : : * environment etc. On error (eg out of memory), NULL is returned.
1852 : : *
1853 : : * Using this function, an application may determine all possible options
1854 : : * and their current default values.
1855 : : *
1856 : : * NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated
1857 : : * and should be freed when no longer needed via PQconninfoFree(). (In prior
1858 : : * versions, the returned array was static, but that's not thread-safe.)
1859 : : * Pre-7.0 applications that use this function will see a small memory leak
1860 : : * until they are updated to call PQconninfoFree.
1861 : : */
1862 : : PQconninfoOption *
10017 bruce@momjian.us 1863 :CBC 89 : PQconndefaults(void)
1864 : : {
1865 : : PQExpBufferData errorBuf;
1866 : : PQconninfoOption *connOptions;
1867 : :
1868 : : /* We don't actually report any errors here, but callees want a buffer */
8993 tgl@sss.pgh.pa.us 1869 : 89 : initPQExpBuffer(&errorBuf);
4562 1870 [ - + ]: 89 : if (PQExpBufferDataBroken(errorBuf))
5683 tgl@sss.pgh.pa.us 1871 :UBC 0 : return NULL; /* out of memory already :-( */
1872 : :
4406 tgl@sss.pgh.pa.us 1873 :CBC 89 : connOptions = conninfo_init(&errorBuf);
1874 [ + - ]: 89 : if (connOptions != NULL)
1875 : : {
1876 : : /* pass NULL errorBuf to ignore errors */
3785 bruce@momjian.us 1877 [ - + ]: 89 : if (!conninfo_add_defaults(connOptions, NULL))
1878 : : {
4406 tgl@sss.pgh.pa.us 1879 :UBC 0 : PQconninfoFree(connOptions);
1880 : 0 : connOptions = NULL;
1881 : : }
1882 : : }
1883 : :
8993 tgl@sss.pgh.pa.us 1884 :CBC 89 : termPQExpBuffer(&errorBuf);
8800 1885 : 89 : return connOptions;
1886 : : }
1887 : :
1888 : : /* ----------------
1889 : : * PQsetdbLogin
1890 : : *
1891 : : * establishes a connection to a postgres backend through the postmaster
1892 : : * at the specified host and port.
1893 : : *
1894 : : * returns a PGconn* which is needed for all subsequent libpq calls
1895 : : *
1896 : : * if the status field of the connection returned is CONNECTION_BAD,
1897 : : * then only the errorMessage is likely to be useful.
1898 : : * ----------------
1899 : : */
1900 : : PGconn *
8857 tgl@sss.pgh.pa.us 1901 :UBC 0 : PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
1902 : : const char *pgtty, const char *dbName, const char *login,
1903 : : const char *pwd)
1904 : : {
1905 : : PGconn *conn;
1906 : :
1907 : : /*
1908 : : * Allocate memory for the conn structure. Note that we also expect this
1909 : : * to initialize conn->errorMessage to empty. All subsequent steps during
1910 : : * connection initialization will only append to that buffer.
1911 : : */
70 alvherre@alvh.no-ip. 1912 :UNC 0 : conn = pqMakeEmptyPGconn();
9716 bruce@momjian.us 1913 [ # # ]:UBC 0 : if (conn == NULL)
7403 neilc@samurai.com 1914 : 0 : return NULL;
1915 : :
1916 : : /*
1917 : : * If the dbName parameter contains what looks like a connection string,
1918 : : * parse it into conn struct using connectOptions1.
1919 : : */
3300 rhaas@postgresql.org 1920 [ # # # # ]: 0 : if (dbName && recognized_connection_string(dbName))
1921 : : {
5995 bruce@momjian.us 1922 [ # # ]: 0 : if (!connectOptions1(conn, dbName))
1923 : 0 : return conn;
1924 : : }
1925 : : else
1926 : : {
1927 : : /*
1928 : : * Old-style path: first, parse an empty conninfo string in order to
1929 : : * set up the same defaults that PQconnectdb() would use.
1930 : : */
1931 [ # # ]: 0 : if (!connectOptions1(conn, ""))
1932 : 0 : return conn;
1933 : :
1934 : : /* Insert dbName parameter value into struct */
1935 [ # # # # ]: 0 : if (dbName && dbName[0] != '\0')
1936 : : {
668 peter@eisentraut.org 1937 : 0 : free(conn->dbName);
5995 bruce@momjian.us 1938 : 0 : conn->dbName = strdup(dbName);
3428 heikki.linnakangas@i 1939 [ # # ]: 0 : if (!conn->dbName)
1940 : 0 : goto oom_error;
1941 : : }
1942 : : }
1943 : :
1944 : : /*
1945 : : * Insert remaining parameters into struct, overriding defaults (as well
1946 : : * as any conflicting data from dbName taken as a conninfo).
1947 : : */
7657 tgl@sss.pgh.pa.us 1948 [ # # # # ]: 0 : if (pghost && pghost[0] != '\0')
1949 : : {
668 peter@eisentraut.org 1950 : 0 : free(conn->pghost);
7657 tgl@sss.pgh.pa.us 1951 : 0 : conn->pghost = strdup(pghost);
3428 heikki.linnakangas@i 1952 [ # # ]: 0 : if (!conn->pghost)
1953 : 0 : goto oom_error;
1954 : : }
1955 : :
7657 tgl@sss.pgh.pa.us 1956 [ # # # # ]: 0 : if (pgport && pgport[0] != '\0')
1957 : : {
668 peter@eisentraut.org 1958 : 0 : free(conn->pgport);
7657 tgl@sss.pgh.pa.us 1959 : 0 : conn->pgport = strdup(pgport);
3428 heikki.linnakangas@i 1960 [ # # ]: 0 : if (!conn->pgport)
1961 : 0 : goto oom_error;
1962 : : }
1963 : :
7657 tgl@sss.pgh.pa.us 1964 [ # # # # ]: 0 : if (pgoptions && pgoptions[0] != '\0')
1965 : : {
668 peter@eisentraut.org 1966 : 0 : free(conn->pgoptions);
9475 bruce@momjian.us 1967 : 0 : conn->pgoptions = strdup(pgoptions);
3428 heikki.linnakangas@i 1968 [ # # ]: 0 : if (!conn->pgoptions)
1969 : 0 : goto oom_error;
1970 : : }
1971 : :
7657 tgl@sss.pgh.pa.us 1972 [ # # # # ]: 0 : if (login && login[0] != '\0')
1973 : : {
668 peter@eisentraut.org 1974 : 0 : free(conn->pguser);
7657 tgl@sss.pgh.pa.us 1975 : 0 : conn->pguser = strdup(login);
3428 heikki.linnakangas@i 1976 [ # # ]: 0 : if (!conn->pguser)
1977 : 0 : goto oom_error;
1978 : : }
1979 : :
7657 tgl@sss.pgh.pa.us 1980 [ # # # # ]: 0 : if (pwd && pwd[0] != '\0')
1981 : : {
668 peter@eisentraut.org 1982 : 0 : free(conn->pgpass);
7913 bruce@momjian.us 1983 : 0 : conn->pgpass = strdup(pwd);
3428 heikki.linnakangas@i 1984 [ # # ]: 0 : if (!conn->pgpass)
1985 : 0 : goto oom_error;
1986 : : }
1987 : :
1988 : : /*
1989 : : * Compute derived options
1990 : : */
70 alvherre@alvh.no-ip. 1991 [ # # ]:UNC 0 : if (!pqConnectOptions2(conn))
7657 tgl@sss.pgh.pa.us 1992 :UBC 0 : return conn;
1993 : :
1994 : : /*
1995 : : * Connect to the database
1996 : : */
70 alvherre@alvh.no-ip. 1997 [ # # ]:UNC 0 : if (pqConnectDBStart(conn))
1998 : 0 : (void) pqConnectDBComplete(conn);
1999 : :
9716 bruce@momjian.us 2000 :UBC 0 : return conn;
2001 : :
3428 heikki.linnakangas@i 2002 : 0 : oom_error:
2003 : 0 : conn->status = CONNECTION_BAD;
516 peter@eisentraut.org 2004 : 0 : libpq_append_conn_error(conn, "out of memory");
3428 heikki.linnakangas@i 2005 : 0 : return conn;
2006 : : }
2007 : :
2008 : :
2009 : : /* ----------
2010 : : * connectNoDelay -
2011 : : * Sets the TCP_NODELAY socket option.
2012 : : * Returns 1 if successful, 0 if not.
2013 : : * ----------
2014 : : */
2015 : : static int
8902 bruce@momjian.us 2016 :CBC 662 : connectNoDelay(PGconn *conn)
2017 : : {
2018 : : #ifdef TCP_NODELAY
2019 : 662 : int on = 1;
2020 : :
8729 tgl@sss.pgh.pa.us 2021 [ - + ]: 662 : if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY,
2022 : : (char *) &on,
2023 : : sizeof(on)) < 0)
2024 : : {
2025 : : char sebuf[PG_STRERROR_R_BUFLEN];
2026 : :
516 peter@eisentraut.org 2027 :UBC 0 : libpq_append_conn_error(conn, "could not set socket to TCP no delay mode: %s",
402 michael@paquier.xyz 2028 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
8902 bruce@momjian.us 2029 : 0 : return 0;
2030 : : }
2031 : : #endif
2032 : :
8902 bruce@momjian.us 2033 :CBC 662 : return 1;
2034 : : }
2035 : :
2036 : : /* ----------
2037 : : * Write currently connected IP address into host_addr (of len host_addr_len).
2038 : : * If unable to, set it to the empty string.
2039 : : * ----------
2040 : : */
2041 : : static void
1973 alvherre@alvh.no-ip. 2042 : 12178 : getHostaddr(PGconn *conn, char *host_addr, int host_addr_len)
2043 : : {
2044 : 12178 : struct sockaddr_storage *addr = &conn->raddr.addr;
2045 : :
1766 2046 [ + + ]: 12178 : if (addr->ss_family == AF_INET)
2047 : : {
1701 tgl@sss.pgh.pa.us 2048 [ - + ]: 662 : if (pg_inet_net_ntop(AF_INET,
2049 : 662 : &((struct sockaddr_in *) addr)->sin_addr.s_addr,
2050 : : 32,
2051 : : host_addr, host_addr_len) == NULL)
1973 alvherre@alvh.no-ip. 2052 :UBC 0 : host_addr[0] = '\0';
2053 : : }
1973 alvherre@alvh.no-ip. 2054 [ - + ]:CBC 11516 : else if (addr->ss_family == AF_INET6)
2055 : : {
1701 tgl@sss.pgh.pa.us 2056 [ # # ]:UBC 0 : if (pg_inet_net_ntop(AF_INET6,
2057 : 0 : &((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr,
2058 : : 128,
2059 : : host_addr, host_addr_len) == NULL)
1973 alvherre@alvh.no-ip. 2060 : 0 : host_addr[0] = '\0';
2061 : : }
2062 : : else
1973 alvherre@alvh.no-ip. 2063 :CBC 11516 : host_addr[0] = '\0';
2064 : 12178 : }
2065 : :
2066 : : /*
2067 : : * emitHostIdentityInfo -
2068 : : * Speculatively append "connection to server so-and-so failed: " to
2069 : : * conn->errorMessage once we've identified the current connection target
2070 : : * address. This ensures that any subsequent error message will be properly
2071 : : * attributed to the server we couldn't connect to. conn->raddr must be
2072 : : * valid, and the result of getHostaddr() must be supplied.
2073 : : */
2074 : : static void
1179 tgl@sss.pgh.pa.us 2075 : 12178 : emitHostIdentityInfo(PGconn *conn, const char *host_addr)
2076 : : {
789 peter@eisentraut.org 2077 [ + + ]: 12178 : if (conn->raddr.addr.ss_family == AF_UNIX)
2078 : : {
2079 : : char service[NI_MAXHOST];
2080 : :
6754 tgl@sss.pgh.pa.us 2081 : 11516 : pg_getnameinfo_all(&conn->raddr.addr, conn->raddr.salen,
2082 : : NULL, 0,
2083 : : service, sizeof(service),
2084 : : NI_NUMERICSERV);
5648 magnus@hagander.net 2085 : 11516 : appendPQExpBuffer(&conn->errorMessage,
1179 tgl@sss.pgh.pa.us 2086 : 11516 : libpq_gettext("connection to server on socket \"%s\" failed: "),
2087 : : service);
2088 : : }
2089 : : else
2090 : : {
2091 : : const char *displayed_host;
2092 : : const char *displayed_port;
2093 : :
2094 : : /* To which host and port were we actually connecting? */
2470 heikki.linnakangas@i 2095 [ + + ]: 662 : if (conn->connhost[conn->whichhost].type == CHT_HOST_ADDRESS)
2096 : 599 : displayed_host = conn->connhost[conn->whichhost].hostaddr;
2097 : : else
2098 : 63 : displayed_host = conn->connhost[conn->whichhost].host;
2719 rhaas@postgresql.org 2099 : 662 : displayed_port = conn->connhost[conn->whichhost].port;
2100 [ + - - + ]: 662 : if (displayed_port == NULL || displayed_port[0] == '\0')
2719 rhaas@postgresql.org 2101 :UBC 0 : displayed_port = DEF_PGPORT_STR;
2102 : :
2103 : : /*
2104 : : * If the user did not supply an IP address using 'hostaddr', and
2105 : : * 'host' was missing or does not match our lookup, display the
2106 : : * looked-up IP address.
2107 : : */
2470 heikki.linnakangas@i 2108 [ + + ]:CBC 662 : if (conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS &&
1189 tgl@sss.pgh.pa.us 2109 [ + - ]: 63 : host_addr[0] &&
2470 heikki.linnakangas@i 2110 [ + - ]: 63 : strcmp(displayed_host, host_addr) != 0)
4714 peter_e@gmx.net 2111 : 63 : appendPQExpBuffer(&conn->errorMessage,
1179 tgl@sss.pgh.pa.us 2112 : 63 : libpq_gettext("connection to server at \"%s\" (%s), port %s failed: "),
2113 : : displayed_host, host_addr,
2114 : : displayed_port);
2115 : : else
4714 peter_e@gmx.net 2116 : 599 : appendPQExpBuffer(&conn->errorMessage,
1179 tgl@sss.pgh.pa.us 2117 : 599 : libpq_gettext("connection to server at \"%s\", port %s failed: "),
2118 : : displayed_host,
2119 : : displayed_port);
2120 : : }
8536 2121 : 12178 : }
2122 : :
2123 : : /* ----------
2124 : : * connectFailureMessage -
2125 : : * create a friendly error message on connection failure,
2126 : : * using the given errno value. Use this for error cases that
2127 : : * imply that there's no server there.
2128 : : * ----------
2129 : : */
2130 : : static void
1189 2131 : 339 : connectFailureMessage(PGconn *conn, int errorno)
2132 : : {
2133 : : char sebuf[PG_STRERROR_R_BUFLEN];
2134 : :
2135 : 339 : appendPQExpBuffer(&conn->errorMessage,
2136 : : "%s\n",
2137 : : SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)));
2138 : :
789 peter@eisentraut.org 2139 [ + + ]: 339 : if (conn->raddr.addr.ss_family == AF_UNIX)
516 2140 : 333 : libpq_append_conn_error(conn, "\tIs the server running locally and accepting connections on that socket?");
2141 : : else
2142 : 6 : libpq_append_conn_error(conn, "\tIs the server running on that host and accepting TCP/IP connections?");
1189 tgl@sss.pgh.pa.us 2143 : 339 : }
2144 : :
2145 : : /*
2146 : : * Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if
2147 : : * conn->keepalives is set to a value which is not parseable as an
2148 : : * integer.
2149 : : */
2150 : : static int
5044 rhaas@postgresql.org 2151 : 662 : useKeepalives(PGconn *conn)
2152 : : {
2153 : : char *ep;
2154 : : int val;
2155 : :
2156 [ + - ]: 662 : if (conn->keepalives == NULL)
2157 : 662 : return 1;
5044 rhaas@postgresql.org 2158 :UBC 0 : val = strtol(conn->keepalives, &ep, 10);
2159 [ # # ]: 0 : if (*ep)
2160 : 0 : return -1;
2161 : 0 : return val != 0 ? 1 : 0;
2162 : : }
2163 : :
2164 : : #ifndef WIN32
2165 : : /*
2166 : : * Set the keepalive idle timer.
2167 : : */
2168 : : static int
5044 rhaas@postgresql.org 2169 :CBC 662 : setKeepalivesIdle(PGconn *conn)
2170 : : {
2171 : : int idle;
2172 : :
2173 [ + - ]: 662 : if (conn->keepalives_idle == NULL)
2174 : 662 : return 1;
2175 : :
76 alvherre@alvh.no-ip. 2176 [ # # ]:UNC 0 : if (!pqParseIntParam(conn->keepalives_idle, &idle, conn,
2177 : : "keepalives_idle"))
2041 michael@paquier.xyz 2178 :UBC 0 : return 0;
5044 rhaas@postgresql.org 2179 [ # # ]: 0 : if (idle < 0)
2180 : 0 : idle = 0;
2181 : :
2182 : : #ifdef PG_TCP_KEEPALIVE_IDLE
2482 tgl@sss.pgh.pa.us 2183 [ # # ]: 0 : if (setsockopt(conn->sock, IPPROTO_TCP, PG_TCP_KEEPALIVE_IDLE,
2184 : : (char *) &idle, sizeof(idle)) < 0)
2185 : : {
2186 : : char sebuf[PG_STRERROR_R_BUFLEN];
2187 : :
516 peter@eisentraut.org 2188 : 0 : libpq_append_conn_error(conn, "%s(%s) failed: %s",
2189 : : "setsockopt",
2190 : : PG_TCP_KEEPALIVE_IDLE_STR,
402 michael@paquier.xyz 2191 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
5031 rhaas@postgresql.org 2192 : 0 : return 0;
2193 : : }
2194 : : #endif
2195 : :
5044 2196 : 0 : return 1;
2197 : : }
2198 : :
2199 : : /*
2200 : : * Set the keepalive interval.
2201 : : */
2202 : : static int
5044 rhaas@postgresql.org 2203 :CBC 662 : setKeepalivesInterval(PGconn *conn)
2204 : : {
2205 : : int interval;
2206 : :
2207 [ + - ]: 662 : if (conn->keepalives_interval == NULL)
2208 : 662 : return 1;
2209 : :
76 alvherre@alvh.no-ip. 2210 [ # # ]:UNC 0 : if (!pqParseIntParam(conn->keepalives_interval, &interval, conn,
2211 : : "keepalives_interval"))
2041 michael@paquier.xyz 2212 :UBC 0 : return 0;
5044 rhaas@postgresql.org 2213 [ # # ]: 0 : if (interval < 0)
2214 : 0 : interval = 0;
2215 : :
2216 : : #ifdef TCP_KEEPINTVL
2217 [ # # ]: 0 : if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL,
2218 : : (char *) &interval, sizeof(interval)) < 0)
2219 : : {
2220 : : char sebuf[PG_STRERROR_R_BUFLEN];
2221 : :
516 peter@eisentraut.org 2222 : 0 : libpq_append_conn_error(conn, "%s(%s) failed: %s",
2223 : : "setsockopt",
2224 : : "TCP_KEEPINTVL",
402 michael@paquier.xyz 2225 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
5044 rhaas@postgresql.org 2226 : 0 : return 0;
2227 : : }
2228 : : #endif
2229 : :
2230 : 0 : return 1;
2231 : : }
2232 : :
2233 : : /*
2234 : : * Set the count of lost keepalive packets that will trigger a connection
2235 : : * break.
2236 : : */
2237 : : static int
5044 rhaas@postgresql.org 2238 :CBC 662 : setKeepalivesCount(PGconn *conn)
2239 : : {
2240 : : int count;
2241 : :
2242 [ + - ]: 662 : if (conn->keepalives_count == NULL)
2243 : 662 : return 1;
2244 : :
76 alvherre@alvh.no-ip. 2245 [ # # ]:UNC 0 : if (!pqParseIntParam(conn->keepalives_count, &count, conn,
2246 : : "keepalives_count"))
2041 michael@paquier.xyz 2247 :UBC 0 : return 0;
5044 rhaas@postgresql.org 2248 [ # # ]: 0 : if (count < 0)
2249 : 0 : count = 0;
2250 : :
2251 : : #ifdef TCP_KEEPCNT
2252 [ # # ]: 0 : if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT,
2253 : : (char *) &count, sizeof(count)) < 0)
2254 : : {
2255 : : char sebuf[PG_STRERROR_R_BUFLEN];
2256 : :
516 peter@eisentraut.org 2257 : 0 : libpq_append_conn_error(conn, "%s(%s) failed: %s",
2258 : : "setsockopt",
2259 : : "TCP_KEEPCNT",
402 michael@paquier.xyz 2260 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
5044 rhaas@postgresql.org 2261 : 0 : return 0;
2262 : : }
2263 : : #endif
2264 : :
2265 : 0 : return 1;
2266 : : }
2267 : : #else /* WIN32 */
2268 : : #ifdef SIO_KEEPALIVE_VALS
2269 : : /*
2270 : : * Enable keepalives and set the keepalive values on Win32,
2271 : : * where they are always set in one batch.
2272 : : *
2273 : : * CAUTION: This needs to be signal safe, since it's used by PQcancel.
2274 : : */
2275 : : int
2276 : : pqSetKeepalivesWin32(pgsocket sock, int idle, int interval)
2277 : : {
2278 : : struct tcp_keepalive ka;
2279 : : DWORD retsize;
2280 : :
2281 : : if (idle <= 0)
2282 : : idle = 2 * 60 * 60; /* 2 hours = default */
2283 : : if (interval <= 0)
2284 : : interval = 1; /* 1 second = default */
2285 : :
2286 : : ka.onoff = 1;
2287 : : ka.keepalivetime = idle * 1000;
2288 : : ka.keepaliveinterval = interval * 1000;
2289 : :
2290 : : if (WSAIoctl(sock,
2291 : : SIO_KEEPALIVE_VALS,
2292 : : (LPVOID) &ka,
2293 : : sizeof(ka),
2294 : : NULL,
2295 : : 0,
2296 : : &retsize,
2297 : : NULL,
2298 : : NULL)
2299 : : != 0)
2300 : : return 0;
2301 : : return 1;
2302 : : }
2303 : :
2304 : : static int
2305 : : prepKeepalivesWin32(PGconn *conn)
2306 : : {
2307 : : int idle = -1;
2308 : : int interval = -1;
2309 : :
2310 : : if (conn->keepalives_idle &&
2311 : : !pqParseIntParam(conn->keepalives_idle, &idle, conn,
2312 : : "keepalives_idle"))
2313 : : return 0;
2314 : : if (conn->keepalives_interval &&
2315 : : !pqParseIntParam(conn->keepalives_interval, &interval, conn,
2316 : : "keepalives_interval"))
2317 : : return 0;
2318 : :
2319 : : if (!pqSetKeepalivesWin32(conn->sock, idle, interval))
2320 : : {
2321 : : libpq_append_conn_error(conn, "%s(%s) failed: error code %d",
2322 : : "WSAIoctl", "SIO_KEEPALIVE_VALS",
2323 : : WSAGetLastError());
2324 : : return 0;
2325 : : }
2326 : : return 1;
2327 : : }
2328 : : #endif /* SIO_KEEPALIVE_VALS */
2329 : : #endif /* WIN32 */
2330 : :
2331 : : /*
2332 : : * Set the TCP user timeout.
2333 : : */
2334 : : static int
1835 michael@paquier.xyz 2335 :CBC 662 : setTCPUserTimeout(PGconn *conn)
2336 : : {
2337 : : int timeout;
2338 : :
2339 [ + - ]: 662 : if (conn->pgtcp_user_timeout == NULL)
2340 : 662 : return 1;
2341 : :
76 alvherre@alvh.no-ip. 2342 [ # # ]:UNC 0 : if (!pqParseIntParam(conn->pgtcp_user_timeout, &timeout, conn,
2343 : : "tcp_user_timeout"))
1835 michael@paquier.xyz 2344 :UBC 0 : return 0;
2345 : :
2346 [ # # ]: 0 : if (timeout < 0)
2347 : 0 : timeout = 0;
2348 : :
2349 : : #ifdef TCP_USER_TIMEOUT
2350 [ # # ]: 0 : if (setsockopt(conn->sock, IPPROTO_TCP, TCP_USER_TIMEOUT,
2351 : : (char *) &timeout, sizeof(timeout)) < 0)
2352 : : {
2353 : : char sebuf[256];
2354 : :
516 peter@eisentraut.org 2355 : 0 : libpq_append_conn_error(conn, "%s(%s) failed: %s",
2356 : : "setsockopt",
2357 : : "TCP_USER_TIMEOUT",
402 michael@paquier.xyz 2358 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1835 2359 : 0 : return 0;
2360 : : }
2361 : : #endif
2362 : :
2363 : 0 : return 1;
2364 : : }
2365 : :
2366 : : /* ----------
2367 : : * pqConnectDBStart -
2368 : : * Begin the process of making a connection to the backend.
2369 : : *
2370 : : * Returns 1 if successful, 0 if not.
2371 : : * ----------
2372 : : */
2373 : : int
70 alvherre@alvh.no-ip. 2374 :GNC 12081 : pqConnectDBStart(PGconn *conn)
2375 : : {
8902 bruce@momjian.us 2376 [ - + ]:CBC 12081 : if (!conn)
8902 bruce@momjian.us 2377 :UBC 0 : return 0;
2378 : :
6635 tgl@sss.pgh.pa.us 2379 [ - + ]:CBC 12081 : if (!conn->options_valid)
6635 tgl@sss.pgh.pa.us 2380 :UBC 0 : goto connect_errReturn;
2381 : :
2382 : : /*
2383 : : * Check for bad linking to backend-internal versions of src/common
2384 : : * functions (see comments in link-canary.c for the reason we need this).
2385 : : * Nobody but developers should see this message, so we don't bother
2386 : : * translating it.
2387 : : */
2044 tgl@sss.pgh.pa.us 2388 [ - + ]:CBC 12081 : if (!pg_link_canary_is_frontend())
2389 : : {
1189 tgl@sss.pgh.pa.us 2390 :UBC 0 : appendPQExpBufferStr(&conn->errorMessage,
2391 : : "libpq is incorrectly linked to backend functions\n");
2044 2392 : 0 : goto connect_errReturn;
2393 : : }
2394 : :
2395 : : /* Ensure our buffers are empty */
8902 bruce@momjian.us 2396 :CBC 12081 : conn->inStart = conn->inCursor = conn->inEnd = 0;
2397 : 12081 : conn->outCount = 0;
2398 : :
2399 : : /*
2400 : : * Set up to try to connect to the first host. (Setting whichhost = -1 is
2401 : : * a bit of a cheat, but PQconnectPoll will advance it to 0 before
2402 : : * anything else looks at it.)
2403 : : *
2404 : : * Cancel requests are special though, they should only try one host and
2405 : : * address, and these fields have already been set up in PQcancelCreate,
2406 : : * so leave these fields alone for cancel requests.
2407 : : */
33 alvherre@alvh.no-ip. 2408 [ + + ]:GNC 12081 : if (!conn->cancelRequest)
2409 : : {
2410 : 12075 : conn->whichhost = -1;
2411 : 12075 : conn->try_next_host = true;
2412 : 12075 : conn->try_next_addr = false;
2413 : : }
2414 : :
7616 tgl@sss.pgh.pa.us 2415 :CBC 12081 : conn->status = CONNECTION_NEEDED;
2416 : :
2417 : : /* Also reset the target_server_type state if needed */
1139 2418 [ - + ]: 12081 : if (conn->target_server_type == SERVER_TYPE_PREFER_STANDBY_PASS2)
1139 tgl@sss.pgh.pa.us 2419 :UBC 0 : conn->target_server_type = SERVER_TYPE_PREFER_STANDBY;
2420 : :
2421 : : /*
2422 : : * The code for processing CONNECTION_NEEDED state is in PQconnectPoll(),
2423 : : * so that it can easily be re-executed if needed again during the
2424 : : * asynchronous startup process. However, we must run it once here,
2425 : : * because callers expect a success return from this routine to mean that
2426 : : * we are in PGRES_POLLING_WRITING connection state.
2427 : : */
7616 tgl@sss.pgh.pa.us 2428 [ + + ]:CBC 12081 : if (PQconnectPoll(conn) == PGRES_POLLING_WRITING)
2429 : 11740 : return 1;
2430 : :
8902 bruce@momjian.us 2431 : 341 : connect_errReturn:
2432 : :
2433 : : /*
2434 : : * If we managed to open a socket, close it immediately rather than
2435 : : * waiting till PQfinish. (The application cannot have gotten the socket
2436 : : * from PQsocket yet, so this doesn't risk breaking anything.)
2437 : : */
3076 tgl@sss.pgh.pa.us 2438 : 341 : pqDropConnection(conn, true);
8902 bruce@momjian.us 2439 : 341 : conn->status = CONNECTION_BAD;
2440 : 341 : return 0;
2441 : : }
2442 : :
2443 : :
2444 : : /*
2445 : : * pqConnectDBComplete
2446 : : *
2447 : : * Block and complete a connection.
2448 : : *
2449 : : * Returns 1 on success, 0 on failure.
2450 : : */
2451 : : int
70 alvherre@alvh.no-ip. 2452 :GNC 10817 : pqConnectDBComplete(PGconn *conn)
2453 : : {
8855 tgl@sss.pgh.pa.us 2454 :CBC 10817 : PostgresPollingStatusType flag = PGRES_POLLING_WRITING;
7787 bruce@momjian.us 2455 : 10817 : time_t finish_time = ((time_t) -1);
2522 rhaas@postgresql.org 2456 : 10817 : int timeout = 0;
2071 tgl@sss.pgh.pa.us 2457 : 10817 : int last_whichhost = -2; /* certainly different from whichhost */
382 dgustafsson@postgres 2458 : 10817 : int last_whichaddr = -2; /* certainly different from whichaddr */
2459 : :
8855 tgl@sss.pgh.pa.us 2460 [ + - - + ]: 10817 : if (conn == NULL || conn->status == CONNECTION_BAD)
8855 tgl@sss.pgh.pa.us 2461 :UBC 0 : return 0;
2462 : :
2463 : : /*
2464 : : * Set up a time limit, if connect_timeout isn't zero.
2465 : : */
7893 bruce@momjian.us 2466 [ + + ]:CBC 10817 : if (conn->connect_timeout != NULL)
2467 : : {
76 alvherre@alvh.no-ip. 2468 [ - + ]:GNC 2 : if (!pqParseIntParam(conn->connect_timeout, &timeout, conn,
2469 : : "connect_timeout"))
2470 : : {
2471 : : /* mark the connection as bad to report the parsing failure */
1637 michael@paquier.xyz 2472 :UBC 0 : conn->status = CONNECTION_BAD;
2041 2473 : 0 : return 0;
2474 : : }
2475 : :
7843 tgl@sss.pgh.pa.us 2476 [ + - ]:CBC 2 : if (timeout > 0)
2477 : : {
2478 : : /*
2479 : : * Rounding could cause connection to fail unexpectedly quickly;
2480 : : * to prevent possibly waiting hardly-at-all, insist on at least
2481 : : * two seconds.
2482 : : */
2483 [ - + ]: 2 : if (timeout < 2)
7843 tgl@sss.pgh.pa.us 2484 :UBC 0 : timeout = 2;
2485 : : }
2486 : : else /* negative means 0 */
2041 michael@paquier.xyz 2487 : 0 : timeout = 0;
2488 : : }
2489 : :
2490 : : for (;;)
7901 bruce@momjian.us 2491 :CBC 24563 : {
2522 rhaas@postgresql.org 2492 : 35380 : int ret = 0;
2493 : :
2494 : : /*
2495 : : * (Re)start the connect_timeout timer if it's active and we are
2496 : : * considering a different host than we were last time through. If
2497 : : * we've already succeeded, though, needn't recalculate.
2498 : : */
2071 tgl@sss.pgh.pa.us 2499 [ + + ]: 35380 : if (flag != PGRES_POLLING_OK &&
2500 [ + + ]: 24883 : timeout > 0 &&
2501 [ + + ]: 4 : (conn->whichhost != last_whichhost ||
382 dgustafsson@postgres 2502 [ - + ]: 2 : conn->whichaddr != last_whichaddr))
2503 : : {
2071 tgl@sss.pgh.pa.us 2504 : 2 : finish_time = time(NULL) + timeout;
2505 : 2 : last_whichhost = conn->whichhost;
382 dgustafsson@postgres 2506 : 2 : last_whichaddr = conn->whichaddr;
2507 : : }
2508 : :
2509 : : /*
2510 : : * Wait, if necessary. Note that the initial state (just after
2511 : : * PQconnectStart) is to wait for the socket to select for writing.
2512 : : */
8857 tgl@sss.pgh.pa.us 2513 [ + + + + ]: 35380 : switch (flag)
2514 : : {
8902 bruce@momjian.us 2515 : 10497 : case PGRES_POLLING_OK:
8857 tgl@sss.pgh.pa.us 2516 : 10497 : return 1; /* success! */
2517 : :
8902 bruce@momjian.us 2518 : 12218 : case PGRES_POLLING_READING:
2522 rhaas@postgresql.org 2519 : 12218 : ret = pqWaitTimed(1, 0, conn, finish_time);
2520 [ - + ]: 12218 : if (ret == -1)
2521 : : {
2522 : : /* hard failure, eg select() problem, aborts everything */
8857 tgl@sss.pgh.pa.us 2523 :UBC 0 : conn->status = CONNECTION_BAD;
2524 : 0 : return 0;
2525 : : }
8902 bruce@momjian.us 2526 :CBC 12218 : break;
2527 : :
2528 : 12345 : case PGRES_POLLING_WRITING:
2522 rhaas@postgresql.org 2529 : 12345 : ret = pqWaitTimed(0, 1, conn, finish_time);
2530 [ - + ]: 12345 : if (ret == -1)
2531 : : {
2532 : : /* hard failure, eg select() problem, aborts everything */
8857 tgl@sss.pgh.pa.us 2533 :UBC 0 : conn->status = CONNECTION_BAD;
2534 : 0 : return 0;
2535 : : }
8902 bruce@momjian.us 2536 :CBC 12345 : break;
2537 : :
2538 : 320 : default:
2539 : : /* Just in case we failed to set it in PQconnectPoll */
2540 : 320 : conn->status = CONNECTION_BAD;
2541 : 320 : return 0;
2542 : : }
2543 : :
2497 tgl@sss.pgh.pa.us 2544 [ - + ]: 24563 : if (ret == 1) /* connect_timeout elapsed */
2545 : : {
2546 : : /*
2547 : : * Give up on current server/address, try the next one.
2548 : : */
2071 tgl@sss.pgh.pa.us 2549 :UBC 0 : conn->try_next_addr = true;
2078 2550 : 0 : conn->status = CONNECTION_NEEDED;
2551 : : }
2552 : :
2553 : : /*
2554 : : * Now try to advance the state machine.
2555 : : */
33 alvherre@alvh.no-ip. 2556 [ + + ]:GNC 24563 : if (conn->cancelRequest)
2557 : 2 : flag = PQcancelPoll((PGcancelConn *) conn);
2558 : : else
2559 : 24561 : flag = PQconnectPoll(conn);
2560 : : }
2561 : : }
2562 : :
2563 : : /* ----------------
2564 : : * PQconnectPoll
2565 : : *
2566 : : * Poll an asynchronous connection.
2567 : : *
2568 : : * Returns a PostgresPollingStatusType.
2569 : : * Before calling this function, use select(2) to determine when data
2570 : : * has arrived..
2571 : : *
2572 : : * You must call PQfinish whether or not this fails.
2573 : : *
2574 : : * This function and PQconnectStart are intended to allow connections to be
2575 : : * made without blocking the execution of your program on remote I/O. However,
2576 : : * there are a number of caveats:
2577 : : *
2578 : : * o If you call PQtrace, ensure that the stream object into which you trace
2579 : : * will not block.
2580 : : * o If you do not supply an IP address for the remote host (i.e. you
2581 : : * supply a host name instead) then PQconnectStart will block on
2582 : : * getaddrinfo. You will be fine if using Unix sockets (i.e. by
2583 : : * supplying neither a host name nor a host address).
2584 : : * o If your backend wants to use Kerberos authentication then you must
2585 : : * supply both a host name and a host address, otherwise this function
2586 : : * may block on gethostname.
2587 : : *
2588 : : * ----------------
2589 : : */
2590 : : PostgresPollingStatusType
8902 bruce@momjian.us 2591 :CBC 38531 : PQconnectPoll(PGconn *conn)
2592 : : {
2078 tgl@sss.pgh.pa.us 2593 : 38531 : bool reset_connection_state_machine = false;
2594 : 38531 : bool need_new_connection = false;
2595 : : PGresult *res;
2596 : : char sebuf[PG_STRERROR_R_BUFLEN];
2597 : : int optval;
2598 : :
8902 bruce@momjian.us 2599 [ - + ]: 38531 : if (conn == NULL)
8902 bruce@momjian.us 2600 :UBC 0 : return PGRES_POLLING_FAILED;
2601 : :
2602 : : /* Get the new data */
8902 bruce@momjian.us 2603 [ - - + + :CBC 38531 : switch (conn->status)
+ - ]
2604 : : {
2605 : : /*
2606 : : * We really shouldn't have been polled in these two cases, but we
2607 : : * can handle it.
2608 : : */
8902 bruce@momjian.us 2609 :UBC 0 : case CONNECTION_BAD:
2610 : 0 : return PGRES_POLLING_FAILED;
2611 : 0 : case CONNECTION_OK:
2612 : 0 : return PGRES_POLLING_OK;
2613 : :
2614 : : /* These are reading states */
8902 bruce@momjian.us 2615 :CBC 12078 : case CONNECTION_AWAITING_RESPONSE:
2616 : : case CONNECTION_AUTH_OK:
2617 : : case CONNECTION_CHECK_WRITABLE:
2618 : : case CONNECTION_CONSUME:
2619 : : case CONNECTION_CHECK_STANDBY:
2620 : : {
2621 : : /* Load waiting data */
8768 2622 : 12078 : int n = pqReadData(conn);
2623 : :
2624 [ + + ]: 12078 : if (n < 0)
2625 : 9 : goto error_return;
2626 [ + + ]: 12069 : if (n == 0)
2627 : 153 : return PGRES_POLLING_READING;
2628 : :
2629 : 11916 : break;
2630 : : }
2631 : :
2632 : : /* These are writing states, so we just proceed. */
8902 2633 : 12979 : case CONNECTION_STARTED:
2634 : : case CONNECTION_MADE:
8768 2635 : 12979 : break;
2636 : :
2637 : : /* Special cases: proceed without waiting. */
7616 tgl@sss.pgh.pa.us 2638 : 13474 : case CONNECTION_SSL_STARTUP:
2639 : : case CONNECTION_NEEDED:
2640 : : case CONNECTION_GSS_STARTUP:
2641 : : case CONNECTION_CHECK_TARGET:
2642 : 13474 : break;
2643 : :
8902 bruce@momjian.us 2644 :UBC 0 : default:
516 peter@eisentraut.org 2645 : 0 : libpq_append_conn_error(conn, "invalid connection state, probably indicative of memory corruption");
8902 bruce@momjian.us 2646 : 0 : goto error_return;
2647 : : }
2648 : :
2649 : :
6756 bruce@momjian.us 2650 :CBC 35092 : keep_going: /* We will come back to here until there is
2651 : : * nothing left to do. */
2652 : :
2653 : : /* Time to advance to next address, or next host if no more addresses? */
2078 tgl@sss.pgh.pa.us 2654 [ + + ]: 73461 : if (conn->try_next_addr)
2655 : : {
382 dgustafsson@postgres 2656 [ + - ]: 339 : if (conn->whichaddr < conn->naddr)
2657 : : {
2658 : 339 : conn->whichaddr++;
2078 tgl@sss.pgh.pa.us 2659 : 339 : reset_connection_state_machine = true;
2660 : : }
2661 : : else
2078 tgl@sss.pgh.pa.us 2662 :UBC 0 : conn->try_next_host = true;
2078 tgl@sss.pgh.pa.us 2663 :CBC 339 : conn->try_next_addr = false;
2664 : : }
2665 : :
2666 : : /* Time to advance to next connhost[] entry? */
2667 [ + + ]: 73461 : if (conn->try_next_host)
2668 : : {
2669 : : pg_conn_host *ch;
2670 : : struct addrinfo hint;
2671 : : struct addrinfo *addrlist;
2672 : : int thisport;
2673 : : int ret;
2674 : : char portstr[MAXPGPATH];
2675 : :
1139 2676 [ + + ]: 12549 : if (conn->whichhost + 1 < conn->nconnhost)
2677 : 12093 : conn->whichhost++;
2678 : : else
2679 : : {
2680 : : /*
2681 : : * Oops, no more hosts.
2682 : : *
2683 : : * If we are trying to connect in "prefer-standby" mode, then drop
2684 : : * the standby requirement and start over. Don't do this for
2685 : : * cancel requests though, since we are certain the list of
2686 : : * servers won't change as the target_server_type option is not
2687 : : * applicable to those connections.
2688 : : *
2689 : : * Otherwise, an appropriate error message is already set up, so
2690 : : * we just need to set the right status.
2691 : : */
2692 [ + + ]: 456 : if (conn->target_server_type == SERVER_TYPE_PREFER_STANDBY &&
33 alvherre@alvh.no-ip. 2693 [ + - ]:GNC 1 : conn->nconnhost > 0 &&
2694 [ + - ]: 1 : !conn->cancelRequest)
2695 : : {
1139 tgl@sss.pgh.pa.us 2696 :CBC 1 : conn->target_server_type = SERVER_TYPE_PREFER_STANDBY_PASS2;
2697 : 1 : conn->whichhost = 0;
2698 : : }
2699 : : else
2700 : 455 : goto error_return;
2701 : : }
2702 : :
2703 : : /* Drop any address info for previous host */
2061 2704 : 12094 : release_conn_addrinfo(conn);
2705 : :
2706 : : /*
2707 : : * Look up info for the new host. On failure, log the problem in
2708 : : * conn->errorMessage, then loop around to try the next host. (Note
2709 : : * we don't clear try_next_host until we've succeeded.)
2710 : : */
2711 : 12094 : ch = &conn->connhost[conn->whichhost];
2712 : :
2713 : : /* Initialize hint structure */
2714 [ + - + - : 84658 : MemSet(&hint, 0, sizeof(hint));
+ - + - +
+ ]
2715 : 12094 : hint.ai_socktype = SOCK_STREAM;
382 dgustafsson@postgres 2716 : 12094 : hint.ai_family = AF_UNSPEC;
2717 : :
2718 : : /* Figure out the port number we're going to use. */
2061 tgl@sss.pgh.pa.us 2719 [ + - - + ]: 12094 : if (ch->port == NULL || ch->port[0] == '\0')
2061 tgl@sss.pgh.pa.us 2720 :UBC 0 : thisport = DEF_PGPORT;
2721 : : else
2722 : : {
76 alvherre@alvh.no-ip. 2723 [ - + ]:GNC 12094 : if (!pqParseIntParam(ch->port, &thisport, conn, "port"))
2041 michael@paquier.xyz 2724 :UBC 0 : goto error_return;
2725 : :
2061 tgl@sss.pgh.pa.us 2726 [ + + - + ]:CBC 12094 : if (thisport < 1 || thisport > 65535)
2727 : : {
516 peter@eisentraut.org 2728 : 3 : libpq_append_conn_error(conn, "invalid port number: \"%s\"", ch->port);
2061 tgl@sss.pgh.pa.us 2729 : 3 : goto keep_going;
2730 : : }
2731 : : }
2732 : 12091 : snprintf(portstr, sizeof(portstr), "%d", thisport);
2733 : :
2734 : : /* Use pg_getaddrinfo_all() to resolve the address */
2735 [ + + + - ]: 12091 : switch (ch->type)
2736 : : {
2737 : 57 : case CHT_HOST_NAME:
2738 : 57 : ret = pg_getaddrinfo_all(ch->host, portstr, &hint,
2739 : : &addrlist);
382 dgustafsson@postgres 2740 [ + - - + ]: 57 : if (ret || !addrlist)
2741 : : {
516 peter@eisentraut.org 2742 :UBC 0 : libpq_append_conn_error(conn, "could not translate host name \"%s\" to address: %s",
2743 : : ch->host, gai_strerror(ret));
2061 tgl@sss.pgh.pa.us 2744 : 0 : goto keep_going;
2745 : : }
2061 tgl@sss.pgh.pa.us 2746 :CBC 57 : break;
2747 : :
2748 : 523 : case CHT_HOST_ADDRESS:
2749 : 523 : hint.ai_flags = AI_NUMERICHOST;
2750 : 523 : ret = pg_getaddrinfo_all(ch->hostaddr, portstr, &hint,
2751 : : &addrlist);
382 dgustafsson@postgres 2752 [ + - - + ]: 523 : if (ret || !addrlist)
2753 : : {
516 peter@eisentraut.org 2754 :UBC 0 : libpq_append_conn_error(conn, "could not parse network address \"%s\": %s",
2755 : : ch->hostaddr, gai_strerror(ret));
2061 tgl@sss.pgh.pa.us 2756 : 0 : goto keep_going;
2757 : : }
2061 tgl@sss.pgh.pa.us 2758 :CBC 523 : break;
2759 : :
2760 : 11511 : case CHT_UNIX_SOCKET:
382 dgustafsson@postgres 2761 : 11511 : hint.ai_family = AF_UNIX;
2061 tgl@sss.pgh.pa.us 2762 [ - + - + ]: 11511 : UNIXSOCK_PATH(portstr, thisport, ch->host);
2763 [ - + ]: 11511 : if (strlen(portstr) >= UNIXSOCK_PATH_BUFLEN)
2764 : : {
516 peter@eisentraut.org 2765 :UBC 0 : libpq_append_conn_error(conn, "Unix-domain socket path \"%s\" is too long (maximum %d bytes)",
2766 : : portstr,
2767 : : (int) (UNIXSOCK_PATH_BUFLEN - 1));
2061 tgl@sss.pgh.pa.us 2768 : 0 : goto keep_going;
2769 : : }
2770 : :
2771 : : /*
2772 : : * NULL hostname tells pg_getaddrinfo_all to parse the service
2773 : : * name as a Unix-domain socket path.
2774 : : */
2061 tgl@sss.pgh.pa.us 2775 :CBC 11511 : ret = pg_getaddrinfo_all(NULL, portstr, &hint,
2776 : : &addrlist);
382 dgustafsson@postgres 2777 [ + - - + ]: 11511 : if (ret || !addrlist)
2778 : : {
516 peter@eisentraut.org 2779 :UBC 0 : libpq_append_conn_error(conn, "could not translate Unix-domain socket path \"%s\" to address: %s",
2780 : : portstr, gai_strerror(ret));
2061 tgl@sss.pgh.pa.us 2781 : 0 : goto keep_going;
2782 : : }
2061 tgl@sss.pgh.pa.us 2783 :CBC 11511 : break;
2784 : : }
2785 : :
2786 : : /*
2787 : : * Store a copy of the addrlist in private memory so we can perform
2788 : : * randomization for load balancing.
2789 : : */
382 dgustafsson@postgres 2790 : 12091 : ret = store_conn_addrinfo(conn, addrlist);
2791 : 12091 : pg_freeaddrinfo_all(hint.ai_family, addrlist);
2792 [ - + ]: 12091 : if (ret)
382 dgustafsson@postgres 2793 :UBC 0 : goto error_return; /* message already logged */
2794 : :
2795 : : /*
2796 : : * If random load balancing is enabled we shuffle the addresses.
2797 : : */
382 dgustafsson@postgres 2798 [ + + ]:CBC 12091 : if (conn->load_balance_type == LOAD_BALANCE_RANDOM)
2799 : : {
2800 : : /*
2801 : : * This is the "inside-out" variant of the Fisher-Yates shuffle
2802 : : * algorithm. Notionally, we append each new value to the array
2803 : : * and then swap it with a randomly-chosen array element (possibly
2804 : : * including itself, else we fail to generate permutations with
2805 : : * the last integer last). The swap step can be optimized by
2806 : : * combining it with the insertion.
2807 : : *
2808 : : * We don't need to initialize conn->prng_state here, because that
2809 : : * already happened in pqConnectOptions2.
2810 : : */
2811 [ + + ]: 226 : for (int i = 1; i < conn->naddr; i++)
2812 : : {
2813 : 110 : int j = pg_prng_uint64_range(&conn->prng_state, 0, i);
2814 : 110 : AddrInfo temp = conn->addr[j];
2815 : :
2816 : 110 : conn->addr[j] = conn->addr[i];
2817 : 110 : conn->addr[i] = temp;
2818 : : }
2819 : : }
2820 : :
2078 tgl@sss.pgh.pa.us 2821 : 12091 : reset_connection_state_machine = true;
2822 : 12091 : conn->try_next_host = false;
2823 : : }
2824 : :
2825 : : /* Reset connection state machine? */
2826 [ + + ]: 73003 : if (reset_connection_state_machine)
2827 : : {
2828 : : /*
2829 : : * (Re) initialize our connection control variables for a set of
2830 : : * connection attempts to a single server address. These variables
2831 : : * must persist across individual connection attempts, but we must
2832 : : * reset them when we start to consider a new server.
2833 : : */
2834 : 12430 : conn->pversion = PG_PROTOCOL(3, 0);
2835 : 12430 : conn->send_appname = true;
6 heikki.linnakangas@i 2836 :GNC 12430 : conn->failed_enc_methods = 0;
2837 : 12430 : conn->current_enc_method = 0;
2838 : 12430 : conn->allowed_enc_methods = 0;
2078 tgl@sss.pgh.pa.us 2839 :CBC 12430 : reset_connection_state_machine = false;
2840 : 12430 : need_new_connection = true;
2841 : : }
2842 : :
2843 : : /* Force a new connection (perhaps to the same server as before)? */
2844 [ + + ]: 73003 : if (need_new_connection)
2845 : : {
2846 : : /* Drop any existing connection */
2847 : 12518 : pqDropConnection(conn, true);
2848 : :
2849 : : /* Reset all state obtained from old server */
2850 : 12518 : pqDropServerData(conn);
2851 : :
2852 : : /* Drop any PGresult we might have, too */
2853 : 12518 : conn->asyncStatus = PGASYNC_IDLE;
2854 : 12518 : conn->xactStatus = PQTRANS_IDLE;
1126 alvherre@alvh.no-ip. 2855 : 12518 : conn->pipelineStatus = PQ_PIPELINE_OFF;
2078 tgl@sss.pgh.pa.us 2856 : 12518 : pqClearAsyncResult(conn);
2857 : :
2858 : : /* Reset conn->status to put the state machine in the right state */
2859 : 12518 : conn->status = CONNECTION_NEEDED;
2860 : :
2861 : 12518 : need_new_connection = false;
2862 : : }
2863 : :
2864 : : /* Decide what to do next, if SSL or GSS negotiation fails */
2865 : : #define ENCRYPTION_NEGOTIATION_FAILED() \
2866 : : do { \
2867 : : switch (encryption_negotiation_failed(conn)) \
2868 : : { \
2869 : : case 0: \
2870 : : goto error_return; \
2871 : : case 1: \
2872 : : conn->status = CONNECTION_MADE; \
2873 : : return PGRES_POLLING_WRITING; \
2874 : : case 2: \
2875 : : need_new_connection = true; \
2876 : : goto keep_going; \
2877 : : } \
2878 : : } while(0);
2879 : :
2880 : : /* Decide what to do next, if connection fails */
2881 : : #define CONNECTION_FAILED() \
2882 : : do { \
2883 : : if (connection_failed(conn)) \
2884 : : { \
2885 : : need_new_connection = true; \
2886 : : goto keep_going; \
2887 : : } \
2888 : : else \
2889 : : goto error_return; \
2890 : : } while(0);
2891 : :
2892 : : /* Now try to advance the state machine for this connection */
8768 bruce@momjian.us 2893 [ + + + + : 73003 : switch (conn->status)
+ + + + -
- - - ]
2894 : : {
7616 tgl@sss.pgh.pa.us 2895 : 12524 : case CONNECTION_NEEDED:
2896 : : {
2897 : : /*
2898 : : * Try to initiate a connection to one of the addresses
2899 : : * returned by pg_getaddrinfo_all(). conn->whichaddr is the
2900 : : * next one to try.
2901 : : *
2902 : : * The extra level of braces here is historical. It's not
2903 : : * worth reindenting this whole switch case to remove 'em.
2904 : : */
2905 : : {
2906 : : char host_addr[NI_MAXHOST];
2907 : : int sock_type;
2908 : : AddrInfo *addr_cur;
2909 : :
2910 : : /*
2911 : : * Advance to next possible host, if we've tried all of
2912 : : * the addresses for the current host.
2913 : : */
382 dgustafsson@postgres 2914 [ + + ]: 12524 : if (conn->whichaddr == conn->naddr)
2915 : : {
2078 tgl@sss.pgh.pa.us 2916 : 333 : conn->try_next_host = true;
2917 : 11849 : goto keep_going;
2918 : : }
382 dgustafsson@postgres 2919 : 12191 : addr_cur = &conn->addr[conn->whichaddr];
2920 : :
2921 : : /* Remember current address for possible use later */
2922 : 12191 : memcpy(&conn->raddr, &addr_cur->addr, sizeof(SockAddr));
2923 : :
2924 : : #ifdef ENABLE_GSS
2925 : :
2926 : : /*
2927 : : * Before establishing the connection, check if it's
2928 : : * doomed to fail because gssencmode='require' but GSSAPI
2929 : : * is not available.
2930 : : */
6 heikki.linnakangas@i 2931 [ + + ]:GNC 12191 : if (conn->gssencmode[0] == 'r')
2932 : : {
2933 [ + + ]: 130 : if (conn->raddr.addr.ss_family == AF_UNIX)
2934 : : {
2935 : 1 : libpq_append_conn_error(conn,
2936 : : "GSSAPI encryption required but it is not supported over a local socket");
2937 : 13 : goto error_return;
2938 : : }
2939 [ + - ]: 129 : if (conn->gcred == GSS_C_NO_CREDENTIAL)
2940 : : {
2941 [ + + ]: 129 : if (!pg_GSS_have_cred_cache(&conn->gcred))
2942 : : {
2943 : 12 : libpq_append_conn_error(conn,
2944 : : "GSSAPI encryption required but no credential cache");
2945 : 12 : goto error_return;
2946 : : }
2947 : : }
2948 : : }
2949 : : #endif
2950 : :
2951 : : /*
2952 : : * Choose the encryption method to try first. Do this
2953 : : * before establishing the connection, so that if none of
2954 : : * the modes allowed by the connections options are
2955 : : * available, we can error out before establishing the
2956 : : * connection.
2957 : : */
2958 [ - + ]: 12178 : if (!init_allowed_encryption_methods(conn))
6 heikki.linnakangas@i 2959 :UNC 0 : goto error_return;
2960 : :
2961 : : /*
2962 : : * Set connip, too. Note we purposely ignore strdup
2963 : : * failure; not a big problem if it fails.
2964 : : */
1973 alvherre@alvh.no-ip. 2965 [ + + ]:CBC 12178 : if (conn->connip != NULL)
2966 : : {
2967 : 94 : free(conn->connip);
2968 : 94 : conn->connip = NULL;
2969 : : }
2970 : 12178 : getHostaddr(conn, host_addr, NI_MAXHOST);
1189 tgl@sss.pgh.pa.us 2971 [ + + ]: 12178 : if (host_addr[0])
1973 alvherre@alvh.no-ip. 2972 : 662 : conn->connip = strdup(host_addr);
2973 : :
2974 : : /* Try to create the socket */
394 tmunro@postgresql.or 2975 : 12178 : sock_type = SOCK_STREAM;
2976 : : #ifdef SOCK_CLOEXEC
2977 : :
2978 : : /*
2979 : : * Atomically mark close-on-exec, if possible on this
2980 : : * platform, so that there isn't a window where a
2981 : : * subprogram executed by another thread inherits the
2982 : : * socket. See fallback code below.
2983 : : */
2984 : 12178 : sock_type |= SOCK_CLOEXEC;
2985 : : #endif
2986 : : #ifdef SOCK_NONBLOCK
2987 : :
2988 : : /*
2989 : : * We might as well skip a system call for nonblocking
2990 : : * mode too, if we can.
2991 : : */
2992 : 12178 : sock_type |= SOCK_NONBLOCK;
2993 : : #endif
382 dgustafsson@postgres 2994 : 12178 : conn->sock = socket(addr_cur->family, sock_type, 0);
3651 bruce@momjian.us 2995 [ - + ]: 12178 : if (conn->sock == PGINVALID_SOCKET)
2996 : : {
1189 tgl@sss.pgh.pa.us 2997 :UBC 0 : int errorno = SOCK_ERRNO;
2998 : :
2999 : : /*
3000 : : * Silently ignore socket() failure if we have more
3001 : : * addresses to try; this reduces useless chatter in
3002 : : * cases where the address list includes both IPv4 and
3003 : : * IPv6 but kernel only accepts one family.
3004 : : */
382 dgustafsson@postgres 3005 [ # # ]: 0 : if (conn->whichaddr < conn->naddr ||
2719 rhaas@postgresql.org 3006 [ # # ]: 0 : conn->whichhost + 1 < conn->nconnhost)
3007 : : {
2078 tgl@sss.pgh.pa.us 3008 : 0 : conn->try_next_addr = true;
3009 : 0 : goto keep_going;
3010 : : }
1179 3011 : 0 : emitHostIdentityInfo(conn, host_addr);
516 peter@eisentraut.org 3012 : 0 : libpq_append_conn_error(conn, "could not create socket: %s",
3013 : : SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)));
2078 tgl@sss.pgh.pa.us 3014 : 0 : goto error_return;
3015 : : }
3016 : :
3017 : : /*
3018 : : * Once we've identified a target address, all errors
3019 : : * except the preceding socket()-failure case should be
3020 : : * prefixed with host-identity information. (If the
3021 : : * connection succeeds, the contents of conn->errorMessage
3022 : : * won't matter, so this is harmless.)
3023 : : */
1179 tgl@sss.pgh.pa.us 3024 :CBC 12178 : emitHostIdentityInfo(conn, host_addr);
3025 : :
3026 : : /*
3027 : : * Select socket options: no delay of outgoing data for
3028 : : * TCP sockets, nonblock mode, close-on-exec. Try the
3029 : : * next address if any of this fails.
3030 : : */
382 dgustafsson@postgres 3031 [ + + ]: 12178 : if (addr_cur->family != AF_UNIX)
3032 : : {
7616 tgl@sss.pgh.pa.us 3033 [ - + ]: 662 : if (!connectNoDelay(conn))
3034 : : {
3035 : : /* error message already created */
2078 tgl@sss.pgh.pa.us 3036 :UBC 0 : conn->try_next_addr = true;
3037 : 0 : goto keep_going;
3038 : : }
3039 : : }
3040 : : #ifndef SOCK_NONBLOCK
3041 : : if (!pg_set_noblock(conn->sock))
3042 : : {
3043 : : libpq_append_conn_error(conn, "could not set socket to nonblocking mode: %s",
3044 : : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
3045 : : conn->try_next_addr = true;
3046 : : goto keep_going;
3047 : : }
3048 : : #endif
3049 : :
3050 : : #ifndef SOCK_CLOEXEC
3051 : : #ifdef F_SETFD
3052 : : if (fcntl(conn->sock, F_SETFD, FD_CLOEXEC) == -1)
3053 : : {
3054 : : libpq_append_conn_error(conn, "could not set socket to close-on-exec mode: %s",
3055 : : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
3056 : : conn->try_next_addr = true;
3057 : : goto keep_going;
3058 : : }
3059 : : #endif /* F_SETFD */
3060 : : #endif
3061 : :
382 dgustafsson@postgres 3062 [ + + ]:CBC 12178 : if (addr_cur->family != AF_UNIX)
3063 : : {
3064 : : #ifndef WIN32
5031 bruce@momjian.us 3065 : 662 : int on = 1;
3066 : : #endif
3067 : 662 : int usekeepalives = useKeepalives(conn);
3068 : 662 : int err = 0;
3069 : :
5044 rhaas@postgresql.org 3070 [ - + ]: 662 : if (usekeepalives < 0)
3071 : : {
516 peter@eisentraut.org 3072 :UBC 0 : libpq_append_conn_error(conn, "keepalives parameter must be an integer");
5044 rhaas@postgresql.org 3073 : 0 : err = 1;
3074 : : }
5044 rhaas@postgresql.org 3075 [ + - ]:CBC 662 : else if (usekeepalives == 0)
3076 : : {
3077 : : /* Do nothing */
3078 : : }
3079 : : #ifndef WIN32
3080 [ - + ]: 662 : else if (setsockopt(conn->sock,
3081 : : SOL_SOCKET, SO_KEEPALIVE,
3082 : : (char *) &on, sizeof(on)) < 0)
3083 : : {
516 peter@eisentraut.org 3084 :UBC 0 : libpq_append_conn_error(conn, "%s(%s) failed: %s",
3085 : : "setsockopt",
3086 : : "SO_KEEPALIVE",
402 michael@paquier.xyz 3087 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
5044 rhaas@postgresql.org 3088 : 0 : err = 1;
3089 : : }
5044 rhaas@postgresql.org 3090 [ + - ]:CBC 662 : else if (!setKeepalivesIdle(conn)
3091 [ + - ]: 662 : || !setKeepalivesInterval(conn)
3092 [ - + ]: 662 : || !setKeepalivesCount(conn))
5044 rhaas@postgresql.org 3093 :UBC 0 : err = 1;
3094 : : #else /* WIN32 */
3095 : : #ifdef SIO_KEEPALIVE_VALS
3096 : : else if (!prepKeepalivesWin32(conn))
3097 : : err = 1;
3098 : : #endif /* SIO_KEEPALIVE_VALS */
3099 : : #endif /* WIN32 */
1835 michael@paquier.xyz 3100 [ - + ]:CBC 662 : else if (!setTCPUserTimeout(conn))
1835 michael@paquier.xyz 3101 :UBC 0 : err = 1;
3102 : :
5044 rhaas@postgresql.org 3103 [ - + ]:CBC 662 : if (err)
3104 : : {
2078 tgl@sss.pgh.pa.us 3105 :UBC 0 : conn->try_next_addr = true;
3106 : 0 : goto keep_going;
3107 : : }
3108 : : }
3109 : :
3110 : : /*----------
3111 : : * We have three methods of blocking SIGPIPE during
3112 : : * send() calls to this socket:
3113 : : *
3114 : : * - setsockopt(sock, SO_NOSIGPIPE)
3115 : : * - send(sock, ..., MSG_NOSIGNAL)
3116 : : * - setting the signal mask to SIG_IGN during send()
3117 : : *
3118 : : * The third method requires three syscalls per send,
3119 : : * so we prefer either of the first two, but they are
3120 : : * less portable. The state is tracked in the following
3121 : : * members of PGconn:
3122 : : *
3123 : : * conn->sigpipe_so - we have set up SO_NOSIGPIPE
3124 : : * conn->sigpipe_flag - we're specifying MSG_NOSIGNAL
3125 : : *
3126 : : * If we can use SO_NOSIGPIPE, then set sigpipe_so here
3127 : : * and we're done. Otherwise, set sigpipe_flag so that
3128 : : * we will try MSG_NOSIGNAL on sends. If we get an error
3129 : : * with MSG_NOSIGNAL, we'll clear that flag and revert to
3130 : : * signal masking.
3131 : : *----------
3132 : : */
5378 tgl@sss.pgh.pa.us 3133 :CBC 12178 : conn->sigpipe_so = false;
3134 : : #ifdef MSG_NOSIGNAL
3135 : 12178 : conn->sigpipe_flag = true;
3136 : : #else
3137 : : conn->sigpipe_flag = false;
3138 : : #endif /* MSG_NOSIGNAL */
3139 : :
3140 : : #ifdef SO_NOSIGPIPE
3141 : : optval = 1;
3142 : : if (setsockopt(conn->sock, SOL_SOCKET, SO_NOSIGPIPE,
3143 : : (char *) &optval, sizeof(optval)) == 0)
3144 : : {
3145 : : conn->sigpipe_so = true;
3146 : : conn->sigpipe_flag = false;
3147 : : }
3148 : : #endif /* SO_NOSIGPIPE */
3149 : :
3150 : : /*
3151 : : * Start/make connection. This should not block, since we
3152 : : * are in nonblock mode. If it does, well, too bad.
3153 : : */
382 dgustafsson@postgres 3154 [ + + ]: 12178 : if (connect(conn->sock, (struct sockaddr *) &addr_cur->addr.addr,
3155 : : addr_cur->addr.salen) < 0)
3156 : : {
7616 tgl@sss.pgh.pa.us 3157 [ + + ]: 995 : if (SOCK_ERRNO == EINPROGRESS ||
3158 : : #ifdef WIN32
3159 : : SOCK_ERRNO == EWOULDBLOCK ||
3160 : : #endif
3944 3161 [ - + ]: 333 : SOCK_ERRNO == EINTR)
3162 : : {
3163 : : /*
3164 : : * This is fine - we're in non-blocking mode, and
3165 : : * the connection is in progress. Tell caller to
3166 : : * wait for write-ready on socket.
3167 : : */
7616 3168 : 662 : conn->status = CONNECTION_STARTED;
3169 : 662 : return PGRES_POLLING_WRITING;
3170 : : }
3171 : : /* otherwise, trouble */
3172 : : }
3173 : : else
3174 : : {
3175 : : /*
3176 : : * Hm, we're connected already --- seems the "nonblock
3177 : : * connection" wasn't. Advance the state machine and
3178 : : * go do the next stuff.
3179 : : */
3180 : 11183 : conn->status = CONNECTION_STARTED;
3181 : 11183 : goto keep_going;
3182 : : }
3183 : :
3184 : : /*
3185 : : * This connection failed. Add the error report to
3186 : : * conn->errorMessage, then try the next address if any.
3187 : : */
3188 : 333 : connectFailureMessage(conn, SOCK_ERRNO);
2078 3189 : 333 : conn->try_next_addr = true;
3190 : 333 : goto keep_going;
3191 : : }
3192 : : }
3193 : :
8902 bruce@momjian.us 3194 : 11845 : case CONNECTION_STARTED:
3195 : : {
887 peter@eisentraut.org 3196 : 11845 : socklen_t optlen = sizeof(optval);
3197 : :
3198 : : /*
3199 : : * Write ready, since we've made it here, so the connection
3200 : : * has been made ... or has failed.
3201 : : */
3202 : :
3203 : : /*
3204 : : * Now check (using getsockopt) that there is not an error
3205 : : * state waiting for us on the socket.
3206 : : */
3207 : :
8768 bruce@momjian.us 3208 [ - + ]: 11845 : if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
3209 : : (char *) &optval, &optlen) == -1)
3210 : : {
516 peter@eisentraut.org 3211 :UBC 0 : libpq_append_conn_error(conn, "could not get socket error status: %s",
402 michael@paquier.xyz 3212 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
8768 bruce@momjian.us 3213 : 0 : goto error_return;
3214 : : }
8768 bruce@momjian.us 3215 [ + + ]:CBC 11845 : else if (optval != 0)
3216 : : {
3217 : : /*
3218 : : * When using a nonblocking connect, we will typically see
3219 : : * connect failures at this point, so provide a friendly
3220 : : * error message.
3221 : : */
8309 peter_e@gmx.net 3222 : 6 : connectFailureMessage(conn, optval);
3223 : :
3224 : : /*
3225 : : * Try the next address if any, just as in the case where
3226 : : * connect() returned failure immediately.
3227 : : */
2078 tgl@sss.pgh.pa.us 3228 : 6 : conn->try_next_addr = true;
3229 : 6 : goto keep_going;
3230 : : }
3231 : :
3232 : : /* Fill in the client address */
7612 bruce@momjian.us 3233 : 11839 : conn->laddr.salen = sizeof(conn->laddr.addr);
7559 3234 [ - + ]: 11839 : if (getsockname(conn->sock,
2489 tgl@sss.pgh.pa.us 3235 : 11839 : (struct sockaddr *) &conn->laddr.addr,
3236 : : &conn->laddr.salen) < 0)
3237 : : {
516 peter@eisentraut.org 3238 :UBC 0 : libpq_append_conn_error(conn, "could not get client address from socket: %s",
402 michael@paquier.xyz 3239 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
8768 bruce@momjian.us 3240 : 0 : goto error_return;
3241 : : }
3242 : :
3243 : : /*
3244 : : * Implement requirepeer check, if requested and it's a
3245 : : * Unix-domain socket.
3246 : : */
4702 tgl@sss.pgh.pa.us 3247 [ - + - - ]:CBC 11839 : if (conn->requirepeer && conn->requirepeer[0] &&
789 peter@eisentraut.org 3248 [ # # ]:UBC 0 : conn->raddr.addr.ss_family == AF_UNIX)
3249 : : {
3250 : : #ifndef WIN32
3251 : : char *remote_username;
3252 : : #endif
3253 : : uid_t uid;
3254 : : gid_t gid;
3255 : :
5019 peter_e@gmx.net 3256 : 0 : errno = 0;
tgl@sss.pgh.pa.us 3257 [ # # ]: 0 : if (getpeereid(conn->sock, &uid, &gid) != 0)
3258 : : {
3259 : : /*
3260 : : * Provide special error message if getpeereid is a
3261 : : * stub
3262 : : */
4700 3263 [ # # ]: 0 : if (errno == ENOSYS)
516 peter@eisentraut.org 3264 : 0 : libpq_append_conn_error(conn, "requirepeer parameter is not supported on this platform");
3265 : : else
3266 : 0 : libpq_append_conn_error(conn, "could not get peer credentials: %s",
402 michael@paquier.xyz 3267 : 0 : strerror_r(errno, sebuf, sizeof(sebuf)));
5019 peter_e@gmx.net 3268 : 0 : goto error_return;
3269 : : }
3270 : :
3271 : : #ifndef WIN32
824 tgl@sss.pgh.pa.us 3272 : 0 : remote_username = pg_fe_getusername(uid,
3273 : : &conn->errorMessage);
3274 [ # # ]: 0 : if (remote_username == NULL)
3275 : 0 : goto error_return; /* message already logged */
3276 : :
3277 [ # # ]: 0 : if (strcmp(remote_username, conn->requirepeer) != 0)
3278 : : {
516 peter@eisentraut.org 3279 : 0 : libpq_append_conn_error(conn, "requirepeer specifies \"%s\", but actual peer user name is \"%s\"",
3280 : : conn->requirepeer, remote_username);
824 tgl@sss.pgh.pa.us 3281 : 0 : free(remote_username);
5019 peter_e@gmx.net 3282 : 0 : goto error_return;
3283 : : }
824 tgl@sss.pgh.pa.us 3284 : 0 : free(remote_username);
3285 : : #else /* WIN32 */
3286 : : /* should have failed with ENOSYS above */
3287 : : Assert(false);
3288 : : #endif /* WIN32 */
3289 : : }
3290 : :
3291 : : /*
3292 : : * Make sure we can write before advancing to next step.
3293 : : */
6 heikki.linnakangas@i 3294 :GNC 11839 : conn->status = CONNECTION_MADE;
3295 : 11839 : return PGRES_POLLING_WRITING;
3296 : : }
3297 : :
3298 : 12317 : case CONNECTION_MADE:
3299 : : {
3300 : : char *startpacket;
3301 : : int packetlen;
3302 : :
3303 : : #ifdef ENABLE_GSS
3304 : :
3305 : : /*
3306 : : * If GSSAPI encryption is enabled, send a packet to the
3307 : : * server asking for GSSAPI Encryption and proceed with GSSAPI
3308 : : * handshake. We will come back here after GSSAPI encryption
3309 : : * has been established, with conn->gctx set.
3310 : : */
3311 [ + + + + ]: 12317 : if (conn->current_enc_method == ENC_GSSAPI && !conn->gctx)
3312 : : {
1838 sfrost@snowman.net 3313 :CBC 233 : ProtocolVersion pv = pg_hton32(NEGOTIATE_GSS_CODE);
3314 : :
3315 [ - + ]: 233 : if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
3316 : : {
516 peter@eisentraut.org 3317 :UBC 0 : libpq_append_conn_error(conn, "could not send GSSAPI negotiation packet: %s",
402 michael@paquier.xyz 3318 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1838 sfrost@snowman.net 3319 : 0 : goto error_return;
3320 : : }
3321 : :
3322 : : /* Ok, wait for response */
1838 sfrost@snowman.net 3323 :CBC 233 : conn->status = CONNECTION_GSS_STARTUP;
3324 : 233 : return PGRES_POLLING_READING;
3325 : : }
3326 : : #endif
3327 : :
3328 : : #ifdef USE_SSL
3329 : :
3330 : : /*
3331 : : * Enable the libcrypto callbacks before checking if SSL needs
3332 : : * to be done. This is done before sending the startup packet
3333 : : * as depending on the type of authentication done, like MD5
3334 : : * or SCRAM that use cryptohashes, the callbacks would be
3335 : : * required even without a SSL connection
3336 : : */
1130 michael@paquier.xyz 3337 [ - + ]: 12084 : if (pqsecure_initialize(conn, false, true) < 0)
1130 michael@paquier.xyz 3338 :UBC 0 : goto error_return;
3339 : :
3340 : : /*
3341 : : * If direct SSL is enabled, jump right into SSL handshake. We
3342 : : * will come back here after SSL encryption has been
3343 : : * established, with ssl_in_use set.
3344 : : */
6 heikki.linnakangas@i 3345 [ + + + + ]:GNC 12084 : if (conn->current_enc_method == ENC_DIRECT_SSL && !conn->ssl_in_use)
3346 : : {
3347 : 74 : conn->status = CONNECTION_SSL_STARTUP;
3348 : 74 : return PGRES_POLLING_WRITING;
3349 : : }
3350 : :
3351 : : /*
3352 : : * If negotiated SSL is enabled, request SSL and proceed with
3353 : : * SSL handshake. We will come back here after SSL encryption
3354 : : * has been established, with ssl_in_use set.
3355 : : */
3356 [ + + + + ]: 12010 : if (conn->current_enc_method == ENC_NEGOTIATED_SSL && !conn->ssl_in_use)
3357 : : {
3358 : : ProtocolVersion pv;
3359 : :
3360 : : /*
3361 : : * Send the SSL request packet.
3362 : : *
3363 : : * Theoretically, this could block, but it really
3364 : : * shouldn't since we only got here if the socket is
3365 : : * write-ready.
3366 : : */
2387 andres@anarazel.de 3367 :CBC 237 : pv = pg_hton32(NEGOTIATE_SSL_CODE);
7616 tgl@sss.pgh.pa.us 3368 [ - + ]: 237 : if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
3369 : : {
516 peter@eisentraut.org 3370 :UBC 0 : libpq_append_conn_error(conn, "could not send SSL negotiation packet: %s",
402 michael@paquier.xyz 3371 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
7616 tgl@sss.pgh.pa.us 3372 : 0 : goto error_return;
3373 : : }
3374 : : /* Ok, wait for response */
7616 tgl@sss.pgh.pa.us 3375 :CBC 237 : conn->status = CONNECTION_SSL_STARTUP;
3376 : 237 : return PGRES_POLLING_READING;
3377 : : }
3378 : : #endif /* USE_SSL */
3379 : :
3380 : : /*
3381 : : * For cancel requests this is as far as we need to go in the
3382 : : * connection establishment. Now we can actually send our
3383 : : * cancellation request.
3384 : : */
33 alvherre@alvh.no-ip. 3385 [ + + ]:GNC 11773 : if (conn->cancelRequest)
3386 : : {
3387 : : CancelRequestPacket cancelpacket;
3388 : :
3389 : 6 : packetlen = sizeof(cancelpacket);
3390 : 6 : cancelpacket.cancelRequestCode = (MsgType) pg_hton32(CANCEL_REQUEST_CODE);
3391 : 6 : cancelpacket.backendPID = pg_hton32(conn->be_pid);
3392 : 6 : cancelpacket.cancelAuthCode = pg_hton32(conn->be_key);
3393 [ - + ]: 6 : if (pqPacketSend(conn, 0, &cancelpacket, packetlen) != STATUS_OK)
3394 : : {
33 alvherre@alvh.no-ip. 3395 :UNC 0 : libpq_append_conn_error(conn, "could not send cancel packet: %s",
3396 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
3397 : 0 : goto error_return;
3398 : : }
33 alvherre@alvh.no-ip. 3399 :GNC 6 : conn->status = CONNECTION_AWAITING_RESPONSE;
3400 : 6 : return PGRES_POLLING_READING;
3401 : : }
3402 : :
3403 : : /*
3404 : : * We have now established encryption, or we are happy to
3405 : : * proceed without.
3406 : : */
3407 : :
3408 : : /* Build the startup packet. */
1137 heikki.linnakangas@i 3409 :CBC 11767 : startpacket = pqBuildStartupPacket3(conn, &packetlen,
3410 : : EnvironmentOptions);
7668 tgl@sss.pgh.pa.us 3411 [ - + ]: 11767 : if (!startpacket)
3412 : : {
516 peter@eisentraut.org 3413 :UBC 0 : libpq_append_conn_error(conn, "out of memory");
7668 tgl@sss.pgh.pa.us 3414 : 0 : goto error_return;
3415 : : }
3416 : :
3417 : : /*
3418 : : * Send the startup packet.
3419 : : *
3420 : : * Theoretically, this could block, but it really shouldn't
3421 : : * since we only got here if the socket is write-ready.
3422 : : */
7668 tgl@sss.pgh.pa.us 3423 [ - + ]:CBC 11767 : if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)
3424 : : {
516 peter@eisentraut.org 3425 :UBC 0 : libpq_append_conn_error(conn, "could not send startup packet: %s",
402 michael@paquier.xyz 3426 : 0 : SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
7668 tgl@sss.pgh.pa.us 3427 : 0 : free(startpacket);
8768 bruce@momjian.us 3428 : 0 : goto error_return;
3429 : : }
3430 : :
7668 tgl@sss.pgh.pa.us 3431 :CBC 11767 : free(startpacket);
3432 : :
8768 bruce@momjian.us 3433 : 11767 : conn->status = CONNECTION_AWAITING_RESPONSE;
8902 3434 : 11767 : return PGRES_POLLING_READING;
3435 : : }
3436 : :
3437 : : /*
3438 : : * Handle SSL negotiation: wait for postmaster messages and
3439 : : * respond as necessary.
3440 : : */
7616 tgl@sss.pgh.pa.us 3441 : 695 : case CONNECTION_SSL_STARTUP:
3442 : : {
3443 : : #ifdef USE_SSL
3444 : : PostgresPollingStatusType pollres;
3445 : :
3446 : : /*
3447 : : * On first time through, get the postmaster's response to our
3448 : : * SSL negotiation packet. If we are trying a direct ssl
3449 : : * connection, go straight to initiating ssl.
3450 : : */
6 heikki.linnakangas@i 3451 [ + + + + ]:GNC 695 : if (!conn->ssl_in_use && conn->current_enc_method == ENC_NEGOTIATED_SSL)
3452 : : {
3453 : : /*
3454 : : * We use pqReadData here since it has the logic to
3455 : : * distinguish no-data-yet from connection closure. Since
3456 : : * conn->ssl isn't set, a plain recv() will occur.
3457 : : */
3458 : : char SSLok;
3459 : : int rdresult;
3460 : :
7038 tgl@sss.pgh.pa.us 3461 :CBC 237 : rdresult = pqReadData(conn);
3462 [ - + ]: 237 : if (rdresult < 0)
3463 : : {
3464 : : /* errorMessage is already filled in */
7616 tgl@sss.pgh.pa.us 3465 :UBC 0 : goto error_return;
3466 : : }
7038 tgl@sss.pgh.pa.us 3467 [ - + ]:CBC 237 : if (rdresult == 0)
3468 : : {
3469 : : /* caller failed to wait for data */
7616 tgl@sss.pgh.pa.us 3470 :UBC 0 : return PGRES_POLLING_READING;
3471 : : }
7038 tgl@sss.pgh.pa.us 3472 [ - + ]:CBC 237 : if (pqGetc(&SSLok, conn) < 0)
3473 : : {
3474 : : /* should not happen really */
7038 tgl@sss.pgh.pa.us 3475 :UBC 0 : return PGRES_POLLING_READING;
3476 : : }
7616 tgl@sss.pgh.pa.us 3477 [ + + ]:CBC 237 : if (SSLok == 'S')
3478 : : {
3479 : : /* mark byte consumed */
4614 3480 : 140 : conn->inStart = conn->inCursor;
3481 : : }
7616 3482 [ + - ]: 97 : else if (SSLok == 'N')
3483 : : {
3484 : : /* mark byte consumed */
4614 3485 : 97 : conn->inStart = conn->inCursor;
3486 : : /* OK to do without SSL? */
3487 : : /* We can proceed using this connection */
6 heikki.linnakangas@i 3488 :UNC 0 : ENCRYPTION_NEGOTIATION_FAILED();
3489 : : }
7616 tgl@sss.pgh.pa.us 3490 [ # # ]:UBC 0 : else if (SSLok == 'E')
3491 : : {
3492 : : /*
3493 : : * Server failure of some sort, such as failure to
3494 : : * fork a backend process. We need to process and
3495 : : * report the error message, which might be formatted
3496 : : * according to either protocol 2 or protocol 3.
3497 : : * Rather than duplicate the code for that, we flip
3498 : : * into AWAITING_RESPONSE state and let the code there
3499 : : * deal with it. Note we have *not* consumed the "E"
3500 : : * byte here.
3501 : : */
4614 3502 : 0 : conn->status = CONNECTION_AWAITING_RESPONSE;
7616 3503 : 0 : goto keep_going;
3504 : : }
3505 : : else
3506 : : {
516 peter@eisentraut.org 3507 : 0 : libpq_append_conn_error(conn, "received invalid response to SSL negotiation: %c",
3508 : : SSLok);
7616 tgl@sss.pgh.pa.us 3509 : 0 : goto error_return;
3510 : : }
3511 : : }
3512 : :
3513 : : /*
3514 : : * Set up global SSL state if required. The crypto state has
3515 : : * already been set if libpq took care of doing that, so there
3516 : : * is no need to make that happen again.
3517 : : */
6 heikki.linnakangas@i 3518 [ - + ]:GNC 598 : if (pqsecure_initialize(conn, true, false) != 0)
6 heikki.linnakangas@i 3519 :UNC 0 : goto error_return;
3520 : :
3521 : : /*
3522 : : * Begin or continue the SSL negotiation process.
3523 : : */
7616 tgl@sss.pgh.pa.us 3524 :CBC 598 : pollres = pqsecure_open_client(conn);
3525 [ + + ]: 598 : if (pollres == PGRES_POLLING_OK)
3526 : : {
3527 : : /*
3528 : : * At this point we should have no data already buffered.
3529 : : * If we do, it was received before we performed the SSL
3530 : : * handshake, so it wasn't encrypted and indeed may have
3531 : : * been injected by a man-in-the-middle.
3532 : : */
888 3533 [ - + ]: 162 : if (conn->inCursor != conn->inEnd)
3534 : : {
516 peter@eisentraut.org 3535 :UBC 0 : libpq_append_conn_error(conn, "received unencrypted data after SSL response");
888 tgl@sss.pgh.pa.us 3536 : 0 : goto error_return;
3537 : : }
3538 : :
3539 : : /* SSL handshake done, ready to send startup packet */
7616 tgl@sss.pgh.pa.us 3540 :CBC 162 : conn->status = CONNECTION_MADE;
3541 : 162 : return PGRES_POLLING_WRITING;
3542 : : }
6354 3543 [ + + ]: 436 : if (pollres == PGRES_POLLING_FAILED)
3544 : : {
3545 : : /*
3546 : : * Failed direct ssl connection, possibly try a new
3547 : : * connection with postgres negotiation
3548 : : */
6 heikki.linnakangas@i 3549 [ + + ]:GNC 52 : CONNECTION_FAILED();
3550 : : }
3551 : : /* Else, return POLLING_READING or POLLING_WRITING status */
7616 tgl@sss.pgh.pa.us 3552 :CBC 384 : return pollres;
3553 : : #else /* !USE_SSL */
3554 : : /* can't get here */
3555 : : goto error_return;
3556 : : #endif /* USE_SSL */
3557 : : }
3558 : :
1838 sfrost@snowman.net 3559 : 698 : case CONNECTION_GSS_STARTUP:
3560 : : {
3561 : : #ifdef ENABLE_GSS
3562 : : PostgresPollingStatusType pollres;
3563 : :
3564 : : /*
3565 : : * If we haven't yet, get the postmaster's response to our
3566 : : * negotiation packet
3567 : : */
6 heikki.linnakangas@i 3568 [ + + ]:GNC 698 : if (!conn->gctx)
3569 : : {
3570 : : char gss_ok;
1838 sfrost@snowman.net 3571 :CBC 233 : int rdresult = pqReadData(conn);
3572 : :
3573 [ - + ]: 233 : if (rdresult < 0)
3574 : : /* pqReadData fills in error message */
1838 sfrost@snowman.net 3575 :UBC 0 : goto error_return;
1838 sfrost@snowman.net 3576 [ - + ]:CBC 233 : else if (rdresult == 0)
3577 : : /* caller failed to wait for data */
1838 sfrost@snowman.net 3578 :UBC 0 : return PGRES_POLLING_READING;
1838 sfrost@snowman.net 3579 [ - + ]:CBC 233 : if (pqGetc(&gss_ok, conn) < 0)
3580 : : /* shouldn't happen... */
1838 sfrost@snowman.net 3581 :UBC 0 : return PGRES_POLLING_READING;
3582 : :
1838 sfrost@snowman.net 3583 [ - + ]:CBC 233 : if (gss_ok == 'E')
3584 : : {
3585 : : /*
3586 : : * Server failure of some sort. Assume it's a
3587 : : * protocol version support failure, and let's see if
3588 : : * we can't recover (if it's not, we'll get a better
3589 : : * error message on retry). Server gets fussy if we
3590 : : * don't hang up the socket, though.
3591 : : */
6 heikki.linnakangas@i 3592 [ # # ]:UNC 0 : CONNECTION_FAILED();
3593 : : }
3594 : :
3595 : : /* mark byte consumed */
1838 sfrost@snowman.net 3596 :CBC 233 : conn->inStart = conn->inCursor;
3597 : :
3598 [ - + ]: 233 : if (gss_ok == 'N')
3599 : : {
3600 : : /* We can proceed using this connection */
6 heikki.linnakangas@i 3601 :UNC 0 : ENCRYPTION_NEGOTIATION_FAILED();
3602 : : }
1838 sfrost@snowman.net 3603 [ - + ]:CBC 233 : else if (gss_ok != 'G')
3604 : : {
516 peter@eisentraut.org 3605 :UBC 0 : libpq_append_conn_error(conn, "received invalid response to GSSAPI negotiation: %c",
3606 : : gss_ok);
1838 sfrost@snowman.net 3607 : 0 : goto error_return;
3608 : : }
3609 : : }
3610 : :
3611 : : /* Begin or continue GSSAPI negotiation */
1838 sfrost@snowman.net 3612 :CBC 698 : pollres = pqsecure_open_gss(conn);
3613 [ + + ]: 698 : if (pollres == PGRES_POLLING_OK)
3614 : : {
3615 : : /*
3616 : : * At this point we should have no data already buffered.
3617 : : * If we do, it was received before we performed the GSS
3618 : : * handshake, so it wasn't encrypted and indeed may have
3619 : : * been injected by a man-in-the-middle.
3620 : : */
888 tgl@sss.pgh.pa.us 3621 [ - + ]: 233 : if (conn->inCursor != conn->inEnd)
3622 : : {
516 peter@eisentraut.org 3623 :UBC 0 : libpq_append_conn_error(conn, "received unencrypted data after GSSAPI encryption response");
888 tgl@sss.pgh.pa.us 3624 : 0 : goto error_return;
3625 : : }
3626 : :
3627 : : /* All set for startup packet */
1838 sfrost@snowman.net 3628 :CBC 233 : conn->status = CONNECTION_MADE;
3629 : 233 : return PGRES_POLLING_WRITING;
3630 : : }
398 michael@paquier.xyz 3631 [ - + ]: 465 : else if (pollres == PGRES_POLLING_FAILED)
3632 : : {
6 heikki.linnakangas@i 3633 [ # # ]:UNC 0 : CONNECTION_FAILED();
3634 : : }
3635 : : /* Else, return POLLING_READING or POLLING_WRITING status */
1838 sfrost@snowman.net 3636 :CBC 465 : return pollres;
3637 : : #else /* !ENABLE_GSS */
3638 : : /* unreachable */
3639 : : goto error_return;
3640 : : #endif /* ENABLE_GSS */
3641 : : }
3642 : :
3643 : : /*
3644 : : * Handle authentication exchange: wait for postmaster messages
3645 : : * and respond as necessary.
3646 : : */
8768 bruce@momjian.us 3647 : 12088 : case CONNECTION_AWAITING_RESPONSE:
3648 : : {
3649 : : char beresp;
3650 : : int msgLength;
3651 : : int avail;
3652 : : AuthRequest areq;
3653 : : int res;
3654 : :
3655 : : /*
3656 : : * Scan the message from current point (note that if we find
3657 : : * the message is incomplete, we will return without advancing
3658 : : * inStart, and resume here next time).
3659 : : */
3660 : 12088 : conn->inCursor = conn->inStart;
3661 : :
3662 : : /* Read type byte */
3663 [ + + ]: 12088 : if (pqGetc(&beresp, conn))
3664 : : {
3665 : : /* We'll come back when there is more data */
8857 tgl@sss.pgh.pa.us 3666 : 147 : return PGRES_POLLING_READING;
3667 : : }
3668 : :
3669 : : /*
3670 : : * Validate message type: we expect only an authentication
3671 : : * request, NegotiateProtocolVersion, or an error here.
3672 : : * Anything else probably means it's not Postgres on the other
3673 : : * end at all.
3674 : : */
236 nathan@postgresql.or 3675 [ + + ]:GNC 11941 : if (beresp != PqMsg_AuthenticationRequest &&
3676 [ - + ]: 304 : beresp != PqMsg_ErrorResponse &&
236 nathan@postgresql.or 3677 [ # # ]:UNC 0 : beresp != PqMsg_NegotiateProtocolVersion)
3678 : : {
516 peter@eisentraut.org 3679 :UBC 0 : libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
3680 : : beresp);
7663 tgl@sss.pgh.pa.us 3681 : 0 : goto error_return;
3682 : : }
3683 : :
3684 : : /* Read message length word */
1137 heikki.linnakangas@i 3685 [ - + ]:CBC 11941 : if (pqGetInt(&msgLength, 4, conn))
3686 : : {
3687 : : /* We'll come back when there is more data */
1137 heikki.linnakangas@i 3688 :UBC 0 : return PGRES_POLLING_READING;
3689 : : }
3690 : :
3691 : : /*
3692 : : * Try to validate message length before using it.
3693 : : *
3694 : : * Authentication requests can't be very large, although GSS
3695 : : * auth requests may not be that small. Same for
3696 : : * NegotiateProtocolVersion.
3697 : : *
3698 : : * Errors can be a little larger, but not huge. If we see a
3699 : : * large apparent length in an error, it means we're really
3700 : : * talking to a pre-3.0-protocol server; cope. (Before
3701 : : * version 14, the server also used the old protocol for
3702 : : * errors that happened before processing the startup packet.)
3703 : : */
236 nathan@postgresql.or 3704 [ + + ]:GNC 11941 : if (beresp == PqMsg_AuthenticationRequest &&
3705 [ + - - + ]: 11637 : (msgLength < 8 || msgLength > 2000))
3706 : : {
417 heikki.linnakangas@i 3707 :UBC 0 : libpq_append_conn_error(conn, "received invalid authentication request");
3708 : 0 : goto error_return;
3709 : : }
236 nathan@postgresql.or 3710 [ - + ]:GNC 11941 : if (beresp == PqMsg_NegotiateProtocolVersion &&
236 nathan@postgresql.or 3711 [ # # # # ]:UNC 0 : (msgLength < 8 || msgLength > 2000))
3712 : : {
417 heikki.linnakangas@i 3713 :UBC 0 : libpq_append_conn_error(conn, "received invalid protocol negotiation message");
7663 tgl@sss.pgh.pa.us 3714 : 0 : goto error_return;
3715 : : }
3716 : :
3717 : : #define MAX_ERRLEN 30000
236 nathan@postgresql.or 3718 [ + + ]:GNC 11941 : if (beresp == PqMsg_ErrorResponse &&
3719 [ + - - + ]: 304 : (msgLength < 8 || msgLength > MAX_ERRLEN))
3720 : : {
3721 : : /* Handle error from a pre-3.0 server */
7559 bruce@momjian.us 3722 :UBC 0 : conn->inCursor = conn->inStart + 1; /* reread data */
5648 magnus@hagander.net 3723 [ # # ]: 0 : if (pqGets_append(&conn->errorMessage, conn))
3724 : : {
3725 : : /*
3726 : : * We may not have authenticated the server yet, so
3727 : : * don't let the buffer grow forever.
3728 : : */
417 heikki.linnakangas@i 3729 : 0 : avail = conn->inEnd - conn->inCursor;
3730 [ # # ]: 0 : if (avail > MAX_ERRLEN)
3731 : : {
3732 : 0 : libpq_append_conn_error(conn, "received invalid error message");
3733 : 0 : goto error_return;
3734 : : }
3735 : :
3736 : : /* We'll come back when there is more data */
8768 bruce@momjian.us 3737 : 0 : return PGRES_POLLING_READING;
3738 : : }
3739 : : /* OK, we read the message; mark data consumed */
3740 : 0 : conn->inStart = conn->inCursor;
3741 : :
3742 : : /*
3743 : : * Before 7.2, the postmaster didn't always end its
3744 : : * messages with a newline, so add one if needed to
3745 : : * conform to libpq conventions.
3746 : : */
1137 heikki.linnakangas@i 3747 [ # # ]: 0 : if (conn->errorMessage.len == 0 ||
3748 [ # # ]: 0 : conn->errorMessage.data[conn->errorMessage.len - 1] != '\n')
3749 : : {
3750 : 0 : appendPQExpBufferChar(&conn->errorMessage, '\n');
3751 : : }
3752 : :
8768 bruce@momjian.us 3753 : 0 : goto error_return;
3754 : : }
3755 : : #undef MAX_ERRLEN
3756 : :
3757 : : /*
3758 : : * Can't process if message body isn't all here yet.
3759 : : *
3760 : : * After this check passes, any further EOF during parsing
3761 : : * implies that the server sent a bad/truncated message.
3762 : : * Reading more bytes won't help in that case, so don't return
3763 : : * PGRES_POLLING_READING after this point.
3764 : : */
7663 tgl@sss.pgh.pa.us 3765 :CBC 11941 : msgLength -= 4;
3766 : 11941 : avail = conn->inEnd - conn->inCursor;
3767 [ - + ]: 11941 : if (avail < msgLength)
3768 : : {
3769 : : /*
3770 : : * Before returning, try to enlarge the input buffer if
3771 : : * needed to hold the whole message; see notes in
3772 : : * pqParseInput3.
3773 : : */
5799 tgl@sss.pgh.pa.us 3774 [ # # ]:UBC 0 : if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
3775 : : conn))
7663 3776 : 0 : goto error_return;
3777 : : /* We'll come back when there is more data */
3778 : 0 : return PGRES_POLLING_READING;
3779 : : }
3780 : :
3781 : : /* Handle errors. */
236 nathan@postgresql.or 3782 [ + + ]:GNC 11941 : if (beresp == PqMsg_ErrorResponse)
3783 : : {
1137 heikki.linnakangas@i 3784 [ - + ]:CBC 304 : if (pqGetErrorNotice3(conn, true))
3785 : : {
417 heikki.linnakangas@i 3786 :UBC 0 : libpq_append_conn_error(conn, "received invalid error message");
3787 : 0 : goto error_return;
3788 : : }
3789 : : /* OK, we read the message; mark data consumed */
7663 tgl@sss.pgh.pa.us 3790 :CBC 304 : conn->inStart = conn->inCursor;
3791 : :
3792 : : /*
3793 : : * If error is "cannot connect now", try the next host if
3794 : : * any (but we don't want to consider additional addresses
3795 : : * for this host, nor is there much point in changing SSL
3796 : : * or GSS mode). This is helpful when dealing with
3797 : : * standby servers that might not be in hot-standby state.
3798 : : */
1189 3799 [ + + ]: 304 : if (strcmp(conn->last_sqlstate,
3800 : : ERRCODE_CANNOT_CONNECT_NOW) == 0)
3801 : : {
3802 : 123 : conn->try_next_host = true;
3803 : 11796 : goto keep_going;
3804 : : }
3805 : :
3806 : : /* Check to see if we should mention pgpassfile */
2078 3807 : 181 : pgpassfileWarning(conn);
3808 : :
6 heikki.linnakangas@i 3809 [ + + ]:GNC 181 : CONNECTION_FAILED();
3810 : : }
236 nathan@postgresql.or 3811 [ - + ]: 11637 : else if (beresp == PqMsg_NegotiateProtocolVersion)
3812 : : {
514 peter@eisentraut.org 3813 [ # # ]:UBC 0 : if (pqGetNegotiateProtocolVersion3(conn))
3814 : : {
417 heikki.linnakangas@i 3815 : 0 : libpq_append_conn_error(conn, "received invalid protocol negotiation message");
514 peter@eisentraut.org 3816 : 0 : goto error_return;
3817 : : }
3818 : : /* OK, we read the message; mark data consumed */
3819 : 0 : conn->inStart = conn->inCursor;
3820 : 0 : goto error_return;
3821 : : }
3822 : :
3823 : : /* It is an authentication request. */
4887 tgl@sss.pgh.pa.us 3824 :CBC 11637 : conn->auth_req_received = true;
3825 : :
3826 : : /* Get the type of request. */
8768 bruce@momjian.us 3827 [ - + ]: 11637 : if (pqGetInt((int *) &areq, 4, conn))
3828 : : {
3829 : : /* can't happen because we checked the length already */
417 heikki.linnakangas@i 3830 :UBC 0 : libpq_append_conn_error(conn, "received invalid authentication request");
514 peter@eisentraut.org 3831 : 0 : goto error_return;
3832 : : }
2558 heikki.linnakangas@i 3833 :CBC 11637 : msgLength -= 4;
3834 : :
3835 : : /*
3836 : : * Process the rest of the authentication request message, and
3837 : : * respond to it if necessary.
3838 : : *
3839 : : * Note that conn->pghost must be non-NULL if we are going to
3840 : : * avoid the Kerberos code doing a hostname look-up.
3841 : : */
3842 : 11637 : res = pg_fe_sendauth(areq, msgLength, conn);
3843 : :
3844 : : /* OK, we have processed the message; mark data consumed */
3845 : 11637 : conn->inStart = conn->inCursor;
3846 : :
3847 [ + + ]: 11637 : if (res != STATUS_OK)
8768 bruce@momjian.us 3848 : 33 : goto error_return;
3849 : :
3850 : : /*
3851 : : * Just make sure that any data sent by pg_fe_sendauth is
3852 : : * flushed out. Although this theoretically could block, it
3853 : : * really shouldn't since we don't send large auth responses.
3854 : : */
3855 [ - + ]: 11604 : if (pqFlush(conn))
8768 bruce@momjian.us 3856 :UBC 0 : goto error_return;
3857 : :
8768 bruce@momjian.us 3858 [ + + ]:CBC 11604 : if (areq == AUTH_REQ_OK)
3859 : : {
3860 : : /* We are done with authentication exchange */
3861 : 11420 : conn->status = CONNECTION_AUTH_OK;
3862 : :
3863 : : /*
3864 : : * Set asyncStatus so that PQgetResult will think that
3865 : : * what comes back next is the result of a query. See
3866 : : * below.
3867 : : */
3868 : 11420 : conn->asyncStatus = PGASYNC_BUSY;
3869 : : }
3870 : :
3871 : : /* Look to see if we have more data yet. */
3872 : 11604 : goto keep_going;
3873 : : }
3874 : :
8902 3875 : 11432 : case CONNECTION_AUTH_OK:
3876 : : {
3877 : : /*
3878 : : * Now we expect to hear from the backend. A ReadyForQuery
3879 : : * message indicates that startup is successful, but we might
3880 : : * also get an Error message indicating failure. (Notice
3881 : : * messages indicating nonfatal warnings are also allowed by
3882 : : * the protocol, as are ParameterStatus and BackendKeyData
3883 : : * messages.) Easiest way to handle this is to let
3884 : : * PQgetResult() read the messages. We just have to fake it
3885 : : * out about the state of the connection, by setting
3886 : : * asyncStatus = PGASYNC_BUSY (done above).
3887 : : */
3888 : :
8768 3889 [ + + ]: 11432 : if (PQisBusy(conn))
3890 : 12 : return PGRES_POLLING_READING;
3891 : :
3892 : 11420 : res = PQgetResult(conn);
3893 : :
3894 : : /*
3895 : : * NULL return indicating we have gone to IDLE state is
3896 : : * expected
3897 : : */
3898 [ + + ]: 11420 : if (res)
3899 : : {
3900 [ - + ]: 16 : if (res->resultStatus != PGRES_FATAL_ERROR)
516 peter@eisentraut.org 3901 :UBC 0 : libpq_append_conn_error(conn, "unexpected message from server during startup");
5247 tgl@sss.pgh.pa.us 3902 [ + - ]:CBC 16 : else if (conn->send_appname &&
3903 [ - + - - ]: 16 : (conn->appname || conn->fbappname))
3904 : : {
3905 : : /*
3906 : : * If we tried to send application_name, check to see
3907 : : * if the error is about that --- pre-9.0 servers will
3908 : : * reject it at this stage of the process. If so,
3909 : : * close the connection and retry without sending
3910 : : * application_name. We could possibly get a false
3911 : : * SQLSTATE match here and retry uselessly, but there
3912 : : * seems no great harm in that; we'll just get the
3913 : : * same error again if it's unrelated.
3914 : : */
3915 : : const char *sqlstate;
3916 : :
3917 : 16 : sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
3918 [ + - ]: 16 : if (sqlstate &&
3919 [ - + ]: 16 : strcmp(sqlstate, ERRCODE_APPNAME_UNKNOWN) == 0)
3920 : : {
5247 tgl@sss.pgh.pa.us 3921 :UBC 0 : PQclear(res);
3922 : 0 : conn->send_appname = false;
2078 3923 : 0 : need_new_connection = true;
5247 3924 : 0 : goto keep_going;
3925 : : }
3926 : : }
3927 : :
3928 : : /*
3929 : : * if the resultStatus is FATAL, then conn->errorMessage
3930 : : * already has a copy of the error; needn't copy it back.
3931 : : * But add a newline if it's not there already, since
3932 : : * postmaster error messages may not have one.
3933 : : */
8768 bruce@momjian.us 3934 [ + - ]:CBC 16 : if (conn->errorMessage.len <= 0 ||
3935 [ - + ]: 16 : conn->errorMessage.data[conn->errorMessage.len - 1] != '\n')
8768 bruce@momjian.us 3936 :UBC 0 : appendPQExpBufferChar(&conn->errorMessage, '\n');
8768 bruce@momjian.us 3937 :CBC 16 : PQclear(res);
3938 : 16 : goto error_return;
3939 : : }
3940 : :
3941 : : /* Almost there now ... */
1678 alvherre@alvh.no-ip. 3942 : 11404 : conn->status = CONNECTION_CHECK_TARGET;
3943 : 11404 : goto keep_going;
3944 : : }
3945 : :
3946 : 11404 : case CONNECTION_CHECK_TARGET:
3947 : : {
3948 : : /*
3949 : : * If a read-write, read-only, primary, or standby connection
3950 : : * is required, see if we have one.
3951 : : */
1139 tgl@sss.pgh.pa.us 3952 [ + + ]: 11404 : if (conn->target_server_type == SERVER_TYPE_READ_WRITE ||
3953 [ + + ]: 11399 : conn->target_server_type == SERVER_TYPE_READ_ONLY)
2693 rhaas@postgresql.org 3954 : 4 : {
3955 : : bool read_only_server;
3956 : :
3957 : : /*
3958 : : * If the server didn't report
3959 : : * "default_transaction_read_only" or "in_hot_standby" at
3960 : : * startup, we must determine its state by sending the
3961 : : * query "SHOW transaction_read_only". This GUC exists in
3962 : : * all server versions that support 3.0 protocol.
3963 : : */
1139 tgl@sss.pgh.pa.us 3964 [ + - ]: 10 : if (conn->default_transaction_read_only == PG_BOOL_UNKNOWN ||
3965 [ - + ]: 10 : conn->in_hot_standby == PG_BOOL_UNKNOWN)
3966 : : {
3967 : : /*
3968 : : * We use PQsendQueryContinue so that
3969 : : * conn->errorMessage does not get cleared. We need
3970 : : * to preserve any error messages related to previous
3971 : : * hosts we have tried and failed to connect to.
3972 : : */
1139 tgl@sss.pgh.pa.us 3973 :UBC 0 : conn->status = CONNECTION_OK;
3974 [ # # ]: 0 : if (!PQsendQueryContinue(conn,
3975 : : "SHOW transaction_read_only"))
3976 : 0 : goto error_return;
3977 : : /* We'll return to this state when we have the answer */
3978 : 0 : conn->status = CONNECTION_CHECK_WRITABLE;
3979 : 0 : return PGRES_POLLING_READING;
3980 : : }
3981 : :
3982 : : /* OK, we can make the test */
1139 tgl@sss.pgh.pa.us 3983 :CBC 10 : read_only_server =
3984 [ + - ]: 20 : (conn->default_transaction_read_only == PG_BOOL_YES ||
3985 [ + + ]: 10 : conn->in_hot_standby == PG_BOOL_YES);
3986 : :
3987 [ + + + + ]: 10 : if ((conn->target_server_type == SERVER_TYPE_READ_WRITE) ?
3988 : : read_only_server : !read_only_server)
3989 : : {
3990 : : /* Wrong server state, reject and try the next host */
3991 [ + + ]: 6 : if (conn->target_server_type == SERVER_TYPE_READ_WRITE)
516 peter@eisentraut.org 3992 : 3 : libpq_append_conn_error(conn, "session is read-only");
3993 : : else
3994 : 3 : libpq_append_conn_error(conn, "session is not read-only");
3995 : :
3996 : : /* Close connection politely. */
1139 tgl@sss.pgh.pa.us 3997 : 6 : conn->status = CONNECTION_OK;
3998 : 6 : sendTerminateConn(conn);
3999 : :
4000 : : /*
4001 : : * Try next host if any, but we don't want to consider
4002 : : * additional addresses for this host.
4003 : : */
4004 : 6 : conn->try_next_host = true;
4005 : 6 : goto keep_going;
4006 : : }
4007 : : }
4008 [ + + ]: 11394 : else if (conn->target_server_type == SERVER_TYPE_PRIMARY ||
4009 [ + + ]: 11389 : conn->target_server_type == SERVER_TYPE_STANDBY ||
4010 [ + + ]: 11384 : conn->target_server_type == SERVER_TYPE_PREFER_STANDBY)
4011 : : {
4012 : : /*
4013 : : * If the server didn't report "in_hot_standby" at
4014 : : * startup, we must determine its state by sending the
4015 : : * query "SELECT pg_catalog.pg_is_in_recovery()". Servers
4016 : : * before 9.0 don't have that function, but by the same
4017 : : * token they don't have any standby mode, so we may just
4018 : : * assume the result.
4019 : : */
4020 [ - + ]: 15 : if (conn->sversion < 90000)
1139 tgl@sss.pgh.pa.us 4021 :UBC 0 : conn->in_hot_standby = PG_BOOL_NO;
4022 : :
1139 tgl@sss.pgh.pa.us 4023 [ - + ]:CBC 15 : if (conn->in_hot_standby == PG_BOOL_UNKNOWN)
4024 : : {
4025 : : /*
4026 : : * We use PQsendQueryContinue so that
4027 : : * conn->errorMessage does not get cleared. We need
4028 : : * to preserve any error messages related to previous
4029 : : * hosts we have tried and failed to connect to.
4030 : : */
1139 tgl@sss.pgh.pa.us 4031 :UBC 0 : conn->status = CONNECTION_OK;
4032 [ # # ]: 0 : if (!PQsendQueryContinue(conn,
4033 : : "SELECT pg_catalog.pg_is_in_recovery()"))
4034 : 0 : goto error_return;
4035 : : /* We'll return to this state when we have the answer */
4036 : 0 : conn->status = CONNECTION_CHECK_STANDBY;
4037 : 0 : return PGRES_POLLING_READING;
4038 : : }
4039 : :
4040 : : /* OK, we can make the test */
1139 tgl@sss.pgh.pa.us 4041 [ + + + + ]:CBC 30 : if ((conn->target_server_type == SERVER_TYPE_PRIMARY) ?
4042 : 5 : (conn->in_hot_standby == PG_BOOL_YES) :
4043 : 10 : (conn->in_hot_standby == PG_BOOL_NO))
4044 : : {
4045 : : /* Wrong server state, reject and try the next host */
4046 [ + + ]: 9 : if (conn->target_server_type == SERVER_TYPE_PRIMARY)
516 peter@eisentraut.org 4047 : 3 : libpq_append_conn_error(conn, "server is in hot standby mode");
4048 : : else
4049 : 6 : libpq_append_conn_error(conn, "server is not in hot standby mode");
4050 : :
4051 : : /* Close connection politely. */
1139 tgl@sss.pgh.pa.us 4052 : 9 : conn->status = CONNECTION_OK;
4053 : 9 : sendTerminateConn(conn);
4054 : :
4055 : : /*
4056 : : * Try next host if any, but we don't want to consider
4057 : : * additional addresses for this host.
4058 : : */
4059 : 9 : conn->try_next_host = true;
4060 : 9 : goto keep_going;
4061 : : }
4062 : : }
4063 : :
4064 : : /*
4065 : : * For non cancel requests we can release the address list
4066 : : * now. For cancel requests we never actually resolve
4067 : : * addresses and instead the addrinfo exists for the lifetime
4068 : : * of the connection.
4069 : : */
33 alvherre@alvh.no-ip. 4070 [ + - ]:GNC 11389 : if (!conn->cancelRequest)
4071 : 11389 : release_conn_addrinfo(conn);
4072 : :
4073 : : /*
4074 : : * Contents of conn->errorMessage are no longer interesting
4075 : : * (and it seems some clients expect it to be empty after a
4076 : : * successful connection).
4077 : : */
786 tgl@sss.pgh.pa.us 4078 :CBC 11389 : pqClearConnErrorState(conn);
4079 : :
4080 : : /* We are open for business! */
7660 4081 : 11389 : conn->status = CONNECTION_OK;
4082 : 11389 : return PGRES_POLLING_OK;
4083 : : }
4084 : :
2615 rhaas@postgresql.org 4085 :UBC 0 : case CONNECTION_CONSUME:
4086 : : {
4087 : : /*
4088 : : * This state just makes sure the connection is idle after
4089 : : * we've obtained the result of a SHOW or SELECT query. Once
4090 : : * we're clear, return to CONNECTION_CHECK_TARGET state to
4091 : : * decide what to do next. We must transiently set status =
4092 : : * CONNECTION_OK in order to use the result-consuming
4093 : : * subroutines.
4094 : : */
4095 : 0 : conn->status = CONNECTION_OK;
4096 [ # # ]: 0 : if (!PQconsumeInput(conn))
4097 : 0 : goto error_return;
4098 : :
4099 [ # # ]: 0 : if (PQisBusy(conn))
4100 : : {
4101 : 0 : conn->status = CONNECTION_CONSUME;
4102 : 0 : return PGRES_POLLING_READING;
4103 : : }
4104 : :
4105 : : /* Call PQgetResult() again until we get a NULL result */
4106 : 0 : res = PQgetResult(conn);
4107 [ # # ]: 0 : if (res != NULL)
4108 : : {
4109 : 0 : PQclear(res);
4110 : 0 : conn->status = CONNECTION_CONSUME;
1139 tgl@sss.pgh.pa.us 4111 : 0 : return PGRES_POLLING_READING;
4112 : : }
4113 : :
4114 : 0 : conn->status = CONNECTION_CHECK_TARGET;
4115 : 0 : goto keep_going;
4116 : : }
4117 : :
2693 rhaas@postgresql.org 4118 : 0 : case CONNECTION_CHECK_WRITABLE:
4119 : : {
4120 : : /*
4121 : : * Waiting for result of "SHOW transaction_read_only". We
4122 : : * must transiently set status = CONNECTION_OK in order to use
4123 : : * the result-consuming subroutines.
4124 : : */
4125 : 0 : conn->status = CONNECTION_OK;
4126 [ # # ]: 0 : if (!PQconsumeInput(conn))
4127 : 0 : goto error_return;
4128 : :
4129 [ # # ]: 0 : if (PQisBusy(conn))
4130 : : {
4131 : 0 : conn->status = CONNECTION_CHECK_WRITABLE;
4132 : 0 : return PGRES_POLLING_READING;
4133 : : }
4134 : :
4135 : 0 : res = PQgetResult(conn);
1139 tgl@sss.pgh.pa.us 4136 [ # # # # : 0 : if (res && PQresultStatus(res) == PGRES_TUPLES_OK &&
# # ]
2693 rhaas@postgresql.org 4137 : 0 : PQntuples(res) == 1)
4138 : : {
1139 tgl@sss.pgh.pa.us 4139 : 0 : char *val = PQgetvalue(res, 0, 0);
4140 : :
4141 : : /*
4142 : : * "transaction_read_only = on" proves that at least one
4143 : : * of default_transaction_read_only and in_hot_standby is
4144 : : * on, but we don't actually know which. We don't care
4145 : : * though for the purpose of identifying a read-only
4146 : : * session, so satisfy the CONNECTION_CHECK_TARGET code by
4147 : : * claiming they are both on. On the other hand, if it's
4148 : : * a read-write session, they are certainly both off.
4149 : : */
2693 rhaas@postgresql.org 4150 [ # # ]: 0 : if (strncmp(val, "on", 2) == 0)
4151 : : {
1139 tgl@sss.pgh.pa.us 4152 : 0 : conn->default_transaction_read_only = PG_BOOL_YES;
4153 : 0 : conn->in_hot_standby = PG_BOOL_YES;
4154 : : }
4155 : : else
4156 : : {
4157 : 0 : conn->default_transaction_read_only = PG_BOOL_NO;
4158 : 0 : conn->in_hot_standby = PG_BOOL_NO;
4159 : : }
4160 : 0 : PQclear(res);
4161 : :
4162 : : /* Finish reading messages before continuing */
4163 : 0 : conn->status = CONNECTION_CONSUME;
4164 : 0 : goto keep_going;
4165 : : }
4166 : :
4167 : : /* Something went wrong with "SHOW transaction_read_only". */
651 peter@eisentraut.org 4168 : 0 : PQclear(res);
4169 : :
4170 : : /* Append error report to conn->errorMessage. */
516 4171 : 0 : libpq_append_conn_error(conn, "\"%s\" failed",
4172 : : "SHOW transaction_read_only");
4173 : :
4174 : : /* Close connection politely. */
1139 tgl@sss.pgh.pa.us 4175 : 0 : conn->status = CONNECTION_OK;
4176 : 0 : sendTerminateConn(conn);
4177 : :
4178 : : /* Try next host. */
4179 : 0 : conn->try_next_host = true;
4180 : 0 : goto keep_going;
4181 : : }
4182 : :
4183 : 0 : case CONNECTION_CHECK_STANDBY:
4184 : : {
4185 : : /*
4186 : : * Waiting for result of "SELECT pg_is_in_recovery()". We
4187 : : * must transiently set status = CONNECTION_OK in order to use
4188 : : * the result-consuming subroutines.
4189 : : */
4190 : 0 : conn->status = CONNECTION_OK;
4191 [ # # ]: 0 : if (!PQconsumeInput(conn))
4192 : 0 : goto error_return;
4193 : :
4194 [ # # ]: 0 : if (PQisBusy(conn))
4195 : : {
4196 : 0 : conn->status = CONNECTION_CHECK_STANDBY;
4197 : 0 : return PGRES_POLLING_READING;
4198 : : }
4199 : :
4200 : 0 : res = PQgetResult(conn);
4201 [ # # # # : 0 : if (res && PQresultStatus(res) == PGRES_TUPLES_OK &&
# # ]
4202 : 0 : PQntuples(res) == 1)
4203 : : {
4204 : 0 : char *val = PQgetvalue(res, 0, 0);
4205 : :
4206 [ # # ]: 0 : if (strncmp(val, "t", 1) == 0)
4207 : 0 : conn->in_hot_standby = PG_BOOL_YES;
4208 : : else
4209 : 0 : conn->in_hot_standby = PG_BOOL_NO;
2693 rhaas@postgresql.org 4210 : 0 : PQclear(res);
4211 : :
4212 : : /* Finish reading messages before continuing */
2615 4213 : 0 : conn->status = CONNECTION_CONSUME;
4214 : 0 : goto keep_going;
4215 : : }
4216 : :
4217 : : /* Something went wrong with "SELECT pg_is_in_recovery()". */
651 peter@eisentraut.org 4218 : 0 : PQclear(res);
4219 : :
4220 : : /* Append error report to conn->errorMessage. */
516 4221 : 0 : libpq_append_conn_error(conn, "\"%s\" failed",
4222 : : "SELECT pg_is_in_recovery()");
4223 : :
4224 : : /* Close connection politely. */
2693 rhaas@postgresql.org 4225 : 0 : conn->status = CONNECTION_OK;
4226 : 0 : sendTerminateConn(conn);
4227 : :
4228 : : /* Try next host. */
1139 tgl@sss.pgh.pa.us 4229 : 0 : conn->try_next_host = true;
2078 4230 : 0 : goto keep_going;
4231 : : }
4232 : :
8902 bruce@momjian.us 4233 : 0 : default:
516 peter@eisentraut.org 4234 : 0 : libpq_append_conn_error(conn,
4235 : : "invalid connection state %d, probably indicative of memory corruption",
402 michael@paquier.xyz 4236 : 0 : conn->status);
8902 bruce@momjian.us 4237 : 0 : goto error_return;
4238 : : }
4239 : :
4240 : : /* Unreachable */
4241 : :
8902 bruce@momjian.us 4242 :CBC 685 : error_return:
4243 : :
4244 : : /*
4245 : : * We used to close the socket at this point, but that makes it awkward
4246 : : * for those above us if they wish to remove this socket from their own
4247 : : * records (an fd_set for example). We'll just have this socket closed
4248 : : * when PQfinish is called (which is compulsory even after an error, since
4249 : : * the connection structure must be freed).
4250 : : */
7616 tgl@sss.pgh.pa.us 4251 : 685 : conn->status = CONNECTION_BAD;
8902 bruce@momjian.us 4252 : 685 : return PGRES_POLLING_FAILED;
4253 : : }
4254 : :
4255 : : /*
4256 : : * Initialize the state machine for negotiating encryption
4257 : : */
4258 : : static bool
6 heikki.linnakangas@i 4259 :GNC 12178 : init_allowed_encryption_methods(PGconn *conn)
4260 : : {
4261 [ + + ]: 12178 : if (conn->raddr.addr.ss_family == AF_UNIX)
4262 : : {
4263 : : /* Don't request SSL or GSSAPI over Unix sockets */
4264 : 11516 : conn->allowed_enc_methods &= ~(ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL | ENC_GSSAPI);
4265 : :
4266 : : /*
4267 : : * XXX: we probably should not do this. sslmode=require works
4268 : : * differently
4269 : : */
4270 [ - + ]: 11516 : if (conn->gssencmode[0] == 'r')
4271 : : {
6 heikki.linnakangas@i 4272 :UNC 0 : libpq_append_conn_error(conn,
4273 : : "GSSAPI encryption required but it is not supported over a local socket)");
4274 : 0 : conn->allowed_enc_methods = 0;
4275 : 0 : conn->current_enc_method = ENC_ERROR;
4276 : 0 : return false;
4277 : : }
4278 : :
6 heikki.linnakangas@i 4279 :GNC 11516 : conn->allowed_enc_methods = ENC_PLAINTEXT;
4280 : 11516 : conn->current_enc_method = ENC_PLAINTEXT;
4281 : 11516 : return true;
4282 : : }
4283 : :
4284 : : /* initialize based on sslmode and gssencmode */
4285 : 662 : conn->allowed_enc_methods = 0;
4286 : :
4287 : : #ifdef USE_SSL
4288 : : /* sslmode anything but 'disable', and GSSAPI not required */
4289 [ + + + + ]: 662 : if (conn->sslmode[0] != 'd' && conn->gssencmode[0] != 'r')
4290 : : {
4291 [ + + ]: 472 : if (conn->sslnegotiation[0] == 'p')
4292 : 293 : conn->allowed_enc_methods |= ENC_NEGOTIATED_SSL;
4293 [ + + ]: 179 : else if (conn->sslnegotiation[0] == 'd')
4294 : 93 : conn->allowed_enc_methods |= ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL;
4295 [ + - ]: 86 : else if (conn->sslnegotiation[0] == 'r')
4296 : 86 : conn->allowed_enc_methods |= ENC_DIRECT_SSL;
4297 : : }
4298 : : #endif
4299 : :
4300 : : #ifdef ENABLE_GSS
4301 [ + + ]: 662 : if (conn->gssencmode[0] != 'd')
4302 : 480 : conn->allowed_enc_methods |= ENC_GSSAPI;
4303 : : #endif
4304 : :
4305 [ + + + + : 662 : if ((conn->sslmode[0] == 'd' || conn->sslmode[0] == 'p' || conn->sslmode[0] == 'a') &&
+ + ]
4306 [ + + + + ]: 449 : (conn->gssencmode[0] == 'd' || conn->gssencmode[0] == 'p'))
4307 : : {
4308 : 356 : conn->allowed_enc_methods |= ENC_PLAINTEXT;
4309 : : }
4310 : :
4311 : 662 : return select_next_encryption_method(conn, false);
4312 : : }
4313 : :
4314 : : /*
4315 : : * Out-of-line portion of the ENCRYPTION_NEGOTIATION_FAILED() macro in the
4316 : : * PQconnectPoll state machine.
4317 : : *
4318 : : * Return value:
4319 : : * 0: connection failed and we are out of encryption methods to try. return an error
4320 : : * 1: Retry with next connection method. The TCP connection is still valid and in
4321 : : * known state, so we can proceed with the negotiating next method without
4322 : : * reconnecting.
4323 : : * 2: Disconnect, and retry with next connection method.
4324 : : *
4325 : : * conn->current_enc_method is updated to the next method to try.
4326 : : */
4327 : : #if defined(USE_SSL) || defined(ENABLE_GSS)
4328 : : static int
4329 : 97 : encryption_negotiation_failed(PGconn *conn)
4330 : : {
4331 [ - + ]: 97 : Assert((conn->failed_enc_methods & conn->current_enc_method) == 0);
4332 : 97 : conn->failed_enc_methods |= conn->current_enc_method;
4333 : :
4334 [ + + ]: 97 : if (select_next_encryption_method(conn, true))
4335 : : {
4336 [ - + ]: 83 : if (conn->current_enc_method == ENC_DIRECT_SSL)
6 heikki.linnakangas@i 4337 :UNC 0 : return 2;
4338 : : else
6 heikki.linnakangas@i 4339 :GNC 83 : return 1;
4340 : : }
4341 : : else
4342 : 14 : return 0;
4343 : : }
4344 : : #endif
4345 : :
4346 : : /*
4347 : : * Out-of-line portion of the CONNECTION_FAILED() macro
4348 : : *
4349 : : * Returns true, if we should reconnect and retry with a different encryption
4350 : : * method. conn->current_enc_method is updated to the next method to try.
4351 : : */
4352 : : static bool
4353 : 233 : connection_failed(PGconn *conn)
4354 : : {
4355 [ - + ]: 233 : Assert((conn->failed_enc_methods & conn->current_enc_method) == 0);
4356 : 233 : conn->failed_enc_methods |= conn->current_enc_method;
4357 : :
4358 : : /*
4359 : : * If the server reported an error after the SSL handshake, no point in
4360 : : * retrying with negotiated vs direct SSL.
4361 : : */
4362 [ + + ]: 233 : if ((conn->current_enc_method & (ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL)) != 0 &&
4363 [ + + ]: 77 : conn->ssl_handshake_started)
4364 : : {
4365 : 25 : conn->failed_enc_methods |= (ENC_DIRECT_SSL | ENC_NEGOTIATED_SSL) & conn->allowed_enc_methods;
4366 : : }
4367 : : else
4368 : 208 : conn->failed_enc_methods |= conn->current_enc_method;
4369 : :
4370 : 233 : return select_next_encryption_method(conn, false);
4371 : : }
4372 : :
4373 : : /*
4374 : : * Choose the next encryption method to try. If this is a retry,
4375 : : * conn->failed_enc_methods has already been updated. The function sets
4376 : : * conn->current_enc_method to the next method to try. Returns false if no
4377 : : * encryption methods remain.
4378 : : */
4379 : : static bool
4380 : 992 : select_next_encryption_method(PGconn *conn, bool have_valid_connection)
4381 : : {
4382 : : int remaining_methods;
4383 : :
4384 : : #define SELECT_NEXT_METHOD(method) \
4385 : : do { \
4386 : : if ((remaining_methods & method) != 0) \
4387 : : { \
4388 : : conn->current_enc_method = method; \
4389 : : return true; \
4390 : : } \
4391 : : } while (false)
4392 : :
4393 : 992 : remaining_methods = conn->allowed_enc_methods & ~conn->failed_enc_methods;
4394 : :
4395 : : /*
4396 : : * Try GSSAPI before SSL
4397 : : */
4398 : : #ifdef ENABLE_GSS
4399 [ + + ]: 992 : if ((remaining_methods & ENC_GSSAPI) != 0)
4400 : : {
4401 : : /*
4402 : : * If GSSAPI encryption is enabled, then call pg_GSS_have_cred_cache()
4403 : : * which will return true if we can acquire credentials (and give us a
4404 : : * handle to use in conn->gcred), and then send a packet to the server
4405 : : * asking for GSSAPI Encryption (and skip past SSL negotiation and
4406 : : * regular startup below).
4407 : : */
4408 [ + - ]: 429 : if (!conn->gctx)
4409 : : {
4410 [ + + ]: 429 : if (!pg_GSS_have_cred_cache(&conn->gcred))
4411 : : {
4412 : 196 : conn->allowed_enc_methods &= ~ENC_GSSAPI;
4413 : 196 : remaining_methods &= ~ENC_GSSAPI;
4414 : :
4415 [ - + ]: 196 : if (conn->gssencmode[0] == 'r')
4416 : : {
6 heikki.linnakangas@i 4417 :UNC 0 : libpq_append_conn_error(conn,
4418 : : "GSSAPI encryption required but no credential cache");
4419 : : }
4420 : : }
4421 : : }
4422 : : }
4423 : :
6 heikki.linnakangas@i 4424 [ + + ]:GNC 992 : SELECT_NEXT_METHOD(ENC_GSSAPI);
4425 : : #endif
4426 : :
4427 : : /* With sslmode=allow, try plaintext connection before SSL. */
4428 [ + + ]: 759 : if (conn->sslmode[0] == 'a')
4429 [ + + ]: 104 : SELECT_NEXT_METHOD(ENC_PLAINTEXT);
4430 : :
4431 : : /*
4432 : : * If enabled, try direct SSL. Unless we have a valid TCP connection that
4433 : : * failed negotiating GSSAPI encryption or a plaintext connection in case
4434 : : * of sslmode='allow'; in that case we prefer to reuse the connection with
4435 : : * negotiated SSL, instead of reconnecting to do direct SSL. The point of
4436 : : * direct SSL is to avoid the roundtrip from the negotiation, but
4437 : : * reconnecting would also incur a roundtrip.
4438 : : */
4439 [ + + ]: 702 : if (have_valid_connection)
4440 [ - + ]: 97 : SELECT_NEXT_METHOD(ENC_NEGOTIATED_SSL);
4441 : :
4442 [ + + ]: 702 : SELECT_NEXT_METHOD(ENC_DIRECT_SSL);
4443 [ + + ]: 606 : SELECT_NEXT_METHOD(ENC_NEGOTIATED_SSL);
4444 : :
4445 [ + + ]: 330 : if (conn->sslmode[0] != 'a')
4446 [ + + ]: 315 : SELECT_NEXT_METHOD(ENC_PLAINTEXT);
4447 : :
4448 : : /* No more options */
4449 : 159 : conn->current_enc_method = ENC_ERROR;
4450 : 159 : return false;
4451 : : #undef SELECT_NEXT_METHOD
4452 : : }
4453 : :
4454 : : /*
4455 : : * internal_ping
4456 : : * Determine if a server is running and if we can connect to it.
4457 : : *
4458 : : * The argument is a connection that's been started, but not completed.
4459 : : */
4460 : : static PGPing
4889 bruce@momjian.us 4461 :CBC 281 : internal_ping(PGconn *conn)
4462 : : {
4463 : : /* Say "no attempt" if we never got to PQconnectPoll */
4887 tgl@sss.pgh.pa.us 4464 [ + - - + ]: 281 : if (!conn || !conn->options_valid)
4887 tgl@sss.pgh.pa.us 4465 :UBC 0 : return PQPING_NO_ATTEMPT;
4466 : :
4467 : : /* Attempt to complete the connection */
4887 tgl@sss.pgh.pa.us 4468 [ + + ]:CBC 281 : if (conn->status != CONNECTION_BAD)
70 alvherre@alvh.no-ip. 4469 :GNC 185 : (void) pqConnectDBComplete(conn);
4470 : :
4471 : : /* Definitely OK if we succeeded */
4887 tgl@sss.pgh.pa.us 4472 [ + + ]:CBC 281 : if (conn->status != CONNECTION_BAD)
4473 : 86 : return PQPING_OK;
4474 : :
4475 : : /*
4476 : : * Here begins the interesting part of "ping": determine the cause of the
4477 : : * failure in sufficient detail to decide what to return. We do not want
4478 : : * to report that the server is not up just because we didn't have a valid
4479 : : * password, for example. In fact, any sort of authentication request
4480 : : * implies the server is up. (We need this check since the libpq side of
4481 : : * things might have pulled the plug on the connection before getting an
4482 : : * error as such from the postmaster.)
4483 : : */
4484 [ - + ]: 195 : if (conn->auth_req_received)
4887 tgl@sss.pgh.pa.us 4485 :UBC 0 : return PQPING_OK;
4486 : :
4487 : : /*
4488 : : * If we failed to get any ERROR response from the postmaster, report
4489 : : * PQPING_NO_RESPONSE. This result could be somewhat misleading for a
4490 : : * pre-7.4 server, since it won't send back a SQLSTATE, but those are long
4491 : : * out of support. Another corner case where the server could return a
4492 : : * failure without a SQLSTATE is fork failure, but PQPING_NO_RESPONSE
4493 : : * isn't totally unreasonable for that anyway. We expect that every other
4494 : : * failure case in a modern server will produce a report with a SQLSTATE.
4495 : : *
4496 : : * NOTE: whenever we get around to making libpq generate SQLSTATEs for
4497 : : * client-side errors, we should either not store those into
4498 : : * last_sqlstate, or add an extra flag so we can tell client-side errors
4499 : : * apart from server-side ones.
4500 : : */
4887 tgl@sss.pgh.pa.us 4501 [ + + ]:CBC 195 : if (strlen(conn->last_sqlstate) != 5)
4502 : 96 : return PQPING_NO_RESPONSE;
4503 : :
4504 : : /*
4505 : : * Report PQPING_REJECT if server says it's not accepting connections.
4506 : : */
4887 tgl@sss.pgh.pa.us 4507 [ + - ]:GBC 99 : if (strcmp(conn->last_sqlstate, ERRCODE_CANNOT_CONNECT_NOW) == 0)
4508 : 99 : return PQPING_REJECT;
4509 : :
4510 : : /*
4511 : : * Any other SQLSTATE can be taken to indicate that the server is up.
4512 : : * Presumably it didn't like our username, password, or database name; or
4513 : : * perhaps it had some transient failure, but that should not be taken as
4514 : : * meaning "it's down".
4515 : : */
4887 tgl@sss.pgh.pa.us 4516 :UBC 0 : return PQPING_OK;
4517 : : }
4518 : :
4519 : :
4520 : : /*
4521 : : * pqMakeEmptyPGconn
4522 : : * - create a PGconn data structure with (as yet) no interesting data
4523 : : */
4524 : : PGconn *
70 alvherre@alvh.no-ip. 4525 :GNC 12095 : pqMakeEmptyPGconn(void)
4526 : : {
4527 : : PGconn *conn;
4528 : :
4529 : : #ifdef WIN32
4530 : :
4531 : : /*
4532 : : * Make sure socket support is up and running in this process.
4533 : : *
4534 : : * Note: the Windows documentation says that we should eventually do a
4535 : : * matching WSACleanup() call, but experience suggests that that is at
4536 : : * least as likely to cause problems as fix them. So we don't.
4537 : : */
4538 : : static bool wsastartup_done = false;
4539 : :
4540 : : if (!wsastartup_done)
4541 : : {
4542 : : WSADATA wsaData;
4543 : :
4544 : : if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
4545 : : return NULL;
4546 : : wsastartup_done = true;
4547 : : }
4548 : :
4549 : : /* Forget any earlier error */
4550 : : WSASetLastError(0);
4551 : : #endif /* WIN32 */
4552 : :
7562 tgl@sss.pgh.pa.us 4553 :CBC 12095 : conn = (PGconn *) malloc(sizeof(PGconn));
4554 [ - + ]: 12095 : if (conn == NULL)
7562 tgl@sss.pgh.pa.us 4555 :UBC 0 : return conn;
4556 : :
4557 : : /* Zero all pointers and booleans */
7403 neilc@samurai.com 4558 [ + - + - :CBC 12095 : MemSet(conn, 0, sizeof(PGconn));
+ - - + -
- ]
4559 : :
4560 : : /* install default notice hooks */
7603 tgl@sss.pgh.pa.us 4561 : 12095 : conn->noticeHooks.noticeRec = defaultNoticeReceiver;
4562 : 12095 : conn->noticeHooks.noticeProc = defaultNoticeProcessor;
4563 : :
9475 bruce@momjian.us 4564 : 12095 : conn->status = CONNECTION_BAD;
4565 : 12095 : conn->asyncStatus = PGASYNC_IDLE;
1126 alvherre@alvh.no-ip. 4566 : 12095 : conn->pipelineStatus = PQ_PIPELINE_OFF;
7603 tgl@sss.pgh.pa.us 4567 : 12095 : conn->xactStatus = PQTRANS_IDLE;
6635 4568 : 12095 : conn->options_valid = false;
4569 : 12095 : conn->nonblocking = false;
7616 4570 : 12095 : conn->client_encoding = PG_SQL_ASCII;
6538 4571 : 12095 : conn->std_strings = false; /* unless server says differently */
1139 4572 : 12095 : conn->default_transaction_read_only = PG_BOOL_UNKNOWN;
4573 : 12095 : conn->in_hot_standby = PG_BOOL_UNKNOWN;
384 dgustafsson@postgres 4574 : 12095 : conn->scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
7603 tgl@sss.pgh.pa.us 4575 : 12095 : conn->verbosity = PQERRORS_DEFAULT;
3144 4576 : 12095 : conn->show_context = PQSHOW_CONTEXT_ERRORS;
3651 bruce@momjian.us 4577 : 12095 : conn->sock = PGINVALID_SOCKET;
1110 alvherre@alvh.no-ip. 4578 : 12095 : conn->Pfdebug = NULL;
4579 : :
4580 : : /*
4581 : : * We try to send at least 8K at a time, which is the usual size of pipe
4582 : : * buffers on Unix systems. That way, when we are sending a large amount
4583 : : * of data, we avoid incurring extra kernel context swaps for partial
4584 : : * bufferloads. The output buffer is initially made 16K in size, and we
4585 : : * try to dump it after accumulating 8K.
4586 : : *
4587 : : * With the same goal of minimizing context swaps, the input buffer will
4588 : : * be enlarged anytime it has less than 8K free, so we initially allocate
4589 : : * twice that.
4590 : : */
8993 tgl@sss.pgh.pa.us 4591 : 12095 : conn->inBufSize = 16 * 1024;
9475 bruce@momjian.us 4592 : 12095 : conn->inBuffer = (char *) malloc(conn->inBufSize);
7666 tgl@sss.pgh.pa.us 4593 : 12095 : conn->outBufSize = 16 * 1024;
9475 bruce@momjian.us 4594 : 12095 : conn->outBuffer = (char *) malloc(conn->outBufSize);
4393 tgl@sss.pgh.pa.us 4595 : 12095 : conn->rowBufLen = 32;
4596 : 12095 : conn->rowBuf = (PGdataValue *) malloc(conn->rowBufLen * sizeof(PGdataValue));
8993 4597 : 12095 : initPQExpBuffer(&conn->errorMessage);
4598 : 12095 : initPQExpBuffer(&conn->workBuffer);
4599 : :
4600 [ + - ]: 12095 : if (conn->inBuffer == NULL ||
4601 [ + - ]: 12095 : conn->outBuffer == NULL ||
4393 4602 [ + - ]: 12095 : conn->rowBuf == NULL ||
5618 4603 [ + - + - ]: 12095 : PQExpBufferBroken(&conn->errorMessage) ||
4604 [ + - - + ]: 12095 : PQExpBufferBroken(&conn->workBuffer))
4605 : : {
4606 : : /* out of memory already :-( */
9475 bruce@momjian.us 4607 :UBC 0 : freePGconn(conn);
4608 : 0 : conn = NULL;
4609 : : }
4610 : :
9475 bruce@momjian.us 4611 :CBC 12095 : return conn;
4612 : : }
4613 : :
4614 : : /*
4615 : : * freePGconn
4616 : : * - free an idle (closed) PGconn data structure
4617 : : *
4618 : : * NOTE: this should not overlap any functionality with pqClosePGconn().
4619 : : * Clearing/resetting of transient state belongs there; what we do here is
4620 : : * release data that is to be held for the life of the PGconn structure.
4621 : : * If a value ought to be cleared/freed during PQreset(), do it there not here.
4622 : : */
4623 : : static void
9715 4624 : 11913 : freePGconn(PGconn *conn)
4625 : : {
4626 : : /* let any event procs clean up their state data */
668 peter@eisentraut.org 4627 [ - + ]: 11913 : for (int i = 0; i < conn->nEvents; i++)
4628 : : {
4629 : : PGEventConnDestroy evt;
4630 : :
5688 tgl@sss.pgh.pa.us 4631 :UBC 0 : evt.conn = conn;
4632 : 0 : (void) conn->events[i].proc(PGEVT_CONNDESTROY, &evt,
4633 : 0 : conn->events[i].passThrough);
4634 : 0 : free(conn->events[i].name);
4635 : : }
4636 : :
33 alvherre@alvh.no-ip. 4637 :GNC 11913 : release_conn_addrinfo(conn);
70 4638 : 11913 : pqReleaseConnHosts(conn);
4639 : :
668 peter@eisentraut.org 4640 :CBC 11913 : free(conn->client_encoding_initial);
4641 : 11913 : free(conn->events);
4642 : 11913 : free(conn->pghost);
4643 : 11913 : free(conn->pghostaddr);
4644 : 11913 : free(conn->pgport);
4645 : 11913 : free(conn->connect_timeout);
4646 : 11913 : free(conn->pgtcp_user_timeout);
4647 : 11913 : free(conn->pgoptions);
4648 : 11913 : free(conn->appname);
4649 : 11913 : free(conn->fbappname);
4650 : 11913 : free(conn->dbName);
4651 : 11913 : free(conn->replication);
4652 : 11913 : free(conn->pguser);
9490 scrappy@hub.org 4653 [ + + ]: 11913 : if (conn->pgpass)
4654 : : {
1683 peter@eisentraut.org 4655 : 148 : explicit_bzero(conn->pgpass, strlen(conn->pgpass));
9490 scrappy@hub.org 4656 : 148 : free(conn->pgpass);
4657 : : }
668 peter@eisentraut.org 4658 : 11913 : free(conn->pgpassfile);
4659 : 11913 : free(conn->channel_binding);
4660 : 11913 : free(conn->keepalives);
4661 : 11913 : free(conn->keepalives_idle);
4662 : 11913 : free(conn->keepalives_interval);
4663 : 11913 : free(conn->keepalives_count);
4664 : 11913 : free(conn->sslmode);
6 heikki.linnakangas@i 4665 :GNC 11913 : free(conn->sslnegotiation);
668 peter@eisentraut.org 4666 :CBC 11913 : free(conn->sslcert);
4667 : 11913 : free(conn->sslkey);
1577 tgl@sss.pgh.pa.us 4668 [ + + ]: 11913 : if (conn->sslpassword)
4669 : : {
1424 michael@paquier.xyz 4670 : 3 : explicit_bzero(conn->sslpassword, strlen(conn->sslpassword));
1577 tgl@sss.pgh.pa.us 4671 : 3 : free(conn->sslpassword);
4672 : : }
387 michael@paquier.xyz 4673 : 11913 : free(conn->sslcertmode);
668 peter@eisentraut.org 4674 : 11913 : free(conn->sslrootcert);
4675 : 11913 : free(conn->sslcrl);
4676 : 11913 : free(conn->sslcrldir);
4677 : 11913 : free(conn->sslcompression);
4678 : 11913 : free(conn->sslsni);
4679 : 11913 : free(conn->requirepeer);
397 michael@paquier.xyz 4680 : 11913 : free(conn->require_auth);
668 peter@eisentraut.org 4681 : 11913 : free(conn->ssl_min_protocol_version);
4682 : 11913 : free(conn->ssl_max_protocol_version);
4683 : 11913 : free(conn->gssencmode);
4684 : 11913 : free(conn->krbsrvname);
4685 : 11913 : free(conn->gsslib);
329 tgl@sss.pgh.pa.us 4686 : 11913 : free(conn->gssdelegation);
668 peter@eisentraut.org 4687 : 11913 : free(conn->connip);
4688 : : /* Note that conn->Pfdebug is not ours to close or free */
4689 : 11913 : free(conn->write_err_msg);
4690 : 11913 : free(conn->inBuffer);
4691 : 11913 : free(conn->outBuffer);
4692 : 11913 : free(conn->rowBuf);
4693 : 11913 : free(conn->target_session_attrs);
382 dgustafsson@postgres 4694 : 11913 : free(conn->load_balance_hosts);
8993 tgl@sss.pgh.pa.us 4695 : 11913 : termPQExpBuffer(&conn->errorMessage);
4696 : 11913 : termPQExpBuffer(&conn->workBuffer);
4697 : :
9716 bruce@momjian.us 4698 : 11913 : free(conn);
10141 scrappy@hub.org 4699 : 11913 : }
4700 : :
4701 : : /*
4702 : : * pqReleaseConnHosts
4703 : : * - Free the host list in the PGconn.
4704 : : */
4705 : : void
70 alvherre@alvh.no-ip. 4706 :GNC 11918 : pqReleaseConnHosts(PGconn *conn)
4707 : : {
4708 [ + + ]: 11918 : if (conn->connhost)
4709 : : {
4710 [ + + ]: 23965 : for (int i = 0; i < conn->nconnhost; ++i)
4711 : : {
4712 : 12049 : free(conn->connhost[i].host);
4713 : 12049 : free(conn->connhost[i].hostaddr);
4714 : 12049 : free(conn->connhost[i].port);
4715 [ + + ]: 12049 : if (conn->connhost[i].password != NULL)
4716 : : {
4717 : 9 : explicit_bzero(conn->connhost[i].password,
4718 : 9 : strlen(conn->connhost[i].password));
4719 : 9 : free(conn->connhost[i].password);
4720 : : }
4721 : : }
4722 : 11916 : free(conn->connhost);
4723 : : }
4724 : 11918 : }
4725 : :
4726 : : /*
4727 : : * store_conn_addrinfo
4728 : : * - copy addrinfo to PGconn object
4729 : : *
4730 : : * Copies the addrinfos from addrlist to the PGconn object such that the
4731 : : * addrinfos can be manipulated by libpq. Returns a positive integer on
4732 : : * failure, otherwise zero.
4733 : : */
4734 : : static int
382 dgustafsson@postgres 4735 :CBC 12091 : store_conn_addrinfo(PGconn *conn, struct addrinfo *addrlist)
4736 : : {
4737 : 12091 : struct addrinfo *ai = addrlist;
4738 : :
4739 : 12091 : conn->whichaddr = 0;
4740 : :
4741 : 12091 : conn->naddr = 0;
4742 [ + + ]: 24296 : while (ai)
4743 : : {
4744 : 12205 : ai = ai->ai_next;
4745 : 12205 : conn->naddr++;
4746 : : }
4747 : :
4748 : 12091 : conn->addr = calloc(conn->naddr, sizeof(AddrInfo));
4749 [ - + ]: 12091 : if (conn->addr == NULL)
4750 : : {
382 dgustafsson@postgres 4751 :UBC 0 : libpq_append_conn_error(conn, "out of memory");
4752 : 0 : return 1;
4753 : : }
4754 : :
382 dgustafsson@postgres 4755 :CBC 12091 : ai = addrlist;
4756 [ + + ]: 24296 : for (int i = 0; i < conn->naddr; i++)
4757 : : {
4758 : 12205 : conn->addr[i].family = ai->ai_family;
4759 : :
4760 : 12205 : memcpy(&conn->addr[i].addr.addr, ai->ai_addr,
4761 : 12205 : ai->ai_addrlen);
4762 : 12205 : conn->addr[i].addr.salen = ai->ai_addrlen;
4763 : 12205 : ai = ai->ai_next;
4764 : : }
4765 : :
4766 : 12091 : return 0;
4767 : : }
4768 : :
4769 : : /*
4770 : : * release_conn_addrinfo
4771 : : * - Free any addrinfo list in the PGconn.
4772 : : */
4773 : : static void
2061 tgl@sss.pgh.pa.us 4774 : 47304 : release_conn_addrinfo(PGconn *conn)
4775 : : {
382 dgustafsson@postgres 4776 [ + + ]: 47304 : if (conn->addr)
4777 : : {
4778 : 12090 : free(conn->addr);
4779 : 12090 : conn->addr = NULL;
4780 : : }
2693 rhaas@postgresql.org 4781 : 47304 : }
4782 : :
4783 : : /*
4784 : : * sendTerminateConn
4785 : : * - Send a terminate message to backend.
4786 : : */
4787 : : static void
4788 : 11929 : sendTerminateConn(PGconn *conn)
4789 : : {
4790 : : /*
4791 : : * The Postgres cancellation protocol does not have a notion of a
4792 : : * Terminate message, so don't send one.
4793 : : */
33 alvherre@alvh.no-ip. 4794 [ + + ]:GNC 11929 : if (conn->cancelRequest)
4795 : 6 : return;
4796 : :
4797 : : /*
4798 : : * Note that the protocol doesn't allow us to send Terminate messages
4799 : : * during the startup phase.
4800 : : */
3651 bruce@momjian.us 4801 [ + + + + ]:CBC 11923 : if (conn->sock != PGINVALID_SOCKET && conn->status == CONNECTION_OK)
4802 : : {
4803 : : /*
4804 : : * Try to send "close connection" message to backend. Ignore any
4805 : : * error.
4806 : : */
236 nathan@postgresql.or 4807 :GNC 11146 : pqPutMsgStart(PqMsg_Terminate, conn);
7666 tgl@sss.pgh.pa.us 4808 :CBC 11146 : pqPutMsgEnd(conn);
3697 sfrost@snowman.net 4809 : 11146 : (void) pqFlush(conn);
4810 : : }
2693 rhaas@postgresql.org 4811 :ECB (9894) : }
4812 : :
4813 : : /*
4814 : : * pqClosePGconn
4815 : : * - properly close a connection to the backend
4816 : : *
4817 : : * This should reset or release all transient state, but NOT the connection
4818 : : * parameters. On exit, the PGconn should be in condition to start a fresh
4819 : : * connection with the same parameters (see PQreset()).
4820 : : */
4821 : : void
70 alvherre@alvh.no-ip. 4822 :GNC 11914 : pqClosePGconn(PGconn *conn)
4823 : : {
4824 : : /*
4825 : : * If possible, send Terminate message to close the connection politely.
4826 : : */
2693 rhaas@postgresql.org 4827 :CBC 11914 : sendTerminateConn(conn);
4828 : :
4829 : : /*
4830 : : * Must reset the blocking status so a possible reconnect will work.
4831 : : *
4832 : : * Don't call PQsetnonblocking() because it will fail if it's unable to
4833 : : * flush the connection.
4834 : : */
2433 peter_e@gmx.net 4835 : 11914 : conn->nonblocking = false;
4836 : :
4837 : : /*
4838 : : * Close the connection, reset all transient state, flush I/O buffers.
4839 : : * Note that this includes clearing conn's error state; we're no longer
4840 : : * interested in any failures associated with the old connection, and we
4841 : : * want a clean slate for any new connection attempt.
4842 : : */
3076 tgl@sss.pgh.pa.us 4843 : 11914 : pqDropConnection(conn, true);
2489 4844 : 11914 : conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just absent */
9475 bruce@momjian.us 4845 : 11914 : conn->asyncStatus = PGASYNC_IDLE;
2078 tgl@sss.pgh.pa.us 4846 : 11914 : conn->xactStatus = PQTRANS_IDLE;
1126 alvherre@alvh.no-ip. 4847 : 11914 : conn->pipelineStatus = PQ_PIPELINE_OFF;
4393 tgl@sss.pgh.pa.us 4848 : 11914 : pqClearAsyncResult(conn); /* deallocate result */
786 4849 : 11914 : pqClearConnErrorState(conn);
4850 : :
4851 : : /*
4852 : : * Release addrinfo, but since cancel requests never change their addrinfo
4853 : : * we don't do that. Otherwise we would have to rebuild it during a
4854 : : * PQcancelReset.
4855 : : */
33 alvherre@alvh.no-ip. 4856 [ + + ]:GNC 11914 : if (!conn->cancelRequest)
4857 : 11908 : release_conn_addrinfo(conn);
4858 : :
4859 : : /* Reset all state obtained from server, too */
2078 tgl@sss.pgh.pa.us 4860 :CBC 11914 : pqDropServerData(conn);
10141 scrappy@hub.org 4861 : 11914 : }
4862 : :
4863 : : /*
4864 : : * PQfinish: properly close a connection to the backend. Also frees
4865 : : * the PGconn data structure so it shouldn't be re-used after this.
4866 : : */
4867 : : void
9715 bruce@momjian.us 4868 : 11913 : PQfinish(PGconn *conn)
4869 : : {
9380 4870 [ + - ]: 11913 : if (conn)
4871 : : {
70 alvherre@alvh.no-ip. 4872 :GNC 11913 : pqClosePGconn(conn);
9716 bruce@momjian.us 4873 :CBC 11913 : freePGconn(conn);
4874 : : }
10141 scrappy@hub.org 4875 : 11913 : }
4876 : :
4877 : : /*
4878 : : * PQreset: resets the connection to the backend by closing the
4879 : : * existing connection and creating a new one.
4880 : : */
4881 : : void
9715 bruce@momjian.us 4882 :UBC 0 : PQreset(PGconn *conn)
4883 : : {
9380 4884 [ # # ]: 0 : if (conn)
4885 : : {
70 alvherre@alvh.no-ip. 4886 :UNC 0 : pqClosePGconn(conn);
4887 : :
4888 [ # # # # ]: 0 : if (pqConnectDBStart(conn) && pqConnectDBComplete(conn))
4889 : : {
4890 : : /*
4891 : : * Notify event procs of successful reset.
4892 : : */
4893 : : int i;
4894 : :
5688 tgl@sss.pgh.pa.us 4895 [ # # ]:UBC 0 : for (i = 0; i < conn->nEvents; i++)
4896 : : {
4897 : : PGEventConnReset evt;
4898 : :
4899 : 0 : evt.conn = conn;
786 4900 : 0 : (void) conn->events[i].proc(PGEVT_CONNRESET, &evt,
4901 : 0 : conn->events[i].passThrough);
4902 : : }
4903 : : }
4904 : : }
8902 bruce@momjian.us 4905 : 0 : }
4906 : :
4907 : :
4908 : : /*
4909 : : * PQresetStart:
4910 : : * resets the connection to the backend
4911 : : * closes the existing connection and makes a new one
4912 : : * Returns 1 on success, 0 on failure.
4913 : : */
4914 : : int
4915 : 0 : PQresetStart(PGconn *conn)
4916 : : {
4917 [ # # ]: 0 : if (conn)
4918 : : {
70 alvherre@alvh.no-ip. 4919 :UNC 0 : pqClosePGconn(conn);
4920 : :
4921 : 0 : return pqConnectDBStart(conn);
4922 : : }
4923 : :
8857 tgl@sss.pgh.pa.us 4924 :UBC 0 : return 0;
4925 : : }
4926 : :
4927 : :
4928 : : /*
4929 : : * PQresetPoll:
4930 : : * resets the connection to the backend
4931 : : * closes the existing connection and makes a new one
4932 : : */
4933 : : PostgresPollingStatusType
8902 bruce@momjian.us 4934 : 0 : PQresetPoll(PGconn *conn)
4935 : : {
4936 [ # # ]: 0 : if (conn)
4937 : : {
5688 tgl@sss.pgh.pa.us 4938 : 0 : PostgresPollingStatusType status = PQconnectPoll(conn);
4939 : :
4940 [ # # ]: 0 : if (status == PGRES_POLLING_OK)
4941 : : {
4942 : : /*
4943 : : * Notify event procs of successful reset.
4944 : : */
4945 : : int i;
4946 : :
4947 [ # # ]: 0 : for (i = 0; i < conn->nEvents; i++)
4948 : : {
4949 : : PGEventConnReset evt;
4950 : :
4951 : 0 : evt.conn = conn;
786 4952 : 0 : (void) conn->events[i].proc(PGEVT_CONNRESET, &evt,
4953 : 0 : conn->events[i].passThrough);
4954 : : }
4955 : : }
4956 : :
5688 4957 : 0 : return status;
4958 : : }
4959 : :
8902 bruce@momjian.us 4960 : 0 : return PGRES_POLLING_FAILED;
4961 : : }
4962 : :
4963 : : /*
4964 : : * pqPacketSend() -- convenience routine to send a message to server.
4965 : : *
4966 : : * pack_type: the single-byte message type code. (Pass zero for startup
4967 : : * packets, which have no message type code.)
4968 : : *
4969 : : * buf, buf_len: contents of message. The given length includes only what
4970 : : * is in buf; the message type and message length fields are added here.
4971 : : *
4972 : : * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
4973 : : * SIDE_EFFECTS: may block.
4974 : : */
4975 : : int
7668 tgl@sss.pgh.pa.us 4976 :CBC 12336 : pqPacketSend(PGconn *conn, char pack_type,
4977 : : const void *buf, size_t buf_len)
4978 : : {
4979 : : /* Start the message. */
1137 heikki.linnakangas@i 4980 [ - + ]: 12336 : if (pqPutMsgStart(pack_type, conn))
9575 scrappy@hub.org 4981 :UBC 0 : return STATUS_ERROR;
4982 : :
4983 : : /* Send the message body. */
7668 tgl@sss.pgh.pa.us 4984 [ - + ]:CBC 12336 : if (pqPutnchar(buf, buf_len, conn))
9575 scrappy@hub.org 4985 :UBC 0 : return STATUS_ERROR;
4986 : :
4987 : : /* Finish the message. */
7666 tgl@sss.pgh.pa.us 4988 [ - + ]:CBC 12336 : if (pqPutMsgEnd(conn))
7666 tgl@sss.pgh.pa.us 4989 :UBC 0 : return STATUS_ERROR;
4990 : :
4991 : : /* Flush to ensure backend gets it. */
9475 bruce@momjian.us 4992 [ - + ]:CBC 12336 : if (pqFlush(conn))
9475 bruce@momjian.us 4993 :UBC 0 : return STATUS_ERROR;
4994 : :
9575 scrappy@hub.org 4995 :CBC 12336 : return STATUS_OK;
4996 : : }
4997 : :
4998 : : #ifdef USE_LDAP
4999 : :
5000 : : #define LDAP_URL "ldap://"
5001 : : #define LDAP_DEF_PORT 389
5002 : : #define PGLDAP_TIMEOUT 2
5003 : :
5004 : : #define ld_is_sp_tab(x) ((x) == ' ' || (x) == '\t')
5005 : : #define ld_is_nl_cr(x) ((x) == '\r' || (x) == '\n')
5006 : :
5007 : :
5008 : : /*
5009 : : * ldapServiceLookup
5010 : : *
5011 : : * Search the LDAP URL passed as first argument, treat the result as a
5012 : : * string of connection options that are parsed and added to the array of
5013 : : * options passed as second argument.
5014 : : *
5015 : : * LDAP URLs must conform to RFC 1959 without escape sequences.
5016 : : * ldap://host:port/dn?attributes?scope?filter?extensions
5017 : : *
5018 : : * Returns
5019 : : * 0 if the lookup was successful,
5020 : : * 1 if the connection to the LDAP server could be established but
5021 : : * the search was unsuccessful,
5022 : : * 2 if a connection could not be established, and
5023 : : * 3 if a fatal error occurred.
5024 : : *
5025 : : * An error message is appended to *errorMessage for return codes 1 and 3.
5026 : : */
5027 : : static int
6471 bruce@momjian.us 5028 : 1 : ldapServiceLookup(const char *purl, PQconninfoOption *options,
5029 : : PQExpBuffer errorMessage)
5030 : : {
6402 5031 : 1 : int port = LDAP_DEF_PORT,
5032 : : scope,
5033 : : rc,
5034 : : size,
5035 : : state,
5036 : : oldstate,
5037 : : i;
5038 : : #ifndef WIN32
5039 : : int msgid;
5040 : : #endif
5041 : : bool found_keyword;
5042 : : char *url,
5043 : : *hostname,
5044 : : *portstr,
5045 : : *endptr,
5046 : : *dn,
5047 : : *scopestr,
5048 : : *filter,
5049 : : *result,
5050 : : *p,
5051 : 1 : *p1 = NULL,
5052 : 1 : *optname = NULL,
5053 : 1 : *optval = NULL;
6471 5054 : 1 : char *attrs[2] = {NULL, NULL};
5055 : 1 : LDAP *ld = NULL;
5056 : : LDAPMessage *res,
5057 : : *entry;
5058 : : struct berval **values;
5059 : 1 : LDAP_TIMEVAL time = {PGLDAP_TIMEOUT, 0};
5060 : :
5061 [ - + ]: 1 : if ((url = strdup(purl)) == NULL)
5062 : : {
516 peter@eisentraut.org 5063 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
6471 bruce@momjian.us 5064 : 0 : return 3;
5065 : : }
5066 : :
5067 : : /*
5068 : : * Parse URL components, check for correctness. Basically, url has '\0'
5069 : : * placed at component boundaries and variables are pointed at each
5070 : : * component.
5071 : : */
5072 : :
6421 tgl@sss.pgh.pa.us 5073 [ - + ]:CBC 1 : if (pg_strncasecmp(url, LDAP_URL, strlen(LDAP_URL)) != 0)
5074 : : {
516 peter@eisentraut.org 5075 :UBC 0 : libpq_append_error(errorMessage,
5076 : : "invalid LDAP URL \"%s\": scheme must be ldap://", purl);
6471 bruce@momjian.us 5077 : 0 : free(url);
5078 : 0 : return 3;
5079 : : }
5080 : :
5081 : : /* hostname */
6471 bruce@momjian.us 5082 :CBC 1 : hostname = url + strlen(LDAP_URL);
6402 5083 [ - + ]: 1 : if (*hostname == '/') /* no hostname? */
4866 bruce@momjian.us 5084 :UBC 0 : hostname = DefaultHost; /* the default */
5085 : :
5086 : : /* dn, "distinguished name" */
6402 bruce@momjian.us 5087 :CBC 1 : p = strchr(url + strlen(LDAP_URL), '/');
6471 5088 [ + - + - : 1 : if (p == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
- + ]
5089 : : {
516 peter@eisentraut.org 5090 :UBC 0 : libpq_append_error(errorMessage,
5091 : : "invalid LDAP URL \"%s\": missing distinguished name",
5092 : : purl);
6471 bruce@momjian.us 5093 : 0 : free(url);
5094 : 0 : return 3;
5095 : : }
6402 bruce@momjian.us 5096 :CBC 1 : *p = '\0'; /* terminate hostname */
6471 5097 : 1 : dn = p + 1;
5098 : :
5099 : : /* attribute */
5100 [ + - + - : 1 : if ((p = strchr(dn, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
- + ]
5101 : : {
516 peter@eisentraut.org 5102 :UBC 0 : libpq_append_error(errorMessage,
5103 : : "invalid LDAP URL \"%s\": must have exactly one attribute",
5104 : : purl);
6471 bruce@momjian.us 5105 : 0 : free(url);
5106 : 0 : return 3;
5107 : : }
6471 bruce@momjian.us 5108 :CBC 1 : *p = '\0';
5109 : 1 : attrs[0] = p + 1;
5110 : :
5111 : : /* scope */
5112 [ + - + - : 1 : if ((p = strchr(attrs[0], '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
- + ]
5113 : : {
516 peter@eisentraut.org 5114 :UBC 0 : libpq_append_error(errorMessage,
5115 : : "invalid LDAP URL \"%s\": must have search scope (base/one/sub)",
5116 : : purl);
6471 bruce@momjian.us 5117 : 0 : free(url);
5118 : 0 : return 3;
5119 : : }
6471 bruce@momjian.us 5120 :CBC 1 : *p = '\0';
5121 : 1 : scopestr = p + 1;
5122 : :
5123 : : /* filter */
5124 [ + - + - : 1 : if ((p = strchr(scopestr, '?')) == NULL || *(p + 1) == '\0' || *(p + 1) == '?')
- + ]
5125 : : {
516 peter@eisentraut.org 5126 :UBC 0 : libpq_append_error(errorMessage,
5127 : : "invalid LDAP URL \"%s\": no filter",
5128 : : purl);
6471 bruce@momjian.us 5129 : 0 : free(url);
5130 : 0 : return 3;
5131 : : }
6471 bruce@momjian.us 5132 :CBC 1 : *p = '\0';
5133 : 1 : filter = p + 1;
5134 [ - + ]: 1 : if ((p = strchr(filter, '?')) != NULL)
6471 bruce@momjian.us 5135 :UBC 0 : *p = '\0';
5136 : :
5137 : : /* port number? */
6471 bruce@momjian.us 5138 [ + - ]:CBC 1 : if ((p1 = strchr(hostname, ':')) != NULL)
5139 : : {
5140 : : long lport;
5141 : :
5142 : 1 : *p1 = '\0';
5143 : 1 : portstr = p1 + 1;
5144 : 1 : errno = 0;
5145 : 1 : lport = strtol(portstr, &endptr, 10);
5146 [ + - + - : 1 : if (*portstr == '\0' || *endptr != '\0' || errno || lport < 0 || lport > 65535)
+ - + - -
+ ]
5147 : : {
516 peter@eisentraut.org 5148 :UBC 0 : libpq_append_error(errorMessage,
5149 : : "invalid LDAP URL \"%s\": invalid port number",
5150 : : purl);
6471 bruce@momjian.us 5151 : 0 : free(url);
5152 : 0 : return 3;
5153 : : }
6471 bruce@momjian.us 5154 :CBC 1 : port = (int) lport;
5155 : : }
5156 : :
5157 : : /* Allow only one attribute */
5158 [ - + ]: 1 : if (strchr(attrs[0], ',') != NULL)
5159 : : {
516 peter@eisentraut.org 5160 :UBC 0 : libpq_append_error(errorMessage,
5161 : : "invalid LDAP URL \"%s\": must have exactly one attribute",
5162 : : purl);
6471 bruce@momjian.us 5163 : 0 : free(url);
5164 : 0 : return 3;
5165 : : }
5166 : :
5167 : : /* set scope */
6421 tgl@sss.pgh.pa.us 5168 [ - + ]:CBC 1 : if (pg_strcasecmp(scopestr, "base") == 0)
6471 bruce@momjian.us 5169 :UBC 0 : scope = LDAP_SCOPE_BASE;
6421 tgl@sss.pgh.pa.us 5170 [ + - ]:CBC 1 : else if (pg_strcasecmp(scopestr, "one") == 0)
6471 bruce@momjian.us 5171 : 1 : scope = LDAP_SCOPE_ONELEVEL;
6421 tgl@sss.pgh.pa.us 5172 [ # # ]:UBC 0 : else if (pg_strcasecmp(scopestr, "sub") == 0)
6471 bruce@momjian.us 5173 : 0 : scope = LDAP_SCOPE_SUBTREE;
5174 : : else
5175 : : {
516 peter@eisentraut.org 5176 : 0 : libpq_append_error(errorMessage,
5177 : : "invalid LDAP URL \"%s\": must have search scope (base/one/sub)",
5178 : : purl);
6471 bruce@momjian.us 5179 : 0 : free(url);
5180 : 0 : return 3;
5181 : : }
5182 : :
5183 : : /* initialize LDAP structure */
6471 bruce@momjian.us 5184 [ - + ]:CBC 1 : if ((ld = ldap_init(hostname, port)) == NULL)
5185 : : {
516 peter@eisentraut.org 5186 :UBC 0 : libpq_append_error(errorMessage, "could not create LDAP structure");
6471 bruce@momjian.us 5187 : 0 : free(url);
5188 : 0 : return 3;
5189 : : }
5190 : :
5191 : : /*
5192 : : * Perform an explicit anonymous bind.
5193 : : *
5194 : : * LDAP does not require that an anonymous bind is performed explicitly,
5195 : : * but we want to distinguish between the case where LDAP bind does not
5196 : : * succeed within PGLDAP_TIMEOUT seconds (return 2 to continue parsing the
5197 : : * service control file) and the case where querying the LDAP server fails
5198 : : * (return 1 to end parsing).
5199 : : *
5200 : : * Unfortunately there is no way of setting a timeout that works for both
5201 : : * Windows and OpenLDAP.
5202 : : */
5203 : : #ifdef WIN32
5204 : : /* the nonstandard ldap_connect function performs an anonymous bind */
5205 : : if (ldap_connect(ld, &time) != LDAP_SUCCESS)
5206 : : {
5207 : : /* error or timeout in ldap_connect */
5208 : : free(url);
5209 : : ldap_unbind(ld);
5210 : : return 2;
5211 : : }
5212 : : #else /* !WIN32 */
5213 : : /* in OpenLDAP, use the LDAP_OPT_NETWORK_TIMEOUT option */
3651 magnus@hagander.net 5214 [ - + ]:CBC 1 : if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &time) != LDAP_SUCCESS)
5215 : : {
3651 magnus@hagander.net 5216 :UBC 0 : free(url);
5217 : 0 : ldap_unbind(ld);
5218 : 0 : return 3;
5219 : : }
5220 : :
5221 : : /* anonymous bind */
6471 bruce@momjian.us 5222 [ + - ]:CBC 1 : if ((msgid = ldap_simple_bind(ld, NULL, NULL)) == -1)
5223 : : {
5224 : : /* error or network timeout */
5225 : 1 : free(url);
5226 : 1 : ldap_unbind(ld);
5227 : 1 : return 2;
5228 : : }
5229 : :
5230 : : /* wait some time for the connection to succeed */
6471 bruce@momjian.us 5231 :UBC 0 : res = NULL;
5232 [ # # ]: 0 : if ((rc = ldap_result(ld, msgid, LDAP_MSG_ALL, &time, &res)) == -1 ||
5233 [ # # ]: 0 : res == NULL)
5234 : : {
5235 : : /* error or timeout */
5236 [ # # ]: 0 : if (res != NULL)
5237 : 0 : ldap_msgfree(res);
5238 : 0 : free(url);
5239 : 0 : ldap_unbind(ld);
5240 : 0 : return 2;
5241 : : }
5242 : 0 : ldap_msgfree(res);
5243 : :
5244 : : /* reset timeout */
3651 magnus@hagander.net 5245 : 0 : time.tv_sec = -1;
5246 [ # # ]: 0 : if (ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &time) != LDAP_SUCCESS)
5247 : : {
5248 : 0 : free(url);
5249 : 0 : ldap_unbind(ld);
5250 : 0 : return 3;
5251 : : }
5252 : : #endif /* WIN32 */
5253 : :
5254 : : /* search */
6471 bruce@momjian.us 5255 : 0 : res = NULL;
5256 [ # # ]: 0 : if ((rc = ldap_search_st(ld, dn, scope, filter, attrs, 0, &time, &res))
5257 : : != LDAP_SUCCESS)
5258 : : {
5259 [ # # ]: 0 : if (res != NULL)
5260 : 0 : ldap_msgfree(res);
516 peter@eisentraut.org 5261 : 0 : libpq_append_error(errorMessage, "lookup on LDAP server failed: %s", ldap_err2string(rc));
6471 bruce@momjian.us 5262 : 0 : ldap_unbind(ld);
5263 : 0 : free(url);
5264 : 0 : return 1;
5265 : : }
5266 : :
5267 : : /* complain if there was not exactly one result */
5268 [ # # ]: 0 : if ((rc = ldap_count_entries(ld, res)) != 1)
5269 : : {
516 peter@eisentraut.org 5270 [ # # ]: 0 : if (rc > 1)
5271 : 0 : libpq_append_error(errorMessage, "more than one entry found on LDAP lookup");
5272 : : else
5273 : 0 : libpq_append_error(errorMessage, "no entry found on LDAP lookup");
6471 bruce@momjian.us 5274 : 0 : ldap_msgfree(res);
5275 : 0 : ldap_unbind(ld);
5276 : 0 : free(url);
5277 : 0 : return 1;
5278 : : }
5279 : :
5280 : : /* get entry */
5281 [ # # ]: 0 : if ((entry = ldap_first_entry(ld, res)) == NULL)
5282 : : {
5283 : : /* should never happen */
516 peter@eisentraut.org 5284 : 0 : libpq_append_error(errorMessage, "no entry found on LDAP lookup");
6471 bruce@momjian.us 5285 : 0 : ldap_msgfree(res);
5286 : 0 : ldap_unbind(ld);
5287 : 0 : free(url);
5288 : 0 : return 1;
5289 : : }
5290 : :
5291 : : /* get values */
5292 [ # # ]: 0 : if ((values = ldap_get_values_len(ld, entry, attrs[0])) == NULL)
5293 : : {
516 peter@eisentraut.org 5294 : 0 : libpq_append_error(errorMessage, "attribute has no values on LDAP lookup");
6471 bruce@momjian.us 5295 : 0 : ldap_msgfree(res);
5296 : 0 : ldap_unbind(ld);
5297 : 0 : free(url);
5298 : 0 : return 1;
5299 : : }
5300 : :
5301 : 0 : ldap_msgfree(res);
5302 : 0 : free(url);
5303 : :
5304 [ # # ]: 0 : if (values[0] == NULL)
5305 : : {
516 peter@eisentraut.org 5306 : 0 : libpq_append_error(errorMessage, "attribute has no values on LDAP lookup");
6471 bruce@momjian.us 5307 : 0 : ldap_value_free_len(values);
5308 : 0 : ldap_unbind(ld);
5309 : 0 : return 1;
5310 : : }
5311 : :
5312 : : /* concatenate values into a single string with newline terminators */
4721 tgl@sss.pgh.pa.us 5313 : 0 : size = 1; /* for the trailing null */
5314 [ # # ]: 0 : for (i = 0; values[i] != NULL; i++)
6471 bruce@momjian.us 5315 : 0 : size += values[i]->bv_len + 1;
4721 tgl@sss.pgh.pa.us 5316 [ # # ]: 0 : if ((result = malloc(size)) == NULL)
5317 : : {
516 peter@eisentraut.org 5318 : 0 : libpq_append_error(errorMessage, "out of memory");
6471 bruce@momjian.us 5319 : 0 : ldap_value_free_len(values);
5320 : 0 : ldap_unbind(ld);
5321 : 0 : return 3;
5322 : : }
4721 tgl@sss.pgh.pa.us 5323 : 0 : p = result;
5324 [ # # ]: 0 : for (i = 0; values[i] != NULL; i++)
5325 : : {
5326 : 0 : memcpy(p, values[i]->bv_val, values[i]->bv_len);
6471 bruce@momjian.us 5327 : 0 : p += values[i]->bv_len;
5328 : 0 : *(p++) = '\n';
5329 : : }
4721 tgl@sss.pgh.pa.us 5330 : 0 : *p = '\0';
5331 : :
6471 bruce@momjian.us 5332 : 0 : ldap_value_free_len(values);
5333 : 0 : ldap_unbind(ld);
5334 : :
5335 : : /* parse result string */
5336 : 0 : oldstate = state = 0;
5337 [ # # ]: 0 : for (p = result; *p != '\0'; ++p)
5338 : : {
5339 [ # # # # : 0 : switch (state)
# # # # ]
5340 : : {
5341 : 0 : case 0: /* between entries */
5342 [ # # # # : 0 : if (!ld_is_sp_tab(*p) && !ld_is_nl_cr(*p))
# # # # ]
5343 : : {
5344 : 0 : optname = p;
5345 : 0 : state = 1;
5346 : : }
5347 : 0 : break;
5348 : 0 : case 1: /* in option name */
5349 [ # # # # ]: 0 : if (ld_is_sp_tab(*p))
5350 : : {
5351 : 0 : *p = '\0';
5352 : 0 : state = 2;
5353 : : }
5354 [ # # # # ]: 0 : else if (ld_is_nl_cr(*p))
5355 : : {
516 peter@eisentraut.org 5356 : 0 : libpq_append_error(errorMessage,
5357 : : "missing \"=\" after \"%s\" in connection info string",
5358 : : optname);
4721 tgl@sss.pgh.pa.us 5359 : 0 : free(result);
6471 bruce@momjian.us 5360 : 0 : return 3;
5361 : : }
5362 [ # # ]: 0 : else if (*p == '=')
5363 : : {
5364 : 0 : *p = '\0';
5365 : 0 : state = 3;
5366 : : }
5367 : 0 : break;
5368 : 0 : case 2: /* after option name */
5369 [ # # ]: 0 : if (*p == '=')
5370 : : {
5371 : 0 : state = 3;
5372 : : }
5373 [ # # # # ]: 0 : else if (!ld_is_sp_tab(*p))
5374 : : {
516 peter@eisentraut.org 5375 : 0 : libpq_append_error(errorMessage,
5376 : : "missing \"=\" after \"%s\" in connection info string",
5377 : : optname);
4721 tgl@sss.pgh.pa.us 5378 : 0 : free(result);
6471 bruce@momjian.us 5379 : 0 : return 3;
5380 : : }
5381 : 0 : break;
5382 : 0 : case 3: /* before option value */
5383 [ # # ]: 0 : if (*p == '\'')
5384 : : {
5385 : 0 : optval = p + 1;
5386 : 0 : p1 = p + 1;
5387 : 0 : state = 5;
5388 : : }
5389 [ # # # # ]: 0 : else if (ld_is_nl_cr(*p))
5390 : : {
5391 : 0 : optval = optname + strlen(optname); /* empty */
5392 : 0 : state = 0;
5393 : : }
5394 [ # # # # ]: 0 : else if (!ld_is_sp_tab(*p))
5395 : : {
5396 : 0 : optval = p;
5397 : 0 : state = 4;
5398 : : }
5399 : 0 : break;
5400 : 0 : case 4: /* in unquoted option value */
5401 [ # # # # : 0 : if (ld_is_sp_tab(*p) || ld_is_nl_cr(*p))
# # # # ]
5402 : : {
5403 : 0 : *p = '\0';
5404 : 0 : state = 0;
5405 : : }
5406 : 0 : break;
5407 : 0 : case 5: /* in quoted option value */
5408 [ # # ]: 0 : if (*p == '\'')
5409 : : {
5410 : 0 : *p1 = '\0';
5411 : 0 : state = 0;
5412 : : }
5413 [ # # ]: 0 : else if (*p == '\\')
5414 : 0 : state = 6;
5415 : : else
5416 : 0 : *(p1++) = *p;
5417 : 0 : break;
5418 : 0 : case 6: /* in quoted option value after escape */
5419 : 0 : *(p1++) = *p;
5420 : 0 : state = 5;
5421 : 0 : break;
5422 : : }
5423 : :
5424 [ # # # # ]: 0 : if (state == 0 && oldstate != 0)
5425 : : {
5426 : 0 : found_keyword = false;
5427 [ # # ]: 0 : for (i = 0; options[i].keyword; i++)
5428 : : {
5429 [ # # ]: 0 : if (strcmp(options[i].keyword, optname) == 0)
5430 : : {
5431 [ # # ]: 0 : if (options[i].val == NULL)
5432 : : {
5433 : 0 : options[i].val = strdup(optval);
3428 heikki.linnakangas@i 5434 [ # # ]: 0 : if (!options[i].val)
5435 : : {
516 peter@eisentraut.org 5436 : 0 : libpq_append_error(errorMessage, "out of memory");
3428 heikki.linnakangas@i 5437 : 0 : free(result);
5438 : 0 : return 3;
5439 : : }
5440 : : }
6471 bruce@momjian.us 5441 : 0 : found_keyword = true;
5442 : 0 : break;
5443 : : }
5444 : : }
5445 [ # # ]: 0 : if (!found_keyword)
5446 : : {
516 peter@eisentraut.org 5447 : 0 : libpq_append_error(errorMessage, "invalid connection option \"%s\"", optname);
4721 tgl@sss.pgh.pa.us 5448 : 0 : free(result);
6471 bruce@momjian.us 5449 : 0 : return 1;
5450 : : }
5451 : 0 : optname = NULL;
5452 : 0 : optval = NULL;
5453 : : }
5454 : 0 : oldstate = state;
5455 : : }
5456 : :
4721 tgl@sss.pgh.pa.us 5457 : 0 : free(result);
5458 : :
6471 bruce@momjian.us 5459 [ # # # # ]: 0 : if (state == 5 || state == 6)
5460 : : {
516 peter@eisentraut.org 5461 : 0 : libpq_append_error(errorMessage,
5462 : : "unterminated quoted string in connection info string");
6471 bruce@momjian.us 5463 : 0 : return 3;
5464 : : }
5465 : :
5466 : 0 : return 0;
5467 : : }
5468 : :
5469 : : #endif /* USE_LDAP */
5470 : :
5471 : : /*
5472 : : * parseServiceInfo: if a service name has been given, look it up and absorb
5473 : : * connection options from it into *options.
5474 : : *
5475 : : * Returns 0 on success, nonzero on failure. On failure, if errorMessage
5476 : : * isn't null, also store an error message there. (Note: the only reason
5477 : : * this function and related ones don't dump core on errorMessage == NULL
5478 : : * is the undocumented fact that appendPQExpBuffer does nothing when passed
5479 : : * a null PQExpBuffer pointer.)
5480 : : */
5481 : : static int
8529 tgl@sss.pgh.pa.us 5482 :CBC 12177 : parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
5483 : : {
4386 alvherre@alvh.no-ip. 5484 : 12177 : const char *service = conninfo_getval(options, "service");
5485 : : char serviceFile[MAXPGPATH];
5486 : : char *env;
7422 bruce@momjian.us 5487 : 12177 : bool group_found = false;
5488 : : int status;
5489 : : struct stat stat_buf;
5490 : :
5491 : : /*
5492 : : * We have to special-case the environment variable PGSERVICE here, since
5493 : : * this is and should be called before inserting environment defaults for
5494 : : * other connection options.
5495 : : */
7657 tgl@sss.pgh.pa.us 5496 [ + + ]: 12177 : if (service == NULL)
5497 : 12176 : service = getenv("PGSERVICE");
5498 : :
5499 : : /* If no service name given, nothing to do */
5198 peter_e@gmx.net 5500 [ + + ]: 12177 : if (service == NULL)
5501 : 12176 : return 0;
5502 : :
5503 : : /*
5504 : : * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that
5505 : : * exists).
5506 : : */
5507 [ + - ]: 1 : if ((env = getenv("PGSERVICEFILE")) != NULL)
5508 : 1 : strlcpy(serviceFile, env, sizeof(serviceFile));
5509 : : else
5510 : : {
5511 : : char homedir[MAXPGPATH];
5512 : :
5198 peter_e@gmx.net 5513 [ # # ]:UBC 0 : if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
2363 tgl@sss.pgh.pa.us 5514 : 0 : goto next_file;
5198 peter_e@gmx.net 5515 : 0 : snprintf(serviceFile, MAXPGPATH, "%s/%s", homedir, ".pg_service.conf");
2363 tgl@sss.pgh.pa.us 5516 [ # # ]: 0 : if (stat(serviceFile, &stat_buf) != 0)
5198 peter_e@gmx.net 5517 : 0 : goto next_file;
5518 : : }
5519 : :
5198 peter_e@gmx.net 5520 :CBC 1 : status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found);
5521 [ - + - - ]: 1 : if (group_found || status != 0)
5522 : 1 : return status;
5523 : :
5198 peter_e@gmx.net 5524 :UBC 0 : next_file:
5525 : :
5526 : : /*
5527 : : * This could be used by any application so we can't use the binary
5528 : : * location to find our config files.
5529 : : */
7255 bruce@momjian.us 5530 [ # # ]: 0 : snprintf(serviceFile, MAXPGPATH, "%s/pg_service.conf",
6881 neilc@samurai.com 5531 : 0 : getenv("PGSYSCONFDIR") ? getenv("PGSYSCONFDIR") : SYSCONFDIR);
2363 tgl@sss.pgh.pa.us 5532 [ # # ]: 0 : if (stat(serviceFile, &stat_buf) != 0)
5198 peter_e@gmx.net 5533 : 0 : goto last_file;
5534 : :
5535 : 0 : status = parseServiceFile(serviceFile, service, options, errorMessage, &group_found);
5536 [ # # ]: 0 : if (status != 0)
5537 : 0 : return status;
5538 : :
5539 : 0 : last_file:
5540 [ # # ]: 0 : if (!group_found)
5541 : : {
516 peter@eisentraut.org 5542 : 0 : libpq_append_error(errorMessage, "definition of service \"%s\" not found", service);
5198 peter_e@gmx.net 5543 : 0 : return 3;
5544 : : }
5545 : :
5546 : 0 : return 0;
5547 : : }
5548 : :
5549 : : static int
5198 peter_e@gmx.net 5550 :CBC 1 : parseServiceFile(const char *serviceFile,
5551 : : const char *service,
5552 : : PQconninfoOption *options,
5553 : : PQExpBuffer errorMessage,
5554 : : bool *group_found)
5555 : : {
1300 tgl@sss.pgh.pa.us 5556 : 1 : int result = 0,
5557 : 1 : linenr = 0,
5558 : : i;
5559 : : FILE *f;
5560 : : char *line;
5561 : : char buf[1024];
5562 : :
5563 : 1 : *group_found = false;
5564 : :
5198 peter_e@gmx.net 5565 : 1 : f = fopen(serviceFile, "r");
5566 [ - + ]: 1 : if (f == NULL)
5567 : : {
516 peter@eisentraut.org 5568 :UBC 0 : libpq_append_error(errorMessage, "service file \"%s\" not found", serviceFile);
5198 peter_e@gmx.net 5569 : 0 : return 1;
5570 : : }
5571 : :
1023 tgl@sss.pgh.pa.us 5572 [ + + ]:CBC 8 : while ((line = fgets(buf, sizeof(buf), f)) != NULL)
5573 : : {
5574 : : int len;
5575 : :
5198 peter_e@gmx.net 5576 : 7 : linenr++;
5577 : :
1023 tgl@sss.pgh.pa.us 5578 [ - + ]: 7 : if (strlen(line) >= sizeof(buf) - 1)
5579 : : {
516 peter@eisentraut.org 5580 :UBC 0 : libpq_append_error(errorMessage,
5581 : : "line %d too long in service file \"%s\"",
5582 : : linenr,
5583 : : serviceFile);
1023 tgl@sss.pgh.pa.us 5584 : 0 : result = 2;
5585 : 0 : goto exit;
5586 : : }
5587 : :
5588 : : /* ignore whitespace at end of line, especially the newline */
1023 tgl@sss.pgh.pa.us 5589 :CBC 7 : len = strlen(line);
5590 [ + + + + ]: 14 : while (len > 0 && isspace((unsigned char) line[len - 1]))
5591 : 7 : line[--len] = '\0';
5592 : :
5593 : : /* ignore leading whitespace too */
5198 peter_e@gmx.net 5594 [ + + - + ]: 7 : while (*line && isspace((unsigned char) line[0]))
5198 peter_e@gmx.net 5595 :UBC 0 : line++;
5596 : :
5597 : : /* ignore comments and empty lines */
1725 tgl@sss.pgh.pa.us 5598 [ + + + + ]:CBC 7 : if (line[0] == '\0' || line[0] == '#')
5198 peter_e@gmx.net 5599 : 5 : continue;
5600 : :
5601 : : /* Check for right groupname */
5602 [ + + ]: 2 : if (line[0] == '[')
5603 : : {
5604 [ - + ]: 1 : if (*group_found)
5605 : : {
5606 : : /* end of desired group reached; return success */
1300 tgl@sss.pgh.pa.us 5607 :UBC 0 : goto exit;
5608 : : }
5609 : :
5198 peter_e@gmx.net 5610 [ + - ]:CBC 1 : if (strncmp(line + 1, service, strlen(service)) == 0 &&
5611 [ + - ]: 1 : line[strlen(service) + 1] == ']')
5612 : 1 : *group_found = true;
5613 : : else
5198 peter_e@gmx.net 5614 :UBC 0 : *group_found = false;
5615 : : }
5616 : : else
5617 : : {
5198 peter_e@gmx.net 5618 [ + - ]:CBC 1 : if (*group_found)
5619 : : {
5620 : : /*
5621 : : * Finally, we are in the right group and can parse the line
5622 : : */
5623 : : char *key,
5624 : : *val;
5625 : : bool found_keyword;
5626 : :
5627 : : #ifdef USE_LDAP
5628 [ + - ]: 1 : if (strncmp(line, "ldap", 4) == 0)
5629 : : {
5630 : 1 : int rc = ldapServiceLookup(line, options, errorMessage);
5631 : :
5632 : : /* if rc = 2, go on reading for fallback */
5633 [ - - + - ]: 1 : switch (rc)
5634 : : {
5198 peter_e@gmx.net 5635 :UBC 0 : case 0:
1300 tgl@sss.pgh.pa.us 5636 : 0 : goto exit;
5198 peter_e@gmx.net 5637 : 0 : case 1:
5638 : : case 3:
1300 tgl@sss.pgh.pa.us 5639 : 0 : result = 3;
5640 : 0 : goto exit;
5198 peter_e@gmx.net 5641 :CBC 1 : case 2:
5642 : 1 : continue;
5643 : : }
5644 : : }
5645 : : #endif
5646 : :
5198 peter_e@gmx.net 5647 :UBC 0 : key = line;
5648 : 0 : val = strchr(line, '=');
5649 [ # # ]: 0 : if (val == NULL)
5650 : : {
516 peter@eisentraut.org 5651 : 0 : libpq_append_error(errorMessage,
5652 : : "syntax error in service file \"%s\", line %d",
5653 : : serviceFile,
5654 : : linenr);
1300 tgl@sss.pgh.pa.us 5655 : 0 : result = 3;
5656 : 0 : goto exit;
5657 : : }
5198 peter_e@gmx.net 5658 : 0 : *val++ = '\0';
5659 : :
3294 bruce@momjian.us 5660 [ # # ]: 0 : if (strcmp(key, "service") == 0)
5661 : : {
516 peter@eisentraut.org 5662 : 0 : libpq_append_error(errorMessage,
5663 : : "nested service specifications not supported in service file \"%s\", line %d",
5664 : : serviceFile,
5665 : : linenr);
1300 tgl@sss.pgh.pa.us 5666 : 0 : result = 3;
5667 : 0 : goto exit;
5668 : : }
5669 : :
5670 : : /*
5671 : : * Set the parameter --- but don't override any previous
5672 : : * explicit setting.
5673 : : */
5198 peter_e@gmx.net 5674 : 0 : found_keyword = false;
5675 [ # # ]: 0 : for (i = 0; options[i].keyword; i++)
5676 : : {
5677 [ # # ]: 0 : if (strcmp(options[i].keyword, key) == 0)
5678 : : {
5679 [ # # ]: 0 : if (options[i].val == NULL)
5680 : 0 : options[i].val = strdup(val);
3428 heikki.linnakangas@i 5681 [ # # ]: 0 : if (!options[i].val)
5682 : : {
516 peter@eisentraut.org 5683 : 0 : libpq_append_error(errorMessage, "out of memory");
1300 tgl@sss.pgh.pa.us 5684 : 0 : result = 3;
5685 : 0 : goto exit;
5686 : : }
5198 peter_e@gmx.net 5687 : 0 : found_keyword = true;
5688 : 0 : break;
5689 : : }
5690 : : }
5691 : :
5692 [ # # ]: 0 : if (!found_keyword)
5693 : : {
516 peter@eisentraut.org 5694 : 0 : libpq_append_error(errorMessage,
5695 : : "syntax error in service file \"%s\", line %d",
5696 : : serviceFile,
5697 : : linenr);
1300 tgl@sss.pgh.pa.us 5698 : 0 : result = 3;
5699 : 0 : goto exit;
5700 : : }
5701 : : }
5702 : : }
5703 : : }
5704 : :
1300 tgl@sss.pgh.pa.us 5705 :CBC 1 : exit:
5198 peter_e@gmx.net 5706 : 1 : fclose(f);
5707 : :
1300 tgl@sss.pgh.pa.us 5708 : 1 : return result;
5709 : : }
5710 : :
5711 : :
5712 : : /*
5713 : : * PQconninfoParse
5714 : : *
5715 : : * Parse a string like PQconnectdb() would do and return the
5716 : : * resulting connection options array. NULL is returned on failure.
5717 : : * The result contains only options specified directly in the string,
5718 : : * not any possible default values.
5719 : : *
5720 : : * If errmsg isn't NULL, *errmsg is set to NULL on success, or a malloc'd
5721 : : * string on failure (use PQfreemem to free it). In out-of-memory conditions
5722 : : * both *errmsg and the result could be NULL.
5723 : : *
5724 : : * NOTE: the returned array is dynamically allocated and should
5725 : : * be freed when no longer needed via PQconninfoFree().
5726 : : */
5727 : : PQconninfoOption *
5683 5728 : 1227 : PQconninfoParse(const char *conninfo, char **errmsg)
5729 : : {
5730 : : PQExpBufferData errorBuf;
5731 : : PQconninfoOption *connOptions;
5732 : :
5733 [ + + ]: 1227 : if (errmsg)
5734 : 1220 : *errmsg = NULL; /* default */
5735 : 1227 : initPQExpBuffer(&errorBuf);
4562 5736 [ - + ]: 1227 : if (PQExpBufferDataBroken(errorBuf))
5683 tgl@sss.pgh.pa.us 5737 :UBC 0 : return NULL; /* out of memory already :-( */
4386 alvherre@alvh.no-ip. 5738 :CBC 1227 : connOptions = parse_connection_string(conninfo, &errorBuf, false);
5683 tgl@sss.pgh.pa.us 5739 [ + + + - ]: 1227 : if (connOptions == NULL && errmsg)
5740 : 23 : *errmsg = errorBuf.data;
5741 : : else
5742 : 1204 : termPQExpBuffer(&errorBuf);
5743 : 1227 : return connOptions;
5744 : : }
5745 : :
5746 : : /*
5747 : : * Build a working copy of the constant PQconninfoOptions array.
5748 : : */
5749 : : static PQconninfoOption *
4406 5750 : 21876 : conninfo_init(PQExpBuffer errorMessage)
5751 : : {
5752 : : PQconninfoOption *options;
5753 : : PQconninfoOption *opt_dest;
5754 : : const internalPQconninfoOption *cur_opt;
5755 : :
5756 : : /*
5757 : : * Get enough memory for all options in PQconninfoOptions, even if some
5758 : : * end up being filtered out.
5759 : : */
4153 magnus@hagander.net 5760 : 21876 : options = (PQconninfoOption *) malloc(sizeof(PQconninfoOption) * sizeof(PQconninfoOptions) / sizeof(PQconninfoOptions[0]));
4406 tgl@sss.pgh.pa.us 5761 [ - + ]: 21876 : if (options == NULL)
5762 : : {
516 peter@eisentraut.org 5763 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
4406 tgl@sss.pgh.pa.us 5764 : 0 : return NULL;
5765 : : }
4153 magnus@hagander.net 5766 :CBC 21876 : opt_dest = options;
5767 : :
5768 [ + + ]: 918792 : for (cur_opt = PQconninfoOptions; cur_opt->keyword; cur_opt++)
5769 : : {
5770 : : /* Only copy the public part of the struct, not the full internal */
5771 : 896916 : memcpy(opt_dest, cur_opt, sizeof(PQconninfoOption));
5772 : 896916 : opt_dest++;
5773 : : }
5774 [ + - + - : 175008 : MemSet(opt_dest, 0, sizeof(PQconninfoOption));
+ - + - +
+ ]
5775 : :
4406 tgl@sss.pgh.pa.us 5776 : 21876 : return options;
5777 : : }
5778 : :
5779 : : /*
5780 : : * Connection string parser
5781 : : *
5782 : : * Returns a malloc'd PQconninfoOption array, if parsing is successful.
5783 : : * Otherwise, NULL is returned and an error message is added to errorMessage.
5784 : : *
5785 : : * If use_defaults is true, default values are filled in (from a service file,
5786 : : * environment variables, etc).
5787 : : */
5788 : : static PQconninfoOption *
4386 alvherre@alvh.no-ip. 5789 : 10258 : parse_connection_string(const char *connstr, PQExpBuffer errorMessage,
5790 : : bool use_defaults)
5791 : : {
5792 : : /* Parse as URI if connection string matches URI prefix */
3300 rhaas@postgresql.org 5793 [ + + ]: 10258 : if (uri_prefix_length(connstr) != 0)
4386 alvherre@alvh.no-ip. 5794 : 59 : return conninfo_uri_parse(connstr, errorMessage, use_defaults);
5795 : :
5796 : : /* Parse as default otherwise */
5797 : 10199 : return conninfo_parse(connstr, errorMessage, use_defaults);
5798 : : }
5799 : :
5800 : : /*
5801 : : * Checks if connection string starts with either of the valid URI prefix
5802 : : * designators.
5803 : : *
5804 : : * Returns the URI prefix length, 0 if the string doesn't contain a URI prefix.
5805 : : *
5806 : : * XXX this is duplicated in psql/common.c.
5807 : : */
5808 : : static int
3300 rhaas@postgresql.org 5809 : 20646 : uri_prefix_length(const char *connstr)
5810 : : {
5811 [ + + ]: 20646 : if (strncmp(connstr, uri_designator,
5812 : : sizeof(uri_designator) - 1) == 0)
5813 : 80 : return sizeof(uri_designator) - 1;
5814 : :
5815 [ + + ]: 20566 : if (strncmp(connstr, short_uri_designator,
5816 : : sizeof(short_uri_designator) - 1) == 0)
5817 : 38 : return sizeof(short_uri_designator) - 1;
5818 : :
5819 : 20528 : return 0;
5820 : : }
5821 : :
5822 : : /*
5823 : : * Recognized connection string either starts with a valid URI prefix or
5824 : : * contains a "=" in it.
5825 : : *
5826 : : * Must be consistent with parse_connection_string: anything for which this
5827 : : * returns true should at least look like it's parseable by that routine.
5828 : : *
5829 : : * XXX this is duplicated in psql/common.c
5830 : : */
5831 : : static bool
5832 : 10329 : recognized_connection_string(const char *connstr)
5833 : : {
5834 [ + - + + ]: 10329 : return uri_prefix_length(connstr) != 0 || strchr(connstr, '=') != NULL;
5835 : : }
5836 : :
5837 : : /*
5838 : : * Subroutine for parse_connection_string
5839 : : *
5840 : : * Deal with a string containing key=value pairs.
5841 : : */
5842 : : static PQconninfoOption *
5971 tgl@sss.pgh.pa.us 5843 : 10199 : conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
5844 : : bool use_defaults)
5845 : : {
5846 : : char *pname;
5847 : : char *pval;
5848 : : char *buf;
5849 : : char *cp;
5850 : : char *cp2;
5851 : : PQconninfoOption *options;
5852 : :
5853 : : /* Make a working copy of PQconninfoOptions */
4406 5854 : 10199 : options = conninfo_init(errorMessage);
8800 5855 [ - + ]: 10199 : if (options == NULL)
8800 tgl@sss.pgh.pa.us 5856 :UBC 0 : return NULL;
5857 : :
5858 : : /* Need a modifiable copy of the input string */
9716 bruce@momjian.us 5859 [ - + ]:CBC 10199 : if ((buf = strdup(conninfo)) == NULL)
5860 : : {
516 peter@eisentraut.org 5861 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
8800 tgl@sss.pgh.pa.us 5862 : 0 : PQconninfoFree(options);
5863 : 0 : return NULL;
5864 : : }
9716 bruce@momjian.us 5865 :CBC 10199 : cp = buf;
5866 : :
5867 [ + + ]: 42362 : while (*cp)
5868 : : {
5869 : : /* Skip blanks before the parameter name */
8533 tgl@sss.pgh.pa.us 5870 [ + + ]: 32175 : if (isspace((unsigned char) *cp))
5871 : : {
9716 bruce@momjian.us 5872 : 214 : cp++;
5873 : 214 : continue;
5874 : : }
5875 : :
5876 : : /* Get the parameter name */
5877 : 31961 : pname = cp;
5878 [ + + ]: 198543 : while (*cp)
5879 : : {
5880 [ + + ]: 198534 : if (*cp == '=')
5881 : 31952 : break;
8533 tgl@sss.pgh.pa.us 5882 [ - + ]: 166582 : if (isspace((unsigned char) *cp))
5883 : : {
9716 bruce@momjian.us 5884 :UBC 0 : *cp++ = '\0';
5885 [ # # ]: 0 : while (*cp)
5886 : : {
8533 tgl@sss.pgh.pa.us 5887 [ # # ]: 0 : if (!isspace((unsigned char) *cp))
9716 bruce@momjian.us 5888 : 0 : break;
5889 : 0 : cp++;
5890 : : }
5891 : 0 : break;
5892 : : }
9716 bruce@momjian.us 5893 :CBC 166582 : cp++;
5894 : : }
5895 : :
5896 : : /* Check that there is a following '=' */
5897 [ + + ]: 31961 : if (*cp != '=')
5898 : : {
516 peter@eisentraut.org 5899 : 9 : libpq_append_error(errorMessage,
5900 : : "missing \"=\" after \"%s\" in connection info string",
5901 : : pname);
8800 tgl@sss.pgh.pa.us 5902 : 9 : PQconninfoFree(options);
9716 bruce@momjian.us 5903 : 9 : free(buf);
8800 tgl@sss.pgh.pa.us 5904 : 9 : return NULL;
5905 : : }
9716 bruce@momjian.us 5906 : 31952 : *cp++ = '\0';
5907 : :
5908 : : /* Skip blanks after the '=' */
5909 [ + + ]: 31952 : while (*cp)
5910 : : {
8533 tgl@sss.pgh.pa.us 5911 [ + - ]: 31951 : if (!isspace((unsigned char) *cp))
9716 bruce@momjian.us 5912 : 31951 : break;
9716 bruce@momjian.us 5913 :UBC 0 : cp++;
5914 : : }
5915 : :
5916 : : /* Get the parameter value */
9716 bruce@momjian.us 5917 :CBC 31952 : pval = cp;
5918 : :
5919 [ + + ]: 31952 : if (*cp != '\'')
5920 : : {
5921 : 25033 : cp2 = pval;
5922 [ + + ]: 288764 : while (*cp)
5923 : : {
8533 tgl@sss.pgh.pa.us 5924 [ + + ]: 285358 : if (isspace((unsigned char) *cp))
5925 : : {
9716 bruce@momjian.us 5926 : 21627 : *cp++ = '\0';
5927 : 21627 : break;
5928 : : }
5929 [ + + ]: 263731 : if (*cp == '\\')
5930 : : {
5931 : 1 : cp++;
5932 [ + - ]: 1 : if (*cp != '\0')
5933 : 1 : *cp2++ = *cp++;
5934 : : }
5935 : : else
5936 : 263730 : *cp2++ = *cp++;
5937 : : }
5938 : 25033 : *cp2 = '\0';
5939 : : }
5940 : : else
5941 : : {
5942 : 6919 : cp2 = pval;
5943 : 6919 : cp++;
5944 : : for (;;)
5945 : : {
5946 [ - + ]: 68721 : if (*cp == '\0')
5947 : : {
516 peter@eisentraut.org 5948 :UBC 0 : libpq_append_error(errorMessage, "unterminated quoted string in connection info string");
8800 tgl@sss.pgh.pa.us 5949 : 0 : PQconninfoFree(options);
9716 bruce@momjian.us 5950 : 0 : free(buf);
8800 tgl@sss.pgh.pa.us 5951 : 0 : return NULL;
5952 : : }
9716 bruce@momjian.us 5953 [ + + ]:CBC 68721 : if (*cp == '\\')
5954 : : {
5955 : 200 : cp++;
5956 [ + - ]: 200 : if (*cp != '\0')
5957 : 200 : *cp2++ = *cp++;
5958 : 200 : continue;
5959 : : }
5960 [ + + ]: 68521 : if (*cp == '\'')
5961 : : {
5962 : 6919 : *cp2 = '\0';
5963 : 6919 : cp++;
5964 : 6919 : break;
5965 : : }
5966 : 61602 : *cp2++ = *cp++;
5967 : : }
5968 : : }
5969 : :
5970 : : /*
5971 : : * Now that we have the name and the value, store the record.
5972 : : */
4386 alvherre@alvh.no-ip. 5973 [ + + ]: 31952 : if (!conninfo_storeval(options, pname, pval, errorMessage, false, false))
5974 : : {
6881 neilc@samurai.com 5975 : 3 : PQconninfoFree(options);
5976 : 3 : free(buf);
5977 : 3 : return NULL;
5978 : : }
5979 : : }
5980 : :
5981 : : /* Done with the modifiable input string */
7657 tgl@sss.pgh.pa.us 5982 : 10187 : free(buf);
5983 : :
5984 : : /*
5985 : : * Add in defaults if the caller wants that.
5986 : : */
4406 5987 [ + + ]: 10187 : if (use_defaults)
5988 : : {
5989 [ - + ]: 851 : if (!conninfo_add_defaults(options, errorMessage))
5990 : : {
4406 tgl@sss.pgh.pa.us 5991 :UBC 0 : PQconninfoFree(options);
5992 : 0 : return NULL;
5993 : : }
5994 : : }
5995 : :
8800 tgl@sss.pgh.pa.us 5996 :CBC 10187 : return options;
5997 : : }
5998 : :
5999 : : /*
6000 : : * Conninfo array parser routine
6001 : : *
6002 : : * If successful, a malloc'd PQconninfoOption array is returned.
6003 : : * If not successful, NULL is returned and an error message is
6004 : : * appended to errorMessage.
6005 : : * Defaults are supplied (from a service file, environment variables, etc)
6006 : : * for unspecified options, but only if use_defaults is true.
6007 : : *
6008 : : * If expand_dbname is non-zero, and the value passed for the first occurrence
6009 : : * of "dbname" keyword is a connection string (as indicated by
6010 : : * recognized_connection_string) then parse and process it, overriding any
6011 : : * previously processed conflicting keywords. Subsequent keywords will take
6012 : : * precedence, however. In-tree programs generally specify expand_dbname=true,
6013 : : * so command-line arguments naming a database can use a connection string.
6014 : : * Some code acquires arbitrary database names from known-literal sources like
6015 : : * PQdb(), PQconninfoParse() and pg_database.datname. When connecting to such
6016 : : * a database, in-tree code first wraps the name in a connection string.
6017 : : */
6018 : : static PQconninfoOption *
2489 6019 : 11237 : conninfo_array_parse(const char *const *keywords, const char *const *values,
6020 : : PQExpBuffer errorMessage, bool use_defaults,
6021 : : int expand_dbname)
6022 : : {
6023 : : PQconninfoOption *options;
4386 alvherre@alvh.no-ip. 6024 : 11237 : PQconninfoOption *dbname_options = NULL;
6025 : : PQconninfoOption *option;
5161 bruce@momjian.us 6026 : 11237 : int i = 0;
6027 : :
6028 : : /*
6029 : : * If expand_dbname is non-zero, check keyword "dbname" to see if val is
6030 : : * actually a recognized connection string.
6031 : : */
6032 [ + + + + ]: 49793 : while (expand_dbname && keywords[i])
6033 : : {
5182 mail@joeconway.com 6034 : 48885 : const char *pname = keywords[i];
5161 bruce@momjian.us 6035 : 48885 : const char *pvalue = values[i];
6036 : :
6037 : : /* first find "dbname" if any */
4386 alvherre@alvh.no-ip. 6038 [ + + + + ]: 48885 : if (strcmp(pname, "dbname") == 0 && pvalue)
6039 : : {
6040 : : /*
6041 : : * If value is a connection string, parse it, but do not use
6042 : : * defaults here -- those get picked up later. We only want to
6043 : : * override for those parameters actually passed.
6044 : : */
3300 rhaas@postgresql.org 6045 [ + + ]: 10329 : if (recognized_connection_string(pvalue))
6046 : : {
4386 alvherre@alvh.no-ip. 6047 : 8178 : dbname_options = parse_connection_string(pvalue, errorMessage, false);
6048 [ - + ]: 8178 : if (dbname_options == NULL)
5182 mail@joeconway.com 6049 :UBC 0 : return NULL;
6050 : : }
5182 mail@joeconway.com 6051 :CBC 10329 : break;
6052 : : }
6053 : 38556 : ++i;
6054 : : }
6055 : :
6056 : : /* Make a working copy of PQconninfoOptions */
4406 tgl@sss.pgh.pa.us 6057 : 11237 : options = conninfo_init(errorMessage);
5190 mail@joeconway.com 6058 [ - + ]: 11237 : if (options == NULL)
6059 : : {
4386 alvherre@alvh.no-ip. 6060 :UBC 0 : PQconninfoFree(dbname_options);
5190 mail@joeconway.com 6061 : 0 : return NULL;
6062 : : }
6063 : :
6064 : : /* Parse the keywords/values arrays */
4406 tgl@sss.pgh.pa.us 6065 :CBC 11237 : i = 0;
5161 bruce@momjian.us 6066 [ + + ]: 84990 : while (keywords[i])
6067 : : {
5190 mail@joeconway.com 6068 : 73753 : const char *pname = keywords[i];
5161 bruce@momjian.us 6069 : 73753 : const char *pvalue = values[i];
6070 : :
3648 6071 [ + + + + ]: 73753 : if (pvalue != NULL && pvalue[0] != '\0')
6072 : : {
6073 : : /* Search for the param record */
5190 mail@joeconway.com 6074 [ + - ]: 374389 : for (option = options; option->keyword != NULL; option++)
6075 : : {
6076 [ + + ]: 374389 : if (strcmp(option->keyword, pname) == 0)
6077 : 28947 : break;
6078 : : }
6079 : :
6080 : : /* Check for invalid connection option */
6081 [ - + ]: 28947 : if (option->keyword == NULL)
6082 : : {
516 peter@eisentraut.org 6083 :UBC 0 : libpq_append_error(errorMessage, "invalid connection option \"%s\"", pname);
5190 mail@joeconway.com 6084 : 0 : PQconninfoFree(options);
4386 alvherre@alvh.no-ip. 6085 : 0 : PQconninfoFree(dbname_options);
5190 mail@joeconway.com 6086 : 0 : return NULL;
6087 : : }
6088 : :
6089 : : /*
6090 : : * If we are on the first dbname parameter, and we have a parsed
6091 : : * connection string, copy those parameters across, overriding any
6092 : : * existing previous settings.
6093 : : */
4386 alvherre@alvh.no-ip. 6094 [ + + + + ]:CBC 28947 : if (strcmp(pname, "dbname") == 0 && dbname_options)
5182 mail@joeconway.com 6095 : 8178 : {
6096 : : PQconninfoOption *str_option;
6097 : :
4386 alvherre@alvh.no-ip. 6098 [ + + ]: 343476 : for (str_option = dbname_options; str_option->keyword != NULL; str_option++)
6099 : : {
5182 mail@joeconway.com 6100 [ + + ]: 335298 : if (str_option->val != NULL)
6101 : : {
6102 : : int k;
6103 : :
6104 [ + - ]: 256609 : for (k = 0; options[k].keyword; k++)
6105 : : {
6106 [ + + ]: 256609 : if (strcmp(options[k].keyword, str_option->keyword) == 0)
6107 : : {
668 peter@eisentraut.org 6108 : 26545 : free(options[k].val);
5182 mail@joeconway.com 6109 : 26545 : options[k].val = strdup(str_option->val);
3428 heikki.linnakangas@i 6110 [ - + ]: 26545 : if (!options[k].val)
6111 : : {
516 peter@eisentraut.org 6112 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
3428 heikki.linnakangas@i 6113 : 0 : PQconninfoFree(options);
6114 : 0 : PQconninfoFree(dbname_options);
6115 : 0 : return NULL;
6116 : : }
5182 mail@joeconway.com 6117 :CBC 26545 : break;
6118 : : }
6119 : : }
6120 : : }
6121 : : }
6122 : :
6123 : : /*
6124 : : * Forget the parsed connection string, so that any subsequent
6125 : : * dbname parameters will not be expanded.
6126 : : */
3428 heikki.linnakangas@i 6127 : 8178 : PQconninfoFree(dbname_options);
6128 : 8178 : dbname_options = NULL;
6129 : : }
6130 : : else
6131 : : {
6132 : : /*
6133 : : * Store the value, overriding previous settings
6134 : : */
668 peter@eisentraut.org 6135 : 20769 : free(option->val);
5182 mail@joeconway.com 6136 : 20769 : option->val = strdup(pvalue);
6137 [ - + ]: 20769 : if (!option->val)
6138 : : {
516 peter@eisentraut.org 6139 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
5182 mail@joeconway.com 6140 : 0 : PQconninfoFree(options);
4386 alvherre@alvh.no-ip. 6141 : 0 : PQconninfoFree(dbname_options);
5182 mail@joeconway.com 6142 : 0 : return NULL;
6143 : : }
6144 : : }
6145 : : }
5190 mail@joeconway.com 6146 :CBC 73753 : ++i;
6147 : : }
4386 alvherre@alvh.no-ip. 6148 : 11237 : PQconninfoFree(dbname_options);
6149 : :
6150 : : /*
6151 : : * Add in defaults if the caller wants that.
6152 : : */
4406 tgl@sss.pgh.pa.us 6153 [ + - ]: 11237 : if (use_defaults)
6154 : : {
6155 [ - + ]: 11237 : if (!conninfo_add_defaults(options, errorMessage))
6156 : : {
4406 tgl@sss.pgh.pa.us 6157 :UBC 0 : PQconninfoFree(options);
6158 : 0 : return NULL;
6159 : : }
6160 : : }
6161 : :
4406 tgl@sss.pgh.pa.us 6162 :CBC 11237 : return options;
6163 : : }
6164 : :
6165 : : /*
6166 : : * Add the default values for any unspecified options to the connection
6167 : : * options array.
6168 : : *
6169 : : * Defaults are obtained from a service file, environment variables, etc.
6170 : : *
6171 : : * Returns true if successful, otherwise false; errorMessage, if supplied,
6172 : : * is filled in upon failure. Note that failure to locate a default value
6173 : : * is not an error condition here --- we just leave the option's value as
6174 : : * NULL.
6175 : : */
6176 : : static bool
6177 : 12177 : conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
6178 : : {
6179 : : PQconninfoOption *option;
375 dgustafsson@postgres 6180 : 12177 : PQconninfoOption *sslmode_default = NULL,
6181 : 12177 : *sslrootcert = NULL;
6182 : : char *tmp;
6183 : :
6184 : : /*
6185 : : * If there's a service spec, use it to obtain any not-explicitly-given
6186 : : * parameters. Ignore error if no error message buffer is passed because
6187 : : * there is no way to pass back the failure message.
6188 : : */
3785 bruce@momjian.us 6189 [ - + - - ]: 12177 : if (parseServiceInfo(options, errorMessage) != 0 && errorMessage)
4406 tgl@sss.pgh.pa.us 6190 :UBC 0 : return false;
6191 : :
6192 : : /*
6193 : : * Get the fallback resources for parameters not specified in the conninfo
6194 : : * string nor the service.
6195 : : */
5190 mail@joeconway.com 6196 [ + + ]:CBC 511434 : for (option = options; option->keyword != NULL; option++)
6197 : : {
375 dgustafsson@postgres 6198 [ + + ]: 499257 : if (strcmp(option->keyword, "sslrootcert") == 0)
6199 : 12177 : sslrootcert = option; /* save for later */
6200 : :
5190 mail@joeconway.com 6201 [ + + ]: 499257 : if (option->val != NULL)
6202 : 49128 : continue; /* Value was in conninfo or service */
6203 : :
6204 : : /*
6205 : : * Try to get the environment variable fallback
6206 : : */
6207 [ + + ]: 450129 : if (option->envvar != NULL)
6208 : : {
6209 [ + + ]: 365072 : if ((tmp = getenv(option->envvar)) != NULL)
6210 : : {
6211 : 21018 : option->val = strdup(tmp);
6212 [ - + ]: 21018 : if (!option->val)
6213 : : {
3785 bruce@momjian.us 6214 [ # # ]:UBC 0 : if (errorMessage)
516 peter@eisentraut.org 6215 : 0 : libpq_append_error(errorMessage, "out of memory");
4406 tgl@sss.pgh.pa.us 6216 : 0 : return false;
6217 : : }
5190 mail@joeconway.com 6218 :CBC 21018 : continue;
6219 : : }
6220 : : }
6221 : :
6222 : : /*
6223 : : * Interpret the deprecated PGREQUIRESSL environment variable. Per
6224 : : * tradition, translate values starting with "1" to sslmode=require,
6225 : : * and ignore other values. Given both PGREQUIRESSL=1 and PGSSLMODE,
6226 : : * PGSSLMODE takes precedence; the opposite was true before v9.3.
6227 : : */
2533 noah@leadboat.com 6228 [ + + ]: 429111 : if (strcmp(option->keyword, "sslmode") == 0)
6229 : : {
6230 : 11538 : const char *requiresslenv = getenv("PGREQUIRESSL");
6231 : :
6232 [ - + - - ]: 11538 : if (requiresslenv != NULL && requiresslenv[0] == '1')
6233 : : {
2533 noah@leadboat.com 6234 :UBC 0 : option->val = strdup("require");
6235 [ # # ]: 0 : if (!option->val)
6236 : : {
6237 [ # # ]: 0 : if (errorMessage)
516 peter@eisentraut.org 6238 : 0 : libpq_append_error(errorMessage, "out of memory");
2533 noah@leadboat.com 6239 : 0 : return false;
6240 : : }
6241 : 0 : continue;
6242 : : }
6243 : :
6244 : : /*
6245 : : * sslmode is not specified. Let it be filled in with the compiled
6246 : : * default for now, but if sslrootcert=system, we'll override the
6247 : : * default later before returning.
6248 : : */
375 dgustafsson@postgres 6249 :CBC 11538 : sslmode_default = option;
6250 : : }
6251 : :
6252 : : /*
6253 : : * No environment variable specified or the variable isn't set - try
6254 : : * compiled-in default
6255 : : */
5190 mail@joeconway.com 6256 [ + + ]: 429111 : if (option->compiled != NULL)
6257 : : {
6258 : 139866 : option->val = strdup(option->compiled);
6259 [ - + ]: 139866 : if (!option->val)
6260 : : {
3785 bruce@momjian.us 6261 [ # # ]:UBC 0 : if (errorMessage)
516 peter@eisentraut.org 6262 : 0 : libpq_append_error(errorMessage, "out of memory");
4406 tgl@sss.pgh.pa.us 6263 : 0 : return false;
6264 : : }
5190 mail@joeconway.com 6265 :CBC 139866 : continue;
6266 : : }
6267 : :
6268 : : /*
6269 : : * Special handling for "user" option. Note that if pg_fe_getauthname
6270 : : * fails, we just leave the value as NULL; there's no need for this to
6271 : : * be an error condition if the caller provides a user name. The only
6272 : : * reason we do this now at all is so that callers of PQconndefaults
6273 : : * will see a correct default (barring error, of course).
6274 : : */
6275 [ + + ]: 289245 : if (strcmp(option->keyword, "user") == 0)
6276 : : {
3381 tgl@sss.pgh.pa.us 6277 : 10874 : option->val = pg_fe_getauthname(NULL);
5190 mail@joeconway.com 6278 : 10874 : continue;
6279 : : }
6280 : : }
6281 : :
6282 : : /*
6283 : : * Special handling for sslrootcert=system with no sslmode explicitly
6284 : : * defined. In this case we want to strengthen the default sslmode to
6285 : : * verify-full.
6286 : : */
375 dgustafsson@postgres 6287 [ + + + - ]: 12177 : if (sslmode_default && sslrootcert)
6288 : : {
6289 [ + + + + ]: 11538 : if (sslrootcert->val && strcmp(sslrootcert->val, "system") == 0)
6290 : : {
6291 : 4 : free(sslmode_default->val);
6292 : :
6293 : 4 : sslmode_default->val = strdup("verify-full");
6294 [ - + ]: 4 : if (!sslmode_default->val)
6295 : : {
375 dgustafsson@postgres 6296 [ # # ]:UBC 0 : if (errorMessage)
6297 : 0 : libpq_append_error(errorMessage, "out of memory");
6298 : 0 : return false;
6299 : : }
6300 : : }
6301 : : }
6302 : :
4406 tgl@sss.pgh.pa.us 6303 :CBC 12177 : return true;
6304 : : }
6305 : :
6306 : : /*
6307 : : * Subroutine for parse_connection_string
6308 : : *
6309 : : * Deal with a URI connection string.
6310 : : */
6311 : : static PQconninfoOption *
4386 alvherre@alvh.no-ip. 6312 : 59 : conninfo_uri_parse(const char *uri, PQExpBuffer errorMessage,
6313 : : bool use_defaults)
6314 : : {
6315 : : PQconninfoOption *options;
6316 : :
6317 : : /* Make a working copy of PQconninfoOptions */
6318 : 59 : options = conninfo_init(errorMessage);
6319 [ - + ]: 59 : if (options == NULL)
4386 alvherre@alvh.no-ip. 6320 :UBC 0 : return NULL;
6321 : :
4386 alvherre@alvh.no-ip. 6322 [ + + ]:CBC 59 : if (!conninfo_uri_parse_options(options, uri, errorMessage))
6323 : : {
6324 : 13 : PQconninfoFree(options);
6325 : 13 : return NULL;
6326 : : }
6327 : :
6328 : : /*
6329 : : * Add in defaults if the caller wants that.
6330 : : */
6331 [ - + ]: 46 : if (use_defaults)
6332 : : {
4386 alvherre@alvh.no-ip. 6333 [ # # ]:UBC 0 : if (!conninfo_add_defaults(options, errorMessage))
6334 : : {
6335 : 0 : PQconninfoFree(options);
6336 : 0 : return NULL;
6337 : : }
6338 : : }
6339 : :
4386 alvherre@alvh.no-ip. 6340 :CBC 46 : return options;
6341 : : }
6342 : :
6343 : : /*
6344 : : * conninfo_uri_parse_options
6345 : : * Actual URI parser.
6346 : : *
6347 : : * If successful, returns true while the options array is filled with parsed
6348 : : * options from the URI.
6349 : : * If not successful, returns false and fills errorMessage accordingly.
6350 : : *
6351 : : * Parses the connection URI string in 'uri' according to the URI syntax (RFC
6352 : : * 3986):
6353 : : *
6354 : : * postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
6355 : : *
6356 : : * where "netloc" is a hostname, an IPv4 address, or an IPv6 address surrounded
6357 : : * by literal square brackets. As an extension, we also allow multiple
6358 : : * netloc[:port] specifications, separated by commas:
6359 : : *
6360 : : * postgresql://[user[:password]@][netloc][:port][,...][/dbname][?param1=value1&...]
6361 : : *
6362 : : * Any of the URI parts might use percent-encoding (%xy).
6363 : : */
6364 : : static bool
6365 : 59 : conninfo_uri_parse_options(PQconninfoOption *options, const char *uri,
6366 : : PQExpBuffer errorMessage)
6367 : : {
6368 : : int prefix_len;
6369 : : char *p;
2700 rhaas@postgresql.org 6370 : 59 : char *buf = NULL;
6371 : : char *start;
4326 bruce@momjian.us 6372 : 59 : char prevchar = '\0';
6373 : 59 : char *user = NULL;
6374 : 59 : char *host = NULL;
6375 : 59 : bool retval = false;
6376 : : PQExpBufferData hostbuf;
6377 : : PQExpBufferData portbuf;
6378 : :
2719 rhaas@postgresql.org 6379 : 59 : initPQExpBuffer(&hostbuf);
6380 : 59 : initPQExpBuffer(&portbuf);
6381 [ + - - + ]: 59 : if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf))
6382 : : {
516 peter@eisentraut.org 6383 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
2700 rhaas@postgresql.org 6384 : 0 : goto cleanup;
6385 : : }
6386 : :
6387 : : /* need a modifiable copy of the input URI */
3428 heikki.linnakangas@i 6388 :CBC 59 : buf = strdup(uri);
4386 alvherre@alvh.no-ip. 6389 [ - + ]: 59 : if (buf == NULL)
6390 : : {
516 peter@eisentraut.org 6391 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
2700 rhaas@postgresql.org 6392 : 0 : goto cleanup;
6393 : : }
3428 heikki.linnakangas@i 6394 :CBC 59 : start = buf;
6395 : :
6396 : : /* Skip the URI prefix */
3300 rhaas@postgresql.org 6397 : 59 : prefix_len = uri_prefix_length(uri);
4386 alvherre@alvh.no-ip. 6398 [ - + ]: 59 : if (prefix_len == 0)
6399 : : {
6400 : : /* Should never happen */
516 peter@eisentraut.org 6401 :UBC 0 : libpq_append_error(errorMessage,
6402 : : "invalid URI propagated to internal parser routine: \"%s\"",
6403 : : uri);
4386 alvherre@alvh.no-ip. 6404 : 0 : goto cleanup;
6405 : : }
4386 alvherre@alvh.no-ip. 6406 :CBC 59 : start += prefix_len;
6407 : 59 : p = start;
6408 : :
6409 : : /* Look ahead for possible user credentials designator */
6410 [ + + + + : 592 : while (*p && *p != '@' && *p != '/')
+ + ]
6411 : 533 : ++p;
6412 [ + + ]: 59 : if (*p == '@')
6413 : : {
6414 : : /*
6415 : : * Found username/password designator, so URI should be of the form
6416 : : * "scheme://user[:password]@[netloc]".
6417 : : */
6418 : 12 : user = start;
6419 : :
6420 : 12 : p = user;
6421 [ + + + + ]: 104 : while (*p != ':' && *p != '@')
6422 : 92 : ++p;
6423 : :
6424 : : /* Save last char and cut off at end of user name */
6425 : 12 : prevchar = *p;
6426 : 12 : *p = '\0';
6427 : :
4339 peter_e@gmx.net 6428 [ + + - + ]: 23 : if (*user &&
6429 : 11 : !conninfo_storeval(options, "user", user,
6430 : : errorMessage, false, true))
4386 alvherre@alvh.no-ip. 6431 :UBC 0 : goto cleanup;
6432 : :
4386 alvherre@alvh.no-ip. 6433 [ + + ]:CBC 12 : if (prevchar == ':')
6434 : : {
6435 : 1 : const char *password = p + 1;
6436 : :
6437 [ + + ]: 8 : while (*p != '@')
6438 : 7 : ++p;
6439 : 1 : *p = '\0';
6440 : :
4339 peter_e@gmx.net 6441 [ + - - + ]: 2 : if (*password &&
6442 : 1 : !conninfo_storeval(options, "password", password,
6443 : : errorMessage, false, true))
4386 alvherre@alvh.no-ip. 6444 :UBC 0 : goto cleanup;
6445 : : }
6446 : :
6447 : : /* Advance past end of parsed user name or password token */
4386 alvherre@alvh.no-ip. 6448 :CBC 12 : ++p;
6449 : : }
6450 : : else
6451 : : {
6452 : : /*
6453 : : * No username/password designator found. Reset to start of URI.
6454 : : */
6455 : 47 : p = start;
6456 : : }
6457 : :
6458 : : /*
6459 : : * There may be multiple netloc[:port] pairs, each separated from the next
6460 : : * by a comma. When we initially enter this loop, "p" has been
6461 : : * incremented past optional URI credential information at this point and
6462 : : * now points at the "netloc" part of the URI. On subsequent loop
6463 : : * iterations, "p" has been incremented past the comma separator and now
6464 : : * points at the start of the next "netloc".
6465 : : */
6466 : : for (;;)
6467 : : {
6468 : : /*
6469 : : * Look for IPv6 address.
6470 : : */
2719 rhaas@postgresql.org 6471 [ + + ]: 59 : if (*p == '[')
6472 : : {
6473 : 8 : host = ++p;
6474 [ + + + + ]: 51 : while (*p && *p != ']')
6475 : 43 : ++p;
6476 [ + + ]: 8 : if (!*p)
6477 : : {
516 peter@eisentraut.org 6478 : 1 : libpq_append_error(errorMessage,
6479 : : "end of string reached when looking for matching \"]\" in IPv6 host address in URI: \"%s\"",
6480 : : uri);
2719 rhaas@postgresql.org 6481 : 1 : goto cleanup;
6482 : : }
6483 [ + + ]: 7 : if (p == host)
6484 : : {
516 peter@eisentraut.org 6485 : 1 : libpq_append_error(errorMessage,
6486 : : "IPv6 host address may not be empty in URI: \"%s\"",
6487 : : uri);
2719 rhaas@postgresql.org 6488 : 1 : goto cleanup;
6489 : : }
6490 : :
6491 : : /* Cut off the bracket and advance */
6492 : 6 : *(p++) = '\0';
6493 : :
6494 : : /*
6495 : : * The address may be followed by a port specifier or a slash or a
6496 : : * query or a separator comma.
6497 : : */
6498 [ + + + + : 6 : if (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',')
+ + + - +
- ]
6499 : : {
516 peter@eisentraut.org 6500 : 1 : libpq_append_error(errorMessage,
6501 : : "unexpected character \"%c\" at position %d in URI (expected \":\" or \"/\"): \"%s\"",
6502 : 1 : *p, (int) (p - buf + 1), uri);
2719 rhaas@postgresql.org 6503 : 1 : goto cleanup;
6504 : : }
6505 : : }
6506 : : else
6507 : : {
6508 : : /* not an IPv6 address: DNS-named or IPv4 netloc */
6509 : 51 : host = p;
6510 : :
6511 : : /*
6512 : : * Look for port specifier (colon) or end of host specifier
6513 : : * (slash) or query (question mark) or host separator (comma).
6514 : : */
6515 [ + + + + : 220 : while (*p && *p != ':' && *p != '/' && *p != '?' && *p != ',')
+ + + + +
- ]
6516 : 169 : ++p;
6517 : : }
6518 : :
6519 : : /* Save the hostname terminator before we null it */
6520 : 56 : prevchar = *p;
6521 : 56 : *p = '\0';
6522 : :
6523 : 56 : appendPQExpBufferStr(&hostbuf, host);
6524 : :
6525 [ + + ]: 56 : if (prevchar == ':')
6526 : : {
2489 tgl@sss.pgh.pa.us 6527 : 14 : const char *port = ++p; /* advance past host terminator */
6528 : :
2719 rhaas@postgresql.org 6529 [ + + + + : 79 : while (*p && *p != '/' && *p != '?' && *p != ',')
+ + + - ]
6530 : 65 : ++p;
6531 : :
6532 : 14 : prevchar = *p;
6533 : 14 : *p = '\0';
6534 : :
6535 : 14 : appendPQExpBufferStr(&portbuf, port);
6536 : : }
6537 : :
6538 [ + - ]: 56 : if (prevchar != ',')
6539 : 56 : break;
2524 bruce@momjian.us 6540 :UBC 0 : ++p; /* advance past comma separator */
2434 peter_e@gmx.net 6541 : 0 : appendPQExpBufferChar(&hostbuf, ',');
6542 : 0 : appendPQExpBufferChar(&portbuf, ',');
6543 : : }
6544 : :
6545 : : /* Save final values for host and port. */
2719 rhaas@postgresql.org 6546 [ + - - + ]:CBC 56 : if (PQExpBufferDataBroken(hostbuf) || PQExpBufferDataBroken(portbuf))
2719 rhaas@postgresql.org 6547 :UBC 0 : goto cleanup;
2719 rhaas@postgresql.org 6548 [ + + + + ]:CBC 97 : if (hostbuf.data[0] &&
6549 : 41 : !conninfo_storeval(options, "host", hostbuf.data,
6550 : : errorMessage, false, true))
6551 : 4 : goto cleanup;
6552 [ + + - + ]: 65 : if (portbuf.data[0] &&
6553 : 13 : !conninfo_storeval(options, "port", portbuf.data,
6554 : : errorMessage, false, true))
2719 rhaas@postgresql.org 6555 :UBC 0 : goto cleanup;
6556 : :
4386 alvherre@alvh.no-ip. 6557 [ + + + + ]:CBC 52 : if (prevchar && prevchar != '?')
6558 : : {
2489 tgl@sss.pgh.pa.us 6559 : 28 : const char *dbname = ++p; /* advance past host terminator */
6560 : :
6561 : : /* Look for query parameters */
4386 alvherre@alvh.no-ip. 6562 [ + + + + ]: 66 : while (*p && *p != '?')
6563 : 38 : ++p;
6564 : :
6565 : 28 : prevchar = *p;
6566 : 28 : *p = '\0';
6567 : :
6568 : : /*
6569 : : * Avoid setting dbname to an empty string, as it forces the default
6570 : : * value (username) and ignores $PGDATABASE, as opposed to not setting
6571 : : * it at all.
6572 : : */
6573 [ + + - + ]: 45 : if (*dbname &&
6574 : 17 : !conninfo_storeval(options, "dbname", dbname,
6575 : : errorMessage, false, true))
4386 alvherre@alvh.no-ip. 6576 :UBC 0 : goto cleanup;
6577 : : }
6578 : :
4386 alvherre@alvh.no-ip. 6579 [ + + ]:CBC 52 : if (prevchar)
6580 : : {
4326 bruce@momjian.us 6581 : 24 : ++p; /* advance past terminator */
6582 : :
4386 alvherre@alvh.no-ip. 6583 [ + + ]: 24 : if (!conninfo_uri_parse_params(p, options, errorMessage))
6584 : 6 : goto cleanup;
6585 : : }
6586 : :
6587 : : /* everything parsed okay */
6588 : 46 : retval = true;
6589 : :
6590 : 59 : cleanup:
2719 rhaas@postgresql.org 6591 : 59 : termPQExpBuffer(&hostbuf);
6592 : 59 : termPQExpBuffer(&portbuf);
668 peter@eisentraut.org 6593 : 59 : free(buf);
4386 alvherre@alvh.no-ip. 6594 : 59 : return retval;
6595 : : }
6596 : :
6597 : : /*
6598 : : * Connection URI parameters parser routine
6599 : : *
6600 : : * If successful, returns true while connOptions is filled with parsed
6601 : : * parameters. Otherwise, returns false and fills errorMessage appropriately.
6602 : : *
6603 : : * Destructively modifies 'params' buffer.
6604 : : */
6605 : : static bool
6606 : 24 : conninfo_uri_parse_params(char *params,
6607 : : PQconninfoOption *connOptions,
6608 : : PQExpBuffer errorMessage)
6609 : : {
6610 [ + + ]: 43 : while (*params)
6611 : : {
4326 bruce@momjian.us 6612 : 25 : char *keyword = params;
6613 : 25 : char *value = NULL;
6614 : 25 : char *p = params;
6615 : 25 : bool malloced = false;
6616 : : int oldmsglen;
6617 : :
6618 : : /*
6619 : : * Scan the params string for '=' and '&', marking the end of keyword
6620 : : * and value respectively.
6621 : : */
6622 : : for (;;)
6623 : : {
4386 alvherre@alvh.no-ip. 6624 [ + + ]: 409 : if (*p == '=')
6625 : : {
6626 : : /* Was there '=' already? */
6627 [ + + ]: 24 : if (value != NULL)
6628 : : {
516 peter@eisentraut.org 6629 : 1 : libpq_append_error(errorMessage,
6630 : : "extra key/value separator \"=\" in URI query parameter: \"%s\"",
6631 : : keyword);
4386 alvherre@alvh.no-ip. 6632 : 1 : return false;
6633 : : }
6634 : : /* Cut off keyword, advance to value */
3340 tgl@sss.pgh.pa.us 6635 : 23 : *p++ = '\0';
6636 : 23 : value = p;
6637 : : }
4386 alvherre@alvh.no-ip. 6638 [ + + + + ]: 385 : else if (*p == '&' || *p == '\0')
6639 : : {
6640 : : /*
6641 : : * If not at the end, cut off value and advance; leave p
6642 : : * pointing to start of the next parameter, if any.
6643 : : */
3340 tgl@sss.pgh.pa.us 6644 [ + + ]: 24 : if (*p != '\0')
6645 : 4 : *p++ = '\0';
6646 : : /* Was there '=' at all? */
4386 alvherre@alvh.no-ip. 6647 [ + + ]: 24 : if (value == NULL)
6648 : : {
516 peter@eisentraut.org 6649 : 2 : libpq_append_error(errorMessage,
6650 : : "missing key/value separator \"=\" in URI query parameter: \"%s\"",
6651 : : keyword);
4386 alvherre@alvh.no-ip. 6652 : 2 : return false;
6653 : : }
6654 : : /* Got keyword and value, go process them. */
6655 : 22 : break;
6656 : : }
6657 : : else
3340 tgl@sss.pgh.pa.us 6658 : 361 : ++p; /* Advance over all other bytes. */
6659 : : }
6660 : :
4339 peter_e@gmx.net 6661 : 22 : keyword = conninfo_uri_decode(keyword, errorMessage);
6662 [ - + ]: 22 : if (keyword == NULL)
6663 : : {
6664 : : /* conninfo_uri_decode already set an error message */
4339 peter_e@gmx.net 6665 :UBC 0 : return false;
6666 : : }
4339 peter_e@gmx.net 6667 :CBC 22 : value = conninfo_uri_decode(value, errorMessage);
6668 [ + + ]: 22 : if (value == NULL)
6669 : : {
6670 : : /* conninfo_uri_decode already set an error message */
6671 : 1 : free(keyword);
6672 : 1 : return false;
6673 : : }
6674 : 21 : malloced = true;
6675 : :
6676 : : /*
6677 : : * Special keyword handling for improved JDBC compatibility.
6678 : : */
4386 alvherre@alvh.no-ip. 6679 [ - + ]: 21 : if (strcmp(keyword, "ssl") == 0 &&
4386 alvherre@alvh.no-ip. 6680 [ # # ]:UBC 0 : strcmp(value, "true") == 0)
6681 : : {
4339 peter_e@gmx.net 6682 : 0 : free(keyword);
6683 : 0 : free(value);
6684 : 0 : malloced = false;
6685 : :
4386 alvherre@alvh.no-ip. 6686 : 0 : keyword = "sslmode";
6687 : 0 : value = "require";
6688 : : }
6689 : :
6690 : : /*
6691 : : * Store the value if the corresponding option exists; ignore
6692 : : * otherwise. At this point both keyword and value are not
6693 : : * URI-encoded.
6694 : : */
1189 tgl@sss.pgh.pa.us 6695 :CBC 21 : oldmsglen = errorMessage->len;
4386 alvherre@alvh.no-ip. 6696 [ + + ]: 21 : if (!conninfo_storeval(connOptions, keyword, value,
6697 : : errorMessage, true, false))
6698 : : {
6699 : : /* Insert generic message if conninfo_storeval didn't give one. */
1189 tgl@sss.pgh.pa.us 6700 [ + - ]: 2 : if (errorMessage->len == oldmsglen)
516 peter@eisentraut.org 6701 : 2 : libpq_append_error(errorMessage,
6702 : : "invalid URI query parameter: \"%s\"",
6703 : : keyword);
6704 : : /* And fail. */
4252 peter_e@gmx.net 6705 [ + - ]: 2 : if (malloced)
6706 : : {
6707 : 2 : free(keyword);
6708 : 2 : free(value);
6709 : : }
4328 rhaas@postgresql.org 6710 : 2 : return false;
6711 : : }
6712 : :
4339 peter_e@gmx.net 6713 [ + - ]: 19 : if (malloced)
6714 : : {
6715 : 19 : free(keyword);
6716 : 19 : free(value);
6717 : : }
6718 : :
6719 : : /* Proceed to next key=value pair, if any */
4386 alvherre@alvh.no-ip. 6720 : 19 : params = p;
6721 : : }
6722 : :
6723 : 18 : return true;
6724 : : }
6725 : :
6726 : : /*
6727 : : * Connection URI decoder routine
6728 : : *
6729 : : * If successful, returns the malloc'd decoded string.
6730 : : * If not successful, returns NULL and fills errorMessage accordingly.
6731 : : *
6732 : : * The string is decoded by replacing any percent-encoded tokens with
6733 : : * corresponding characters, while preserving any non-encoded characters. A
6734 : : * percent-encoded token is a character triplet: a percent sign, followed by a
6735 : : * pair of hexadecimal digits (0-9A-F), where lower- and upper-case letters are
6736 : : * treated identically.
6737 : : */
6738 : : static char *
6739 : 127 : conninfo_uri_decode(const char *str, PQExpBuffer errorMessage)
6740 : : {
6741 : : char *buf;
6742 : : char *p;
6743 : 127 : const char *q = str;
6744 : :
3428 heikki.linnakangas@i 6745 : 127 : buf = malloc(strlen(str) + 1);
4386 alvherre@alvh.no-ip. 6746 [ - + ]: 127 : if (buf == NULL)
6747 : : {
516 peter@eisentraut.org 6748 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
4386 alvherre@alvh.no-ip. 6749 : 0 : return NULL;
6750 : : }
3428 heikki.linnakangas@i 6751 :CBC 127 : p = buf;
6752 : :
6753 : : for (;;)
6754 : : {
4386 alvherre@alvh.no-ip. 6755 [ + + ]: 852 : if (*q != '%')
6756 : : {
6757 : : /* copy and check for NUL terminator */
6758 [ + + ]: 841 : if (!(*(p++) = *(q++)))
6759 : 122 : break;
6760 : : }
6761 : : else
6762 : : {
6763 : : int hi;
6764 : : int lo;
6765 : : int c;
6766 : :
4326 bruce@momjian.us 6767 : 11 : ++q; /* skip the percent sign itself */
6768 : :
6769 : : /*
6770 : : * Possible EOL will be caught by the first call to
6771 : : * get_hexdigit(), so we never dereference an invalid q pointer.
6772 : : */
4386 alvherre@alvh.no-ip. 6773 [ + + + + ]: 11 : if (!(get_hexdigit(*q++, &hi) && get_hexdigit(*q++, &lo)))
6774 : : {
516 peter@eisentraut.org 6775 : 4 : libpq_append_error(errorMessage,
6776 : : "invalid percent-encoded token: \"%s\"",
6777 : : str);
4386 alvherre@alvh.no-ip. 6778 : 4 : free(buf);
6779 : 5 : return NULL;
6780 : : }
6781 : :
6782 : 7 : c = (hi << 4) | lo;
6783 [ + + ]: 7 : if (c == 0)
6784 : : {
516 peter@eisentraut.org 6785 : 1 : libpq_append_error(errorMessage,
6786 : : "forbidden value %%00 in percent-encoded value: \"%s\"",
6787 : : str);
4386 alvherre@alvh.no-ip. 6788 : 1 : free(buf);
6789 : 1 : return NULL;
6790 : : }
6791 : 6 : *(p++) = c;
6792 : : }
6793 : : }
6794 : :
6795 : 122 : return buf;
6796 : : }
6797 : :
6798 : : /*
6799 : : * Convert hexadecimal digit character to its integer value.
6800 : : *
6801 : : * If successful, returns true and value is filled with digit's base 16 value.
6802 : : * If not successful, returns false.
6803 : : *
6804 : : * Lower- and upper-case letters in the range A-F are treated identically.
6805 : : */
6806 : : static bool
6807 : 19 : get_hexdigit(char digit, int *value)
6808 : : {
6809 [ + + + + ]: 19 : if ('0' <= digit && digit <= '9')
6810 : 11 : *value = digit - '0';
6811 [ + + + + ]: 8 : else if ('A' <= digit && digit <= 'F')
6812 : 3 : *value = digit - 'A' + 10;
6813 [ + + + + ]: 5 : else if ('a' <= digit && digit <= 'f')
6814 : 1 : *value = digit - 'a' + 10;
6815 : : else
6816 : 4 : return false;
6817 : :
6818 : 15 : return true;
6819 : : }
6820 : :
6821 : : /*
6822 : : * Find an option value corresponding to the keyword in the connOptions array.
6823 : : *
6824 : : * If successful, returns a pointer to the corresponding option's value.
6825 : : * If not successful, returns NULL.
6826 : : */
6827 : : static const char *
8800 tgl@sss.pgh.pa.us 6828 : 495697 : conninfo_getval(PQconninfoOption *connOptions,
6829 : : const char *keyword)
6830 : : {
6831 : : PQconninfoOption *option;
6832 : :
4386 alvherre@alvh.no-ip. 6833 : 495697 : option = conninfo_find(connOptions, keyword);
6834 : :
6835 [ + - ]: 495697 : return option ? option->val : NULL;
6836 : : }
6837 : :
6838 : : /*
6839 : : * Store a (new) value for an option corresponding to the keyword in
6840 : : * connOptions array.
6841 : : *
6842 : : * If uri_decode is true, the value is URI-decoded. The keyword is always
6843 : : * assumed to be non URI-encoded.
6844 : : *
6845 : : * If successful, returns a pointer to the corresponding PQconninfoOption,
6846 : : * which value is replaced with a strdup'd copy of the passed value string.
6847 : : * The existing value for the option is free'd before replacing, if any.
6848 : : *
6849 : : * If not successful, returns NULL and fills errorMessage accordingly.
6850 : : * However, if the reason of failure is an invalid keyword being passed and
6851 : : * ignoreMissing is true, errorMessage will be left untouched.
6852 : : */
6853 : : static PQconninfoOption *
6854 : 37913 : conninfo_storeval(PQconninfoOption *connOptions,
6855 : : const char *keyword, const char *value,
6856 : : PQExpBuffer errorMessage, bool ignoreMissing,
6857 : : bool uri_decode)
6858 : : {
6859 : : PQconninfoOption *option;
6860 : : char *value_copy;
6861 : :
6862 : : /*
6863 : : * For backwards compatibility, requiressl=1 gets translated to
6864 : : * sslmode=require, and requiressl=0 gets translated to sslmode=prefer
6865 : : * (which is the default for sslmode).
6866 : : */
4153 magnus@hagander.net 6867 [ - + ]: 37913 : if (strcmp(keyword, "requiressl") == 0)
6868 : : {
4153 magnus@hagander.net 6869 :UBC 0 : keyword = "sslmode";
6870 [ # # ]: 0 : if (value[0] == '1')
6871 : 0 : value = "require";
6872 : : else
6873 : 0 : value = "prefer";
6874 : : }
6875 : :
4339 peter_e@gmx.net 6876 :CBC 37913 : option = conninfo_find(connOptions, keyword);
4386 alvherre@alvh.no-ip. 6877 [ + + ]: 37913 : if (option == NULL)
6878 : : {
6879 [ + + ]: 5 : if (!ignoreMissing)
516 peter@eisentraut.org 6880 : 3 : libpq_append_error(errorMessage,
6881 : : "invalid connection option \"%s\"",
6882 : : keyword);
4339 peter_e@gmx.net 6883 : 5 : return NULL;
6884 : : }
6885 : :
4386 alvherre@alvh.no-ip. 6886 [ + + ]: 37908 : if (uri_decode)
6887 : : {
6888 : 83 : value_copy = conninfo_uri_decode(value, errorMessage);
6889 [ + + ]: 83 : if (value_copy == NULL)
6890 : : /* conninfo_uri_decode already set an error message */
4339 peter_e@gmx.net 6891 : 4 : return NULL;
6892 : : }
6893 : : else
6894 : : {
4386 alvherre@alvh.no-ip. 6895 : 37825 : value_copy = strdup(value);
6896 [ - + ]: 37825 : if (value_copy == NULL)
6897 : : {
516 peter@eisentraut.org 6898 :UBC 0 : libpq_append_error(errorMessage, "out of memory");
4339 peter_e@gmx.net 6899 : 0 : return NULL;
6900 : : }
6901 : : }
6902 : :
668 peter@eisentraut.org 6903 :CBC 37904 : free(option->val);
4386 alvherre@alvh.no-ip. 6904 : 37904 : option->val = value_copy;
6905 : :
6906 : 37904 : return option;
6907 : : }
6908 : :
6909 : : /*
6910 : : * Find a PQconninfoOption option corresponding to the keyword in the
6911 : : * connOptions array.
6912 : : *
6913 : : * If successful, returns a pointer to the corresponding PQconninfoOption
6914 : : * structure.
6915 : : * If not successful, returns NULL.
6916 : : */
6917 : : static PQconninfoOption *
6918 : 533610 : conninfo_find(PQconninfoOption *connOptions, const char *keyword)
6919 : : {
6920 : : PQconninfoOption *option;
6921 : :
8800 tgl@sss.pgh.pa.us 6922 [ + + ]: 10837949 : for (option = connOptions; option->keyword != NULL; option++)
6923 : : {
6924 [ + + ]: 10837944 : if (strcmp(option->keyword, keyword) == 0)
4386 alvherre@alvh.no-ip. 6925 : 533605 : return option;
6926 : : }
6927 : :
9716 bruce@momjian.us 6928 : 5 : return NULL;
6929 : : }
6930 : :
6931 : :
6932 : : /*
6933 : : * Return the connection options used for the connection
6934 : : */
6935 : : PQconninfoOption *
4153 magnus@hagander.net 6936 : 292 : PQconninfo(PGconn *conn)
6937 : : {
6938 : : PQExpBufferData errorBuf;
6939 : : PQconninfoOption *connOptions;
6940 : :
6941 [ - + ]: 292 : if (conn == NULL)
4153 magnus@hagander.net 6942 :UBC 0 : return NULL;
6943 : :
6944 : : /*
6945 : : * We don't actually report any errors here, but callees want a buffer,
6946 : : * and we prefer not to trash the conn's errorMessage.
6947 : : */
4153 magnus@hagander.net 6948 :CBC 292 : initPQExpBuffer(&errorBuf);
6949 [ - + ]: 292 : if (PQExpBufferDataBroken(errorBuf))
4153 magnus@hagander.net 6950 :UBC 0 : return NULL; /* out of memory already :-( */
6951 : :
4153 magnus@hagander.net 6952 :CBC 292 : connOptions = conninfo_init(&errorBuf);
6953 : :
6954 [ + - ]: 292 : if (connOptions != NULL)
6955 : : {
6956 : : const internalPQconninfoOption *option;
6957 : :
6958 [ + + ]: 12264 : for (option = PQconninfoOptions; option->keyword; option++)
6959 : : {
6960 : : char **connmember;
6961 : :
6962 [ + + ]: 11972 : if (option->connofs < 0)
6963 : 292 : continue;
6964 : :
6965 : 11680 : connmember = (char **) ((char *) conn + option->connofs);
6966 : :
6967 [ + + ]: 11680 : if (*connmember)
6968 : 5857 : conninfo_storeval(connOptions, option->keyword, *connmember,
6969 : : &errorBuf, true, false);
6970 : : }
6971 : : }
6972 : :
6973 : 292 : termPQExpBuffer(&errorBuf);
6974 : :
6975 : 292 : return connOptions;
6976 : : }
6977 : :
6978 : :
6979 : : void
8800 tgl@sss.pgh.pa.us 6980 : 33594 : PQconninfoFree(PQconninfoOption *connOptions)
6981 : : {
6982 [ + + ]: 33594 : if (connOptions == NULL)
6983 : 11840 : return;
6984 : :
668 peter@eisentraut.org 6985 [ + + ]: 913668 : for (PQconninfoOption *option = connOptions; option->keyword != NULL; option++)
6986 : 891914 : free(option->val);
8800 tgl@sss.pgh.pa.us 6987 : 21754 : free(connOptions);
6988 : : }
6989 : :
6990 : :
6991 : : /* =========== accessor functions for PGconn ========= */
6992 : : char *
8921 bruce@momjian.us 6993 : 16825 : PQdb(const PGconn *conn)
6994 : : {
9716 6995 [ + + ]: 16825 : if (!conn)
7403 neilc@samurai.com 6996 : 1 : return NULL;
9716 bruce@momjian.us 6997 : 16824 : return conn->dbName;
6998 : : }
6999 : :
7000 : : char *
8921 7001 : 8120 : PQuser(const PGconn *conn)
7002 : : {
9716 7003 [ - + ]: 8120 : if (!conn)
7403 neilc@samurai.com 7004 :UBC 0 : return NULL;
9716 bruce@momjian.us 7005 :CBC 8120 : return conn->pguser;
7006 : : }
7007 : :
7008 : : char *
8921 7009 : 245 : PQpass(const PGconn *conn)
7010 : : {
2524 7011 : 245 : char *password = NULL;
7012 : :
9355 7013 [ - + ]: 245 : if (!conn)
7403 neilc@samurai.com 7014 :UBC 0 : return NULL;
2719 rhaas@postgresql.org 7015 [ + - ]:CBC 245 : if (conn->connhost != NULL)
7016 : 245 : password = conn->connhost[conn->whichhost].password;
7017 [ + + ]: 245 : if (password == NULL)
7018 : 243 : password = conn->pgpass;
7019 : : /* Historically we've returned "" not NULL for no password specified */
2637 tgl@sss.pgh.pa.us 7020 [ + + ]: 245 : if (password == NULL)
7021 : 183 : password = "";
2719 rhaas@postgresql.org 7022 : 245 : return password;
7023 : : }
7024 : :
7025 : : char *
8921 bruce@momjian.us 7026 : 8507 : PQhost(const PGconn *conn)
7027 : : {
9716 7028 [ - + ]: 8507 : if (!conn)
7403 neilc@samurai.com 7029 :UBC 0 : return NULL;
7030 : :
2210 peter_e@gmx.net 7031 [ + - ]:CBC 8507 : if (conn->connhost != NULL)
7032 : : {
7033 : : /*
7034 : : * Return the verbatim host value provided by user, or hostaddr in its
7035 : : * lack.
7036 : : */
7037 [ + - ]: 8507 : if (conn->connhost[conn->whichhost].host != NULL &&
7038 [ + - ]: 8507 : conn->connhost[conn->whichhost].host[0] != '\0')
7039 : 8507 : return conn->connhost[conn->whichhost].host;
2210 peter_e@gmx.net 7040 [ # # ]:UBC 0 : else if (conn->connhost[conn->whichhost].hostaddr != NULL &&
7041 [ # # ]: 0 : conn->connhost[conn->whichhost].hostaddr[0] != '\0')
7042 : 0 : return conn->connhost[conn->whichhost].hostaddr;
7043 : : }
7044 : :
7045 : 0 : return "";
7046 : : }
7047 : :
7048 : : char *
1973 alvherre@alvh.no-ip. 7049 : 0 : PQhostaddr(const PGconn *conn)
7050 : : {
7051 [ # # ]: 0 : if (!conn)
7052 : 0 : return NULL;
7053 : :
7054 : : /* Return the parsed IP address */
1766 7055 [ # # # # ]: 0 : if (conn->connhost != NULL && conn->connip != NULL)
7056 : 0 : return conn->connip;
7057 : :
1973 7058 : 0 : return "";
7059 : : }
7060 : :
7061 : : char *
8921 bruce@momjian.us 7062 :CBC 8262 : PQport(const PGconn *conn)
7063 : : {
9716 7064 [ - + ]: 8262 : if (!conn)
7403 neilc@samurai.com 7065 :UBC 0 : return NULL;
7066 : :
2719 rhaas@postgresql.org 7067 [ + - ]:CBC 8262 : if (conn->connhost != NULL)
7068 : 8262 : return conn->connhost[conn->whichhost].port;
7069 : :
2210 peter_e@gmx.net 7070 :UBC 0 : return "";
7071 : : }
7072 : :
7073 : : /*
7074 : : * No longer does anything, but the function remains for API backwards
7075 : : * compatibility.
7076 : : */
7077 : : char *
8921 bruce@momjian.us 7078 : 0 : PQtty(const PGconn *conn)
7079 : : {
9716 7080 [ # # ]: 0 : if (!conn)
7403 neilc@samurai.com 7081 : 0 : return NULL;
1132 peter@eisentraut.org 7082 : 0 : return "";
7083 : : }
7084 : :
7085 : : char *
8921 bruce@momjian.us 7086 : 0 : PQoptions(const PGconn *conn)
7087 : : {
9716 7088 [ # # ]: 0 : if (!conn)
7403 neilc@samurai.com 7089 : 0 : return NULL;
9355 bruce@momjian.us 7090 : 0 : return conn->pgoptions;
7091 : : }
7092 : :
7093 : : ConnStatusType
8921 bruce@momjian.us 7094 :CBC 213285 : PQstatus(const PGconn *conn)
7095 : : {
9716 7096 [ - + ]: 213285 : if (!conn)
9716 bruce@momjian.us 7097 :UBC 0 : return CONNECTION_BAD;
9716 bruce@momjian.us 7098 :CBC 213285 : return conn->status;
7099 : : }
7100 : :
7101 : : PGTransactionStatusType
7603 tgl@sss.pgh.pa.us 7102 : 172201 : PQtransactionStatus(const PGconn *conn)
7103 : : {
7104 [ + - - + ]: 172201 : if (!conn || conn->status != CONNECTION_OK)
7603 tgl@sss.pgh.pa.us 7105 :UBC 0 : return PQTRANS_UNKNOWN;
7603 tgl@sss.pgh.pa.us 7106 [ + + ]:CBC 172201 : if (conn->asyncStatus != PGASYNC_IDLE)
7107 : 2 : return PQTRANS_ACTIVE;
7108 : 172199 : return conn->xactStatus;
7109 : : }
7110 : :
7111 : : const char *
7112 : 316291 : PQparameterStatus(const PGconn *conn, const char *paramName)
7113 : : {
7114 : : const pgParameterStatus *pstatus;
7115 : :
7116 [ + - - + ]: 316291 : if (!conn || !paramName)
7603 tgl@sss.pgh.pa.us 7117 :UBC 0 : return NULL;
7603 tgl@sss.pgh.pa.us 7118 [ + - ]:CBC 1622658 : for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next)
7119 : : {
7120 [ + + ]: 1622658 : if (strcmp(pstatus->name, paramName) == 0)
7121 : 316291 : return pstatus->value;
7122 : : }
7603 tgl@sss.pgh.pa.us 7123 :UBC 0 : return NULL;
7124 : : }
7125 : :
7126 : : int
7127 : 0 : PQprotocolVersion(const PGconn *conn)
7128 : : {
7129 [ # # ]: 0 : if (!conn)
7130 : 0 : return 0;
7131 [ # # ]: 0 : if (conn->status == CONNECTION_BAD)
7132 : 0 : return 0;
7133 : 0 : return PG_PROTOCOL_MAJOR(conn->pversion);
7134 : : }
7135 : :
7136 : : int
7186 tgl@sss.pgh.pa.us 7137 :CBC 21657 : PQserverVersion(const PGconn *conn)
7138 : : {
7139 [ - + ]: 21657 : if (!conn)
7186 tgl@sss.pgh.pa.us 7140 :UBC 0 : return 0;
7186 tgl@sss.pgh.pa.us 7141 [ - + ]:CBC 21657 : if (conn->status == CONNECTION_BAD)
7186 tgl@sss.pgh.pa.us 7142 :UBC 0 : return 0;
7186 tgl@sss.pgh.pa.us 7143 :CBC 21657 : return conn->sversion;
7144 : : }
7145 : :
7146 : : char *
8921 bruce@momjian.us 7147 : 810 : PQerrorMessage(const PGconn *conn)
7148 : : {
9716 7149 [ - + ]: 810 : if (!conn)
8309 peter_e@gmx.net 7150 :UBC 0 : return libpq_gettext("connection pointer is NULL\n");
7151 : :
7152 : : /*
7153 : : * The errorMessage buffer might be marked "broken" due to having
7154 : : * previously failed to allocate enough memory for the message. In that
7155 : : * case, tell the application we ran out of memory.
7156 : : */
990 tgl@sss.pgh.pa.us 7157 [ + - - + ]:CBC 810 : if (PQExpBufferBroken(&conn->errorMessage))
990 tgl@sss.pgh.pa.us 7158 :UBC 0 : return libpq_gettext("out of memory\n");
7159 : :
8993 tgl@sss.pgh.pa.us 7160 :CBC 810 : return conn->errorMessage.data;
7161 : : }
7162 : :
7163 : : /*
7164 : : * In Windows, socket values are unsigned, and an invalid socket value
7165 : : * (INVALID_SOCKET) is ~0, which equals -1 in comparisons (with no compiler
7166 : : * warning). Ideally we would return an unsigned value for PQsocket() on
7167 : : * Windows, but that would cause the function's return value to differ from
7168 : : * Unix, so we just return -1 for invalid sockets.
7169 : : * http://msdn.microsoft.com/en-us/library/windows/desktop/cc507522%28v=vs.85%29.aspx
7170 : : * http://stackoverflow.com/questions/10817252/why-is-invalid-socket-defined-as-0-in-winsock2-h-c
7171 : : */
7172 : : int
8921 bruce@momjian.us 7173 : 302785 : PQsocket(const PGconn *conn)
7174 : : {
9475 7175 [ - + ]: 302785 : if (!conn)
9475 bruce@momjian.us 7176 :UBC 0 : return -1;
3651 bruce@momjian.us 7177 :CBC 302785 : return (conn->sock != PGINVALID_SOCKET) ? conn->sock : -1;
7178 : : }
7179 : :
7180 : : int
8921 7181 : 694 : PQbackendPID(const PGconn *conn)
7182 : : {
9355 7183 [ + - - + ]: 694 : if (!conn || conn->status != CONNECTION_OK)
9355 bruce@momjian.us 7184 :UBC 0 : return 0;
9355 bruce@momjian.us 7185 :CBC 694 : return conn->be_pid;
7186 : : }
7187 : :
7188 : : PGpipelineStatus
1126 alvherre@alvh.no-ip. 7189 : 39449 : PQpipelineStatus(const PGconn *conn)
7190 : : {
7191 [ - + ]: 39449 : if (!conn)
1126 alvherre@alvh.no-ip. 7192 :UBC 0 : return PQ_PIPELINE_OFF;
7193 : :
1126 alvherre@alvh.no-ip. 7194 :CBC 39449 : return conn->pipelineStatus;
7195 : : }
7196 : :
7197 : : int
5971 tgl@sss.pgh.pa.us 7198 : 245 : PQconnectionNeedsPassword(const PGconn *conn)
7199 : : {
7200 : : char *password;
7201 : :
7202 [ - + ]: 245 : if (!conn)
5971 tgl@sss.pgh.pa.us 7203 :UBC 0 : return false;
2719 rhaas@postgresql.org 7204 :CBC 245 : password = PQpass(conn);
5971 tgl@sss.pgh.pa.us 7205 [ + + + - ]: 245 : if (conn->password_needed &&
2719 rhaas@postgresql.org 7206 [ + + ]: 20 : (password == NULL || password[0] == '\0'))
5971 tgl@sss.pgh.pa.us 7207 : 1 : return true;
7208 : : else
7209 : 244 : return false;
7210 : : }
7211 : :
7212 : : int
6125 7213 : 277 : PQconnectionUsedPassword(const PGconn *conn)
7214 : : {
7215 [ - + ]: 277 : if (!conn)
6125 tgl@sss.pgh.pa.us 7216 :UBC 0 : return false;
5683 tgl@sss.pgh.pa.us 7217 [ + + ]:CBC 277 : if (conn->password_needed)
6125 7218 : 4 : return true;
7219 : : else
7220 : 273 : return false;
7221 : : }
7222 : :
7223 : : int
367 sfrost@snowman.net 7224 : 10 : PQconnectionUsedGSSAPI(const PGconn *conn)
7225 : : {
7226 [ - + ]: 10 : if (!conn)
367 sfrost@snowman.net 7227 :UBC 0 : return false;
367 sfrost@snowman.net 7228 [ + + ]:CBC 10 : if (conn->gssapi_used)
7229 : 4 : return true;
7230 : : else
7231 : 6 : return false;
7232 : : }
7233 : :
7234 : : int
8835 ishii@postgresql.org 7235 : 172239 : PQclientEncoding(const PGconn *conn)
7236 : : {
8856 7237 [ + - - + ]: 172239 : if (!conn || conn->status != CONNECTION_OK)
8856 ishii@postgresql.org 7238 :UBC 0 : return -1;
8856 ishii@postgresql.org 7239 :CBC 172239 : return conn->client_encoding;
7240 : : }
7241 : :
7242 : : int
8835 7243 : 20 : PQsetClientEncoding(PGconn *conn, const char *encoding)
7244 : : {
7245 : : char qbuf[128];
7246 : : static const char query[] = "set client_encoding to '%s'";
7247 : : PGresult *res;
7248 : : int status;
7249 : :
7250 [ + - - + ]: 20 : if (!conn || conn->status != CONNECTION_OK)
8835 ishii@postgresql.org 7251 :UBC 0 : return -1;
7252 : :
8821 ishii@postgresql.org 7253 [ - + ]:CBC 20 : if (!encoding)
8821 ishii@postgresql.org 7254 :UBC 0 : return -1;
7255 : :
7256 : : /* Resolve special "auto" value from the locale */
4803 peter_e@gmx.net 7257 [ - + ]:CBC 20 : if (strcmp(encoding, "auto") == 0)
4803 peter_e@gmx.net 7258 :UBC 0 : encoding = pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true));
7259 : :
7260 : : /* check query buffer overflow */
8835 ishii@postgresql.org 7261 [ - + ]:CBC 20 : if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
8835 ishii@postgresql.org 7262 :UBC 0 : return -1;
7263 : :
7264 : : /* ok, now send a query */
8835 ishii@postgresql.org 7265 :CBC 20 : sprintf(qbuf, query, encoding);
7266 : 20 : res = PQexec(conn, qbuf);
7267 : :
7403 neilc@samurai.com 7268 [ - + ]: 20 : if (res == NULL)
8835 ishii@postgresql.org 7269 :UBC 0 : return -1;
8835 ishii@postgresql.org 7270 [ - + ]:CBC 20 : if (res->resultStatus != PGRES_COMMAND_OK)
8835 ishii@postgresql.org 7271 :UBC 0 : status = -1;
7272 : : else
7273 : : {
7274 : : /*
7275 : : * We rely on the backend to report the parameter value, and we'll
7276 : : * change state at that time.
7277 : : */
8768 bruce@momjian.us 7278 :CBC 20 : status = 0; /* everything is ok */
7279 : : }
8835 ishii@postgresql.org 7280 : 20 : PQclear(res);
6668 neilc@samurai.com 7281 : 20 : return status;
7282 : : }
7283 : :
7284 : : PGVerbosity
7603 tgl@sss.pgh.pa.us 7285 : 8201 : PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
7286 : : {
7287 : : PGVerbosity old;
7288 : :
7289 [ - + ]: 8201 : if (!conn)
7603 tgl@sss.pgh.pa.us 7290 :UBC 0 : return PQERRORS_DEFAULT;
7603 tgl@sss.pgh.pa.us 7291 :CBC 8201 : old = conn->verbosity;
7292 : 8201 : conn->verbosity = verbosity;
7293 : 8201 : return old;
7294 : : }
7295 : :
7296 : : PGContextVisibility
3144 7297 : 8135 : PQsetErrorContextVisibility(PGconn *conn, PGContextVisibility show_context)
7298 : : {
7299 : : PGContextVisibility old;
7300 : :
7301 [ - + ]: 8135 : if (!conn)
3144 tgl@sss.pgh.pa.us 7302 :UBC 0 : return PQSHOW_CONTEXT_ERRORS;
3144 tgl@sss.pgh.pa.us 7303 :CBC 8135 : old = conn->show_context;
7304 : 8135 : conn->show_context = show_context;
7305 : 8135 : return old;
7306 : : }
7307 : :
7308 : : PQnoticeReceiver
7603 7309 : 127 : PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
7310 : : {
7311 : : PQnoticeReceiver old;
7312 : :
7313 [ - + ]: 127 : if (conn == NULL)
7603 tgl@sss.pgh.pa.us 7314 :UBC 0 : return NULL;
7315 : :
7603 tgl@sss.pgh.pa.us 7316 :CBC 127 : old = conn->noticeHooks.noticeRec;
7317 [ + - ]: 127 : if (proc)
7318 : : {
7319 : 127 : conn->noticeHooks.noticeRec = proc;
7320 : 127 : conn->noticeHooks.noticeRecArg = arg;
7321 : : }
7322 : 127 : return old;
7323 : : }
7324 : :
7325 : : PQnoticeProcessor
9357 bruce@momjian.us 7326 : 8832 : PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
7327 : : {
7328 : : PQnoticeProcessor old;
7329 : :
9380 7330 [ - + ]: 8832 : if (conn == NULL)
8937 bruce@momjian.us 7331 :UBC 0 : return NULL;
7332 : :
7603 tgl@sss.pgh.pa.us 7333 :CBC 8832 : old = conn->noticeHooks.noticeProc;
8800 7334 [ + - ]: 8832 : if (proc)
7335 : : {
7603 7336 : 8832 : conn->noticeHooks.noticeProc = proc;
7337 : 8832 : conn->noticeHooks.noticeProcArg = arg;
7338 : : }
8937 bruce@momjian.us 7339 : 8832 : return old;
7340 : : }
7341 : :
7342 : : /*
7343 : : * The default notice message receiver just gets the standard notice text
7344 : : * and sends it to the notice processor. This two-level setup exists
7345 : : * mostly for backwards compatibility; perhaps we should deprecate use of
7346 : : * PQsetNoticeProcessor?
7347 : : */
7348 : : static void
7603 tgl@sss.pgh.pa.us 7349 : 77583 : defaultNoticeReceiver(void *arg, const PGresult *res)
7350 : : {
7351 : : (void) arg; /* not used */
7601 7352 [ + - ]: 77583 : if (res->noticeHooks.noticeProc != NULL)
2411 peter_e@gmx.net 7353 : 77583 : res->noticeHooks.noticeProc(res->noticeHooks.noticeProcArg,
7354 : 77583 : PQresultErrorMessage(res));
7603 tgl@sss.pgh.pa.us 7355 : 77583 : }
7356 : :
7357 : : /*
7358 : : * The default notice message processor just prints the
7359 : : * message on stderr. Applications can override this if they
7360 : : * want the messages to go elsewhere (a window, for example).
7361 : : * Note that simply discarding notices is probably a bad idea.
7362 : : */
7363 : : static void
9357 bruce@momjian.us 7364 : 66 : defaultNoticeProcessor(void *arg, const char *message)
7365 : : {
7366 : : (void) arg; /* not used */
7367 : : /* Note: we expect the supplied string to end with a newline already. */
9380 7368 : 66 : fprintf(stderr, "%s", message);
7369 : 66 : }
7370 : :
7371 : : /*
7372 : : * returns a pointer to the next token or NULL if the current
7373 : : * token doesn't match
7374 : : */
7375 : : static char *
2357 peter_e@gmx.net 7376 : 54 : pwdfMatchesString(char *buf, const char *token)
7377 : : {
7378 : : char *tbuf;
7379 : : const char *ttok;
7893 bruce@momjian.us 7380 : 54 : bool bslash = false;
7381 : :
7913 7382 [ + - - + ]: 54 : if (buf == NULL || token == NULL)
7913 bruce@momjian.us 7383 :UBC 0 : return NULL;
7913 bruce@momjian.us 7384 :CBC 54 : tbuf = buf;
7385 : 54 : ttok = token;
5445 tgl@sss.pgh.pa.us 7386 [ + + + - ]: 54 : if (tbuf[0] == '*' && tbuf[1] == ':')
7913 bruce@momjian.us 7387 : 36 : return tbuf + 2;
7388 [ + - ]: 146 : while (*tbuf != 0)
7389 : : {
7390 [ - + - - ]: 146 : if (*tbuf == '\\' && !bslash)
7391 : : {
7913 bruce@momjian.us 7392 :UBC 0 : tbuf++;
7393 : 0 : bslash = true;
7394 : : }
7913 bruce@momjian.us 7395 [ + + + - :CBC 146 : if (*tbuf == ':' && *ttok == 0 && !bslash)
+ - ]
7893 7396 : 13 : return tbuf + 1;
7913 7397 : 133 : bslash = false;
7398 [ - + ]: 133 : if (*ttok == 0)
7913 bruce@momjian.us 7399 :UBC 0 : return NULL;
7913 bruce@momjian.us 7400 [ + + ]:CBC 133 : if (*tbuf == *ttok)
7401 : : {
7402 : 128 : tbuf++;
7403 : 128 : ttok++;
7404 : : }
7405 : : else
7406 : 5 : return NULL;
7407 : : }
7913 bruce@momjian.us 7408 :UBC 0 : return NULL;
7409 : : }
7410 : :
7411 : : /* Get a password from the password file. Return value is malloc'd. */
7412 : : static char *
2357 peter_e@gmx.net 7413 :CBC 12079 : passwordFromFile(const char *hostname, const char *port, const char *dbname,
7414 : : const char *username, const char *pgpassfile)
7415 : : {
7416 : : FILE *fp;
7417 : : struct stat stat_buf;
7418 : : PQExpBufferData buf;
7419 : :
2083 tgl@sss.pgh.pa.us 7420 [ + - - + ]: 12079 : if (dbname == NULL || dbname[0] == '\0')
7913 bruce@momjian.us 7421 :UBC 0 : return NULL;
7422 : :
2083 tgl@sss.pgh.pa.us 7423 [ + - - + ]:CBC 12079 : if (username == NULL || username[0] == '\0')
7913 bruce@momjian.us 7424 :UBC 0 : return NULL;
7425 : :
7426 : : /* 'localhost' matches pghost of '' or the default socket directory */
2083 tgl@sss.pgh.pa.us 7427 [ + - - + ]:CBC 12079 : if (hostname == NULL || hostname[0] == '\0')
7913 bruce@momjian.us 7428 :UBC 0 : hostname = DefaultHost;
1236 peter@eisentraut.org 7429 [ + + ]:CBC 12079 : else if (is_unixsock_path(hostname))
7430 : :
7431 : : /*
7432 : : * We should probably use canonicalize_path(), but then we have to
7433 : : * bring path.c into libpq, and it doesn't seem worth it.
7434 : : */
6541 bruce@momjian.us 7435 [ - + ]: 11506 : if (strcmp(hostname, DEFAULT_PGSOCKET_DIR) == 0)
6542 bruce@momjian.us 7436 :UBC 0 : hostname = DefaultHost;
7437 : :
2083 tgl@sss.pgh.pa.us 7438 [ + - - + ]:CBC 12079 : if (port == NULL || port[0] == '\0')
7913 bruce@momjian.us 7439 :UBC 0 : port = DEF_PGPORT_STR;
7440 : :
7441 : : /* If password file cannot be opened, ignore it. */
5858 tgl@sss.pgh.pa.us 7442 [ - + ]:CBC 12079 : if (stat(pgpassfile, &stat_buf) != 0)
7899 bruce@momjian.us 7443 :UBC 0 : return NULL;
7444 : :
7445 : : #ifndef WIN32
6883 bruce@momjian.us 7446 [ - + ]:CBC 12079 : if (!S_ISREG(stat_buf.st_mode))
7447 : : {
6883 bruce@momjian.us 7448 :UBC 0 : fprintf(stderr,
2489 tgl@sss.pgh.pa.us 7449 : 0 : libpq_gettext("WARNING: password file \"%s\" is not a plain file\n"),
7450 : : pgpassfile);
6883 bruce@momjian.us 7451 : 0 : return NULL;
7452 : : }
7453 : :
7454 : : /* If password file is insecure, alert the user and ignore it. */
7899 bruce@momjian.us 7455 [ - + ]:CBC 12079 : if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
7456 : : {
7899 bruce@momjian.us 7457 :UBC 0 : fprintf(stderr,
5858 tgl@sss.pgh.pa.us 7458 : 0 : libpq_gettext("WARNING: password file \"%s\" has group or world access; permissions should be u=rw (0600) or less\n"),
7459 : : pgpassfile);
7899 bruce@momjian.us 7460 : 0 : return NULL;
7461 : : }
7462 : : #else
7463 : :
7464 : : /*
7465 : : * On Win32, the directory is protected, so we don't have to check the
7466 : : * file.
7467 : : */
7468 : : #endif
7469 : :
7892 bruce@momjian.us 7470 :CBC 12079 : fp = fopen(pgpassfile, "r");
7913 7471 [ - + ]: 12079 : if (fp == NULL)
7913 bruce@momjian.us 7472 :UBC 0 : return NULL;
7473 : :
7474 : : /* Use an expansible buffer to accommodate any reasonable line length */
1321 tgl@sss.pgh.pa.us 7475 :CBC 12079 : initPQExpBuffer(&buf);
7476 : :
5156 7477 [ + - + - ]: 12111 : while (!feof(fp) && !ferror(fp))
7478 : : {
7479 : : /* Make sure there's a reasonable amount of room in the buffer */
1321 7480 [ - + ]: 12111 : if (!enlargePQExpBuffer(&buf, 128))
1321 tgl@sss.pgh.pa.us 7481 :UBC 0 : break;
7482 : :
7483 : : /* Read some data, appending it to what we already have */
1321 tgl@sss.pgh.pa.us 7484 [ + + ]:CBC 12111 : if (fgets(buf.data + buf.len, buf.maxlen - buf.len, fp) == NULL)
5098 7485 : 12070 : break;
1321 7486 : 41 : buf.len += strlen(buf.data + buf.len);
7487 : :
7488 : : /* If we don't yet have a whole line, loop around to read more */
7489 [ + - + + : 41 : if (!(buf.len > 0 && buf.data[buf.len - 1] == '\n') && !feof(fp))
+ + ]
7490 : 8 : continue;
7491 : :
7492 : : /* ignore comments */
7493 [ + + ]: 33 : if (buf.data[0] != '#')
7494 : : {
7495 : 25 : char *t = buf.data;
7496 : : int len;
7497 : :
7498 : : /* strip trailing newline and carriage return */
7499 : 25 : len = pg_strip_crlf(t);
7500 : :
7501 [ + + + - ]: 39 : if (len > 0 &&
7502 [ + - ]: 28 : (t = pwdfMatchesString(t, hostname)) != NULL &&
7503 [ + + ]: 28 : (t = pwdfMatchesString(t, port)) != NULL &&
7504 [ + + ]: 26 : (t = pwdfMatchesString(t, dbname)) != NULL &&
7505 : 12 : (t = pwdfMatchesString(t, username)) != NULL)
7506 : : {
7507 : : /* Found a match. */
7508 : : char *ret,
7509 : : *p1,
7510 : : *p2;
7511 : :
7512 : 9 : ret = strdup(t);
7513 : :
7514 : 9 : fclose(fp);
7515 : 9 : explicit_bzero(buf.data, buf.maxlen);
7516 : 9 : termPQExpBuffer(&buf);
7517 : :
7518 [ - + ]: 9 : if (!ret)
7519 : : {
7520 : : /* Out of memory. XXX: an error message would be nice. */
1321 tgl@sss.pgh.pa.us 7521 :UBC 0 : return NULL;
7522 : : }
7523 : :
7524 : : /* De-escape password. */
1321 tgl@sss.pgh.pa.us 7525 [ + + + + ]:CBC 49 : for (p1 = p2 = ret; *p1 != ':' && *p1 != '\0'; ++p1, ++p2)
7526 : : {
7527 [ + + + - ]: 40 : if (*p1 == '\\' && p1[1] != '\0')
7528 : 3 : ++p1;
7529 : 40 : *p2 = *p1;
7530 : : }
7531 : 9 : *p2 = '\0';
7532 : :
7533 : 9 : return ret;
7534 : : }
7535 : : }
7536 : :
7537 : : /* No match, reset buffer to prepare for next line. */
7538 : 24 : buf.len = 0;
7539 : : }
7540 : :
7913 bruce@momjian.us 7541 : 12070 : fclose(fp);
1321 tgl@sss.pgh.pa.us 7542 : 12070 : explicit_bzero(buf.data, buf.maxlen);
7543 : 12070 : termPQExpBuffer(&buf);
7913 bruce@momjian.us 7544 : 12070 : return NULL;
7545 : : }
7546 : :
7547 : :
7548 : : /*
7549 : : * If the connection failed due to bad password, we should mention
7550 : : * if we got the password from the pgpassfile.
7551 : : */
7552 : : static void
2637 tgl@sss.pgh.pa.us 7553 : 181 : pgpassfileWarning(PGconn *conn)
7554 : : {
7555 : : /* If it was 'invalid authorization', add pgpassfile mention */
7556 : : /* only works with >= 9.0 servers */
2078 7557 [ + + ]: 181 : if (conn->password_needed &&
7558 [ - + ]: 19 : conn->connhost[conn->whichhost].password != NULL &&
2078 tgl@sss.pgh.pa.us 7559 [ # # ]:UBC 0 : conn->result)
7560 : : {
2628 7561 : 0 : const char *sqlstate = PQresultErrorField(conn->result,
7562 : : PG_DIAG_SQLSTATE);
7563 : :
7564 [ # # # # ]: 0 : if (sqlstate && strcmp(sqlstate, ERRCODE_INVALID_PASSWORD) == 0)
516 peter@eisentraut.org 7565 : 0 : libpq_append_conn_error(conn, "password retrieved from file \"%s\"",
7566 : : conn->pgpassfile);
7567 : : }
5146 bruce@momjian.us 7568 :CBC 181 : }
7569 : :
7570 : : /*
7571 : : * Check if the SSL protocol value given in input is valid or not.
7572 : : * This is used as a sanity check routine for the connection parameters
7573 : : * ssl_min_protocol_version and ssl_max_protocol_version.
7574 : : */
7575 : : static bool
1538 michael@paquier.xyz 7576 : 48331 : sslVerifyProtocolVersion(const char *version)
7577 : : {
7578 : : /*
7579 : : * An empty string and a NULL value are considered valid as it is
7580 : : * equivalent to ignoring the parameter.
7581 : : */
7582 [ + + - + ]: 48331 : if (!version || strlen(version) == 0)
7583 : 24158 : return true;
7584 : :
7585 [ + - + + ]: 48346 : if (pg_strcasecmp(version, "TLSv1") == 0 ||
7586 [ + + ]: 48344 : pg_strcasecmp(version, "TLSv1.1") == 0 ||
7587 [ - + ]: 24173 : pg_strcasecmp(version, "TLSv1.2") == 0 ||
7588 : 2 : pg_strcasecmp(version, "TLSv1.3") == 0)
7589 : 24171 : return true;
7590 : :
7591 : : /* anything else is wrong */
7592 : 2 : return false;
7593 : : }
7594 : :
7595 : :
7596 : : /*
7597 : : * Ensure that the SSL protocol range given in input is correct. The check
7598 : : * is performed on the input string to keep it TLS backend agnostic. Input
7599 : : * to this function is expected verified with sslVerifyProtocolVersion().
7600 : : */
7601 : : static bool
7602 : 12082 : sslVerifyProtocolRange(const char *min, const char *max)
7603 : : {
7604 [ + - + - ]: 12082 : Assert(sslVerifyProtocolVersion(min) &&
7605 : : sslVerifyProtocolVersion(max));
7606 : :
7607 : : /* If at least one of the bounds is not set, the range is valid */
7608 [ + - + + : 12082 : if (min == NULL || max == NULL || strlen(min) == 0 || strlen(max) == 0)
+ - - + ]
7609 : 12079 : return true;
7610 : :
7611 : : /*
7612 : : * If the minimum version is the lowest one we accept, then all options
7613 : : * for the maximum are valid.
7614 : : */
7615 [ - + ]: 3 : if (pg_strcasecmp(min, "TLSv1") == 0)
1538 michael@paquier.xyz 7616 :UBC 0 : return true;
7617 : :
7618 : : /*
7619 : : * The minimum bound is valid, and cannot be TLSv1, so using TLSv1 for the
7620 : : * maximum is incorrect.
7621 : : */
1538 michael@paquier.xyz 7622 [ - + ]:CBC 3 : if (pg_strcasecmp(max, "TLSv1") == 0)
1538 michael@paquier.xyz 7623 :UBC 0 : return false;
7624 : :
7625 : : /*
7626 : : * At this point we know that we have a mix of TLSv1.1 through 1.3
7627 : : * versions.
7628 : : */
1538 michael@paquier.xyz 7629 [ + + ]:CBC 3 : if (pg_strcasecmp(min, max) > 0)
7630 : 1 : return false;
7631 : :
7632 : 2 : return true;
7633 : : }
7634 : :
7635 : :
7636 : : /*
7637 : : * Obtain user's home directory, return in given buffer
7638 : : *
7639 : : * On Unix, this actually returns the user's home directory. On Windows
7640 : : * it returns the PostgreSQL-specific application data folder.
7641 : : *
7642 : : * This is essentially the same as get_home_path(), but we don't use that
7643 : : * because we don't want to pull path.c into libpq (it pollutes application
7644 : : * namespace).
7645 : : *
7646 : : * Returns true on success, false on failure to obtain the directory name.
7647 : : *
7648 : : * CAUTION: although in most situations failure is unexpected, there are users
7649 : : * who like to run applications in a home-directory-less environment. On
7650 : : * failure, you almost certainly DO NOT want to report an error. Just act as
7651 : : * though whatever file you were hoping to find in the home directory isn't
7652 : : * there (which it isn't).
7653 : : */
7654 : : bool
7038 tgl@sss.pgh.pa.us 7655 : 11887 : pqGetHomeDirectory(char *buf, int bufsize)
7656 : : {
7657 : : #ifndef WIN32
7658 : : const char *home;
7659 : :
826 7660 : 11887 : home = getenv("HOME");
7661 [ + - - + ]: 11887 : if (home == NULL || home[0] == '\0')
824 tgl@sss.pgh.pa.us 7662 :UBC 0 : return pg_get_user_home_dir(geteuid(), buf, bufsize);
826 tgl@sss.pgh.pa.us 7663 :CBC 11887 : strlcpy(buf, home, bufsize);
7038 7664 : 11887 : return true;
7665 : : #else
7666 : : char tmppath[MAX_PATH];
7667 : :
7668 : : ZeroMemory(tmppath, sizeof(tmppath));
7669 : : if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, tmppath) != S_OK)
7670 : : return false;
7671 : : snprintf(buf, bufsize, "%s/postgresql", tmppath);
7672 : : return true;
7673 : : #endif
7674 : : }
7675 : :
7676 : : /*
7677 : : * Parse and try to interpret "value" as an integer value, and if successful,
7678 : : * store it in *result, complaining if there is any trailing garbage or an
7679 : : * overflow. This allows any number of leading and trailing whitespaces.
7680 : : */
7681 : : bool
76 alvherre@alvh.no-ip. 7682 :GNC 12096 : pqParseIntParam(const char *value, int *result, PGconn *conn,
7683 : : const char *context)
7684 : : {
7685 : : char *end;
7686 : : long numval;
7687 : :
7688 [ - + ]: 12096 : Assert(value != NULL);
7689 : :
7690 : 12096 : *result = 0;
7691 : :
7692 : : /* strtol(3) skips leading whitespaces */
7693 : 12096 : errno = 0;
7694 : 12096 : numval = strtol(value, &end, 10);
7695 : :
7696 : : /*
7697 : : * If no progress was done during the parsing or an error happened, fail.
7698 : : * This tests properly for overflows of the result.
7699 : : */
7700 [ + - + - : 12096 : if (value == end || errno != 0 || numval != (int) numval)
- + ]
76 alvherre@alvh.no-ip. 7701 :UNC 0 : goto error;
7702 : :
7703 : : /*
7704 : : * Skip any trailing whitespace; if anything but whitespace remains before
7705 : : * the terminating character, fail
7706 : : */
76 alvherre@alvh.no-ip. 7707 [ + + + - ]:GNC 12097 : while (*end != '\0' && isspace((unsigned char) *end))
7708 : 1 : end++;
7709 : :
7710 [ - + ]: 12096 : if (*end != '\0')
76 alvherre@alvh.no-ip. 7711 :UNC 0 : goto error;
7712 : :
76 alvherre@alvh.no-ip. 7713 :GNC 12096 : *result = numval;
7714 : 12096 : return true;
7715 : :
76 alvherre@alvh.no-ip. 7716 :UNC 0 : error:
7717 : 0 : libpq_append_conn_error(conn, "invalid integer value \"%s\" for connection option \"%s\"",
7718 : : value, context);
7719 : 0 : return false;
7720 : : }
7721 : :
7722 : : /*
7723 : : * To keep the API consistent, the locking stubs are always provided, even
7724 : : * if they are not required.
7725 : : *
7726 : : * Since we neglected to provide any error-return convention in the
7727 : : * pgthreadlock_t API, we can't do much except Assert upon failure of any
7728 : : * mutex primitive. Fortunately, such failures appear to be nonexistent in
7729 : : * the field.
7730 : : */
7731 : :
7732 : : static void
7326 bruce@momjian.us 7733 :CBC 46 : default_threadlock(int acquire)
7734 : : {
7735 : : static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER;
7736 : :
7737 [ + + ]: 46 : if (acquire)
7738 : : {
5812 magnus@hagander.net 7739 [ - + ]: 23 : if (pthread_mutex_lock(&singlethread_lock))
1020 tgl@sss.pgh.pa.us 7740 :UBC 0 : Assert(false);
7741 : : }
7742 : : else
7743 : : {
5812 magnus@hagander.net 7744 [ - + ]:CBC 23 : if (pthread_mutex_unlock(&singlethread_lock))
1020 tgl@sss.pgh.pa.us 7745 :UBC 0 : Assert(false);
7746 : : }
7326 bruce@momjian.us 7747 :CBC 46 : }
7748 : :
7749 : : pgthreadlock_t
7073 tgl@sss.pgh.pa.us 7750 :UBC 0 : PQregisterThreadLock(pgthreadlock_t newhandler)
7751 : : {
7752 : 0 : pgthreadlock_t prev = pg_g_threadlock;
7753 : :
7326 bruce@momjian.us 7754 [ # # ]: 0 : if (newhandler)
7073 tgl@sss.pgh.pa.us 7755 : 0 : pg_g_threadlock = newhandler;
7756 : : else
7757 : 0 : pg_g_threadlock = default_threadlock;
7758 : :
7326 bruce@momjian.us 7759 : 0 : return prev;
7760 : : }
|