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