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