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