postgresql/src/interfaces/libpq/fe-connect.c

3148 lines
73 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* fe-connect.c
* functions related to setting up a connection to the backend
*
2003-08-04 04:40:20 +02:00
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
2003-09-22 02:23:35 +02:00
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.261 2003/09/22 00:23:35 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres_fe.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
2002-08-18 02:06:01 +02:00
#include <time.h>
#ifndef HAVE_STRDUP
#include "strdup.h"
#endif
#include "libpq-fe.h"
#include "libpq-int.h"
#include "fe-auth.h"
1998-07-03 06:29:04 +02:00
#ifdef WIN32
#include "win32.h"
#else
#include <sys/socket.h>
1999-07-19 08:25:40 +02:00
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_NETINET_TCP_H
2001-03-22 05:01:46 +01:00
#include <netinet/tcp.h>
#endif
#include <arpa/inet.h>
1998-07-03 06:29:04 +02:00
#endif
#include "libpq/ip.h"
#include "mb/pg_wchar.h"
/* For FNCTL_NONBLOCK */
#if defined(WIN32) || defined(__BEOS__)
long ioctlsocket_ret=1;
#endif
#define PGPASSFILE ".pgpass"
/* fall back options if they are not specified by arguments or defined
by environment variables */
#define DefaultHost "localhost"
#define DefaultTty ""
#define DefaultOption ""
#define DefaultAuthtype ""
#define DefaultPassword ""
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
#ifdef USE_SSL
#define DefaultSSLMode "prefer"
#else
#define DefaultSSLMode "disable"
#endif
/* ----------
* Definition of the conninfo parameters and their fallback resources.
*
* If Environment-Var and Compiled-in are specified as NULL, no
* fallback is available. If after all no value can be determined
* for an option, an error is returned.
*
* The value for the username is treated specially in conninfo_parse.
* If the Compiled-in resource is specified as a NULL value, the
* user is determined by fe_getauthname().
*
* The Label and Disp-Char entries are provided for applications that
* want to use PQconndefaults() to create a generic database connection
* dialog. Disp-Char is defined as follows:
* "" Normal input field
* "*" Password field - hide value
* "D" Debug option - don't show by default
*
* PQconninfoOptions[] is a constant static array that we use to initialize
* a dynamically allocated working copy. All the "val" fields in
* PQconninfoOptions[] *must* be NULL. In a working copy, non-null "val"
* fields point to malloc'd strings that should be freed when the working
* array is freed (see PQconninfoFree).
* ----------
*/
static const PQconninfoOption PQconninfoOptions[] = {
/*
* "authtype" is no longer used, so mark it "don't show". We keep it
* in the array so as not to reject conninfo strings from old apps
* that might still try to set it.
*/
{"authtype", "PGAUTHTYPE", DefaultAuthtype, NULL,
"Database-Authtype", "D", 20},
{"service", "PGSERVICE", NULL, NULL,
2001-03-22 05:01:46 +01:00
"Database-Service", "", 20},
{"user", "PGUSER", NULL, NULL,
"Database-User", "", 20},
{"password", "PGPASSWORD", NULL, NULL,
"Database-Password", "*", 20},
{"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
"Connect-timeout", "", 10}, /* strlen(INT32_MAX) == 10 */
{"dbname", "PGDATABASE", NULL, NULL,
"Database-Name", "", 20},
{"host", "PGHOST", NULL, NULL,
"Database-Host", "", 40},
{"hostaddr", "PGHOSTADDR", NULL, NULL,
"Database-Host-IP-Address", "", 45},
{"port", "PGPORT", DEF_PGPORT_STR, NULL,
"Database-Port", "", 6},
/*
* "tty" is no longer used either, but keep it present for backwards
* compatibility.
*/
{"tty", "PGTTY", DefaultTty, NULL,
"Backend-Debug-TTY", "D", 40},
{"options", "PGOPTIONS", DefaultOption, NULL,
"Backend-Debug-Options", "D", 40},
2000-08-30 16:54:24 +02:00
#ifdef USE_SSL
2003-08-04 02:43:34 +02:00
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
/*
2003-08-04 02:43:34 +02:00
* "requiressl" is deprecated, its purpose having been taken over by
* "sslmode". It remains for backwards compatibility.
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
*/
2000-08-30 16:54:24 +02:00
{"requiressl", "PGREQUIRESSL", "0", NULL,
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
"Require-SSL", "D", 1},
2000-08-30 16:54:24 +02:00
#endif
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
/*
2003-08-04 02:43:34 +02:00
* "sslmode" option is allowed even without client SSL support because
* the client can still handle SSL modes "disable" and "allow".
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
*/
{"sslmode", "PGSSLMODE", DefaultSSLMode, NULL,
2003-08-04 02:43:34 +02:00
"SSL-Mode", "", 8}, /* sizeof("disable") == 8 */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
/* Terminating entry --- MUST BE LAST */
{NULL, NULL, NULL, NULL,
NULL, NULL, 0}
};
static const PQEnvironmentOption EnvironmentOptions[] =
{
/* common user-interface settings */
{
"PGDATESTYLE", "datestyle"
},
{
"PGTZ", "timezone"
},
{
"PGCLIENTENCODING", "client_encoding"
},
/* internal performance-related settings */
{
"PGGEQO", "geqo"
},
{
NULL, NULL
}
};
static bool connectOptions1(PGconn *conn, const char *conninfo);
static bool connectOptions2(PGconn *conn);
static int connectDBStart(PGconn *conn);
static int connectDBComplete(PGconn *conn);
static PGconn *makeEmptyPGconn(void);
static void freePGconn(PGconn *conn);
static void closePGconn(PGconn *conn);
static PQconninfoOption *conninfo_parse(const char *conninfo,
PQExpBuffer errorMessage);
static char *conninfo_getval(PQconninfoOption *connOptions,
const char *keyword);
static void defaultNoticeReceiver(void *arg, const PGresult *res);
static void defaultNoticeProcessor(void *arg, const char *message);
2001-03-22 05:01:46 +01:00
static int parseServiceInfo(PQconninfoOption *options,
PQExpBuffer errorMessage);
static char *pwdfMatchesString(char *buf, char *token);
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
2003-08-04 02:43:34 +02:00
char *username);
/*
* Connecting to a Database
*
* There are now four different ways a user of this API can connect to the
* database. Two are not recommended for use in new code, because of their
* lack of extensibility with respect to the passing of options to the
* backend. These are PQsetdb and PQsetdbLogin (the former now being a macro
* to the latter).
*
* If it is desired to connect in a synchronous (blocking) manner, use the
* function PQconnectdb.
*
* To connect in an asynchronous (non-blocking) manner, use the functions
* PQconnectStart, and PQconnectPoll.
*
* Internally, the static functions connectDBStart, connectDBComplete
* are part of the connection procedure.
*/
/*
* PQconnectdb
*
* establishes a connection to a postgres backend through the postmaster
* using connection information in a string.
*
* The conninfo string is a white-separated list of
*
* option = value
*
* definitions. Value might be a single value containing no whitespaces or
* a single quoted string. If a single quote should appear anywhere in
* the value, it must be escaped with a backslash like \'
*
* Returns a PGconn* which is needed for all subsequent libpq calls, or NULL
* if a memory allocation failed.
* If the status field of the connection returned is CONNECTION_BAD,
* then some fields may be null'ed out instead of having valid values.
*
* You should call PQfinish (if conn is not NULL) regardless of whether this
* call succeeded.
*/
PGconn *
PQconnectdb(const char *conninfo)
{
PGconn *conn = PQconnectStart(conninfo);
if (conn && conn->status != CONNECTION_BAD)
(void) connectDBComplete(conn);
return conn;
}
/*
* PQconnectStart
*
* Begins the establishment of a connection to a postgres backend through the
* postmaster using connection information in a string.
*
* See comment for PQconnectdb for the definition of the string format.
*
* Returns a PGconn*. If NULL is returned, a malloc error has occurred, and
* you should not attempt to proceed with this connection. If the status
* field of the connection returned is CONNECTION_BAD, an error has
* occurred. In this case you should call PQfinish on the result, (perhaps
* inspecting the error message first). Other fields of the structure may not
* be valid if that occurs. If the status field is not CONNECTION_BAD, then
* this stage has succeeded - call PQconnectPoll, using select(2) to see when
* this is necessary.
*
* See PQconnectPoll for more info.
*/
PGconn *
PQconnectStart(const char *conninfo)
{
PGconn *conn;
/*
* Allocate memory for the conn structure
*/
conn = makeEmptyPGconn();
if (conn == NULL)
return (PGconn *) NULL;
/*
* Parse the conninfo string
*/
if (!connectOptions1(conn, conninfo))
return conn;
/*
* Compute derived options
*/
if (!connectOptions2(conn))
return conn;
/*
* Connect to the database
*/
if (!connectDBStart(conn))
{
/* Just in case we failed to set it in connectDBStart */
conn->status = CONNECTION_BAD;
}
return conn;
}
/*
* connectOptions1
*
* Internal subroutine to set up connection parameters given an already-
* created PGconn and a conninfo string. Derived settings should be
* processed by calling connectOptions2 next. (We split them because
* PQsetdbLogin overrides defaults in between.)
*
* Returns true if OK, false if trouble (in which case errorMessage is set
* and so is conn->status).
*/
static bool
connectOptions1(PGconn *conn, const char *conninfo)
{
PQconninfoOption *connOptions;
char *tmp;
/*
* Parse the conninfo string
*/
connOptions = conninfo_parse(conninfo, &conn->errorMessage);
if (connOptions == NULL)
{
conn->status = CONNECTION_BAD;
/* errorMessage is already set */
return false;
}
/*
* Move option values into conn structure
*
* Don't put anything cute here --- intelligence should be in
* connectOptions2 ...
*/
tmp = conninfo_getval(connOptions, "hostaddr");
conn->pghostaddr = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "host");
conn->pghost = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "port");
conn->pgport = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "tty");
conn->pgtty = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "options");
conn->pgoptions = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "dbname");
conn->dbName = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "user");
conn->pguser = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "password");
conn->pgpass = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "connect_timeout");
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
tmp = conninfo_getval(connOptions, "sslmode");
conn->sslmode = tmp ? strdup(tmp) : NULL;
2000-08-30 16:54:24 +02:00
#ifdef USE_SSL
tmp = conninfo_getval(connOptions, "requiressl");
if (tmp && tmp[0] == '1')
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
{
/* here warn that the requiressl option is deprecated? */
if (conn->sslmode)
free(conn->sslmode);
conn->sslmode = strdup("require");
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
}
2000-08-30 16:54:24 +02:00
#endif
/*
* Free the option info - all is in conn now
*/
PQconninfoFree(connOptions);
return true;
}
/*
* connectOptions2
*
* Compute derived connection options after absorbing all user-supplied info.
*
* Returns true if OK, false if trouble (in which case errorMessage is set
* and so is conn->status).
*/
static bool
connectOptions2(PGconn *conn)
{
/*
* If database name was not given, default it to equal user name
*/
if ((conn->dbName == NULL || conn->dbName[0] == '\0')
&& conn->pguser != NULL)
{
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(conn->pguser);
}
/*
* Supply default password if none given
*/
if (conn->pgpass == NULL || conn->pgpass[0] == '\0')
{
if (conn->pgpass)
free(conn->pgpass);
conn->pgpass = PasswordFromFile(conn->pghost, conn->pgport,
conn->dbName, conn->pguser);
if (conn->pgpass == NULL)
conn->pgpass = strdup(DefaultPassword);
}
/*
* Allow unix socket specification in the host name
*/
if (conn->pghost && is_absolute_path(conn->pghost))
{
if (conn->pgunixsocket)
free(conn->pgunixsocket);
conn->pgunixsocket = conn->pghost;
conn->pghost = NULL;
}
#ifdef NOT_USED
2003-08-04 02:43:34 +02:00
/*
* parse dbName to get all additional info in it, if any
*/
if (update_db_info(conn) != 0)
{
conn->status = CONNECTION_BAD;
/* errorMessage is already set */
return false;
}
#endif
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
/*
* validate sslmode option
*/
if (conn->sslmode)
{
if (strcmp(conn->sslmode, "disable") != 0
&& strcmp(conn->sslmode, "allow") != 0
&& strcmp(conn->sslmode, "prefer") != 0
&& strcmp(conn->sslmode, "require") != 0)
{
conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage,
2003-09-22 02:23:35 +02:00
libpq_gettext("invalid sslmode value: \"%s\"\n"),
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->sslmode);
return false;
}
#ifndef USE_SSL
2003-08-04 02:43:34 +02:00
switch (conn->sslmode[0])
{
case 'a': /* "allow" */
case 'p': /* "prefer" */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
/*
* warn user that an SSL connection will never be
* negotiated since SSL was not compiled in?
*/
break;
2003-08-04 02:43:34 +02:00
case 'r': /* "require" */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->status = CONNECTION_BAD;
printfPQExpBuffer(&conn->errorMessage,
2003-09-22 02:23:35 +02:00
libpq_gettext("sslmode value \"%s\" invalid when SSL support is not compiled in\n"),
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->sslmode);
return false;
}
#endif
}
else
conn->sslmode = strdup(DefaultSSLMode);
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
return true;
}
/*
* PQconndefaults
*
* Parse an empty string like PQconnectdb() would do and return the
* working connection options array.
*
* Using this function, an application may determine all possible options
* and their current default values.
*
* NOTE: as of PostgreSQL 7.0, the returned array is dynamically allocated
* and should be freed when no longer needed via PQconninfoFree(). (In prior
* versions, the returned array was static, but that's not thread-safe.)
* Pre-7.0 applications that use this function will see a small memory leak
* until they are updated to call PQconninfoFree.
*/
PQconninfoOption *
PQconndefaults(void)
{
PQExpBufferData errorBuf;
PQconninfoOption *connOptions;
initPQExpBuffer(&errorBuf);
connOptions = conninfo_parse("", &errorBuf);
termPQExpBuffer(&errorBuf);
return connOptions;
}
/* ----------------
* PQsetdbLogin
*
* establishes a connection to a postgres backend through the postmaster
* at the specified host and port.
*
* returns a PGconn* which is needed for all subsequent libpq calls
*
* if the status field of the connection returned is CONNECTION_BAD,
* then only the errorMessage is likely to be useful.
* ----------------
*/
PGconn *
PQsetdbLogin(const char *pghost, const char *pgport, const char *pgoptions,
const char *pgtty, const char *dbName, const char *login,
const char *pwd)
{
PGconn *conn;
/*
* Allocate memory for the conn structure
*/
conn = makeEmptyPGconn();
if (conn == NULL)
return (PGconn *) NULL;
/*
* Parse an empty conninfo string in order to set up the same defaults
* that PQconnectdb() would use.
*/
if (!connectOptions1(conn, ""))
return conn;
/*
* Absorb specified options into conn structure, overriding defaults
*/
if (pghost && pghost[0] != '\0')
{
if (conn->pghost)
free(conn->pghost);
conn->pghost = strdup(pghost);
}
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (pgport && pgport[0] != '\0')
{
if (conn->pgport)
free(conn->pgport);
conn->pgport = strdup(pgport);
}
if (pgoptions && pgoptions[0] != '\0')
{
if (conn->pgoptions)
free(conn->pgoptions);
conn->pgoptions = strdup(pgoptions);
}
if (pgtty && pgtty[0] != '\0')
{
if (conn->pgtty)
free(conn->pgtty);
conn->pgtty = strdup(pgtty);
}
if (dbName && dbName[0] != '\0')
{
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(dbName);
}
if (login && login[0] != '\0')
{
if (conn->pguser)
free(conn->pguser);
conn->pguser = strdup(login);
}
if (pwd && pwd[0] != '\0')
{
if (conn->pgpass)
free(conn->pgpass);
conn->pgpass = strdup(pwd);
}
/*
* Compute derived options
*/
if (!connectOptions2(conn))
return conn;
2000-08-30 16:54:24 +02:00
/*
* Connect to the database
*/
if (connectDBStart(conn))
(void) connectDBComplete(conn);
return conn;
}
2001-03-22 05:01:46 +01:00
#ifdef NOT_USED /* because it's broken */
/*
* update_db_info -
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
* get all additional info out of dbName
*/
static int
update_db_info(PGconn *conn)
{
2001-03-22 05:01:46 +01:00
char *tmp,
*tmp2,
*old = conn->dbName;
if (strchr(conn->dbName, '@') != NULL)
{
/* old style: dbname[@server][:port] */
tmp = strrchr(conn->dbName, ':');
if (tmp != NULL) /* port number given */
{
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (conn->pgport)
free(conn->pgport);
conn->pgport = strdup(tmp + 1);
*tmp = '\0';
}
tmp = strrchr(conn->dbName, '@');
if (tmp != NULL) /* host name given */
{
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (conn->pghost)
free(conn->pghost);
conn->pghost = strdup(tmp + 1);
*tmp = '\0';
}
conn->dbName = strdup(old);
free(old);
}
else
{
int offset;
/*
* only allow protocols tcp and unix
*/
if (strncmp(conn->dbName, "tcp:", 4) == 0)
offset = 4;
else if (strncmp(conn->dbName, "unix:", 5) == 0)
offset = 5;
else
return 0;
if (strncmp(conn->dbName + offset, "postgresql://", strlen("postgresql://")) == 0)
{
/*-------
* new style:
* <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
* [/db name][?options]
*-------
*/
offset += strlen("postgresql://");
tmp = strrchr(conn->dbName + offset, '?');
if (tmp != NULL) /* options given */
{
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (conn->pgoptions)
free(conn->pgoptions);
conn->pgoptions = strdup(tmp + 1);
*tmp = '\0';
}
tmp = last_path_separator(conn->dbName + offset);
if (tmp != NULL) /* database name given */
{
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(tmp + 1);
*tmp = '\0';
}
else
{
2001-03-22 05:01:46 +01:00
/*
* Why do we default only this value from the environment
* again?
*/
if ((tmp = getenv("PGDATABASE")) != NULL)
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
{
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(tmp);
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
}
else if (conn->pguser)
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
{
if (conn->dbName)
free(conn->dbName);
conn->dbName = strdup(conn->pguser);
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
}
}
tmp = strrchr(old + offset, ':');
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (tmp != NULL) /* port number or Unix socket path given */
{
*tmp = '\0';
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
{
if (strncmp(old, "unix:", 5) != 0)
{
printfPQExpBuffer(&conn->errorMessage,
2001-03-22 05:01:46 +01:00
"connectDBStart() -- "
"socket name can only be specified with "
"non-TCP\n");
return 1;
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
}
*tmp2 = '\0';
if (conn->pgunixsocket)
free(conn->pgunixsocket);
conn->pgunixsocket = strdup(tmp + 1);
}
else
{
if (conn->pgport)
free(conn->pgport);
conn->pgport = strdup(tmp + 1);
if (conn->pgunixsocket)
free(conn->pgunixsocket);
conn->pgunixsocket = NULL;
}
}
if (strncmp(old, "unix:", 5) == 0)
{
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (conn->pghost)
free(conn->pghost);
conn->pghost = NULL;
if (strcmp(old + offset, "localhost") != 0)
{
printfPQExpBuffer(&conn->errorMessage,
"connectDBStart() -- "
"non-TCP access only possible on "
"localhost\n");
return 1;
}
}
else
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
{
if (conn->pghost)
free(conn->pghost);
conn->pghost = strdup(old + offset);
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
}
free(old);
}
}
return 0;
}
#endif /* NOT_USED */
/* ----------
* connectMakeNonblocking -
* Make a connection non-blocking.
* Returns 1 if successful, 0 if not.
* ----------
*/
static int
connectMakeNonblocking(PGconn *conn)
{
if (FCNTL_NONBLOCK(conn->sock) < 0)
{
2003-08-04 02:43:34 +02:00
char sebuf[256];
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to non-blocking mode: %s\n"),
2003-08-04 02:43:34 +02:00
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
return 0;
}
return 1;
}
/* ----------
* connectNoDelay -
* Sets the TCP_NODELAY socket option.
* Returns 1 if successful, 0 if not.
* ----------
*/
static int
connectNoDelay(PGconn *conn)
{
#ifdef TCP_NODELAY
int on = 1;
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY,
(char *) &on,
sizeof(on)) < 0)
{
2003-08-04 02:43:34 +02:00
char sebuf[256];
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to TCP no delay mode: %s\n"),
2003-08-04 02:43:34 +02:00
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
return 0;
}
#endif
return 1;
}
/* ----------
* connectFailureMessage -
* create a friendly error message on connection failure.
* ----------
*/
static void
connectFailureMessage(PGconn *conn, int errorno)
{
2003-08-04 02:43:34 +02:00
char sebuf[256];
#ifdef HAVE_UNIX_SOCKETS
if (IS_AF_UNIX(conn->raddr.addr.ss_family))
{
2003-08-04 02:43:34 +02:00
char service[NI_MAXHOST];
getnameinfo_all(&conn->raddr.addr, conn->raddr.salen,
NULL, 0,
service, sizeof(service),
NI_NUMERICSERV);
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"could not connect to server: %s\n"
"\tIs the server running locally and accepting\n"
"\tconnections on Unix domain socket \"%s\"?\n"
),
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
service);
}
else
#endif /* HAVE_UNIX_SOCKETS */
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"could not connect to server: %s\n"
2003-08-04 02:43:34 +02:00
"\tIs the server running on host \"%s\" and accepting\n"
"\tTCP/IP connections on port %s?\n"
),
SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)),
conn->pghostaddr
? conn->pghostaddr
: (conn->pghost
? conn->pghost
: "???"),
conn->pgport);
}
}
/* ----------
* connectDBStart -
* Begin the process of making a connection to the backend.
*
* Returns 1 if successful, 0 if not.
* ----------
*/
static int
connectDBStart(PGconn *conn)
{
int portnum;
2003-08-04 02:43:34 +02:00
char portstr[128];
struct addrinfo *addrs = NULL;
struct addrinfo hint;
const char *node = NULL;
int ret;
if (!conn)
return 0;
/* Ensure our buffers are empty */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
/*
* Determine the parameters to pass to getaddrinfo_all.
*/
/* Initialize hint structure */
MemSet(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_STREAM;
hint.ai_family = AF_UNSPEC;
/* Set up port number as a string */
if (conn->pgport != NULL && conn->pgport[0] != '\0')
portnum = atoi(conn->pgport);
else
portnum = DEF_PGPORT;
snprintf(portstr, sizeof(portstr), "%d", portnum);
if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
{
/* Using pghostaddr avoids a hostname lookup */
node = conn->pghostaddr;
hint.ai_family = AF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
}
else if (conn->pghost != NULL && conn->pghost[0] != '\0')
{
/* Using pghost, so we have to look-up the hostname */
node = conn->pghost;
hint.ai_family = AF_UNSPEC;
}
#ifdef HAVE_UNIX_SOCKETS
else
{
/* pghostaddr and pghost are NULL, so use Unix domain socket */
node = NULL;
hint.ai_family = AF_UNIX;
UNIXSOCK_PATH(portstr, portnum, conn->pgunixsocket);
}
#endif /* HAVE_UNIX_SOCKETS */
/* Use getaddrinfo_all() to resolve the address */
ret = getaddrinfo_all(node, portstr, &hint, &addrs);
if (ret || !addrs)
{
if (node)
printfPQExpBuffer(&conn->errorMessage,
2003-09-22 02:23:35 +02:00
libpq_gettext("could not translate host name \"%s\" to address: %s\n"),
node, gai_strerror(ret));
else
printfPQExpBuffer(&conn->errorMessage,
2003-09-22 02:23:35 +02:00
libpq_gettext("could not translate Unix-domain socket path \"%s\" to address: %s\n"),
portstr, gai_strerror(ret));
freeaddrinfo_all(hint.ai_family, addrs);
goto connect_errReturn;
}
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
#ifdef USE_SSL
/* setup values based on SSL mode */
2003-08-04 02:43:34 +02:00
if (conn->sslmode[0] == 'd') /* "disable" */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->allow_ssl_try = false;
2003-08-04 02:43:34 +02:00
else if (conn->sslmode[0] == 'a') /* "allow" */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->wait_ssl_try = true;
#endif
/*
* Set up to try to connect, with protocol 3.0 as the first attempt.
*/
conn->addrlist = addrs;
conn->addr_cur = addrs;
conn->addrlist_family = hint.ai_family;
2003-08-04 02:43:34 +02:00
conn->pversion = PG_PROTOCOL(3, 0);
conn->status = CONNECTION_NEEDED;
/*
2003-08-04 02:43:34 +02:00
* The code for processing CONNECTION_NEEDED state is in
* PQconnectPoll(), so that it can easily be re-executed if needed
* again during the asynchronous startup process. However, we must
* run it once here, because callers expect a success return from this
* routine to mean that we are in PGRES_POLLING_WRITING connection
* state.
*/
if (PQconnectPoll(conn) == PGRES_POLLING_WRITING)
return 1;
connect_errReturn:
if (conn->sock >= 0)
{
pqsecure_close(conn);
closesocket(conn->sock);
conn->sock = -1;
}
conn->status = CONNECTION_BAD;
return 0;
}
/*
* connectDBComplete
*
* Block and complete a connection.
*
* Returns 1 on success, 0 on failure.
*/
static int
connectDBComplete(PGconn *conn)
{
PostgresPollingStatusType flag = PGRES_POLLING_WRITING;
time_t finish_time = ((time_t) -1);
if (conn == NULL || conn->status == CONNECTION_BAD)
return 0;
2002-09-04 22:31:48 +02:00
/*
* Set up a time limit, if connect_timeout isn't zero.
2002-09-04 22:31:48 +02:00
*/
if (conn->connect_timeout != NULL)
{
int timeout = atoi(conn->connect_timeout);
if (timeout > 0)
{
/*
* Rounding could cause connection to fail; need at least 2
* secs
*/
if (timeout < 2)
timeout = 2;
/* calculate the finish time based on start + timeout */
finish_time = time(NULL) + timeout;
}
}
for (;;)
{
/*
* Wait, if necessary. Note that the initial state (just after
* PQconnectStart) is to wait for the socket to select for
* writing.
*/
switch (flag)
{
case PGRES_POLLING_OK:
return 1; /* success! */
case PGRES_POLLING_READING:
if (pqWaitTimed(1, 0, conn, finish_time))
{
conn->status = CONNECTION_BAD;
return 0;
}
break;
case PGRES_POLLING_WRITING:
if (pqWaitTimed(0, 1, conn, finish_time))
{
conn->status = CONNECTION_BAD;
return 0;
}
break;
default:
/* Just in case we failed to set it in PQconnectPoll */
conn->status = CONNECTION_BAD;
return 0;
}
/*
* Now try to advance the state machine.
*/
flag = PQconnectPoll(conn);
}
}
/* ----------------
* PQconnectPoll
*
* Poll an asynchronous connection.
*
* Returns a PostgresPollingStatusType.
* Before calling this function, use select(2) to determine when data
* has arrived..
*
* You must call PQfinish whether or not this fails.
*
* This function and PQconnectStart are intended to allow connections to be
* made without blocking the execution of your program on remote I/O. However,
* there are a number of caveats:
*
* o If you call PQtrace, ensure that the stream object into which you trace
* will not block.
* o If you do not supply an IP address for the remote host (i.e. you
* supply a host name instead) then PQconnectStart will block on
* gethostbyname. You will be fine if using Unix sockets (i.e. by
* supplying neither a host name nor a host address).
* o If your backend wants to use Kerberos authentication then you must
* supply both a host name and a host address, otherwise this function
* may block on gethostname.
*
* ----------------
*/
PostgresPollingStatusType
PQconnectPoll(PGconn *conn)
{
PGresult *res;
char sebuf[256];
2001-03-22 05:01:46 +01:00
if (conn == NULL)
return PGRES_POLLING_FAILED;
/* Get the new data */
switch (conn->status)
{
/*
* We really shouldn't have been polled in these two cases,
* but we can handle it.
*/
case CONNECTION_BAD:
return PGRES_POLLING_FAILED;
case CONNECTION_OK:
return PGRES_POLLING_OK;
/* These are reading states */
case CONNECTION_AWAITING_RESPONSE:
case CONNECTION_AUTH_OK:
{
/* Load waiting data */
int n = pqReadData(conn);
if (n < 0)
goto error_return;
if (n == 0)
return PGRES_POLLING_READING;
break;
}
/* These are writing states, so we just proceed. */
case CONNECTION_STARTED:
case CONNECTION_MADE:
break;
/* We allow pqSetenvPoll to decide whether to proceed. */
case CONNECTION_SETENV:
break;
/* Special cases: proceed without waiting. */
case CONNECTION_SSL_STARTUP:
case CONNECTION_NEEDED:
break;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state, "
"probably indicative of memory corruption\n"
));
goto error_return;
}
keep_going: /* We will come back to here until there
* is nothing left to do. */
switch (conn->status)
{
case CONNECTION_NEEDED:
{
/*
* Try to initiate a connection to one of the addresses
* returned by getaddrinfo_all(). conn->addr_cur is the
* next one to try. We fail when we run out of addresses
2003-08-04 02:43:34 +02:00
* (reporting the error returned for the *last*
* alternative, which may not be what users expect :-().
*/
while (conn->addr_cur != NULL)
{
struct addrinfo *addr_cur = conn->addr_cur;
/* Remember current address for possible error msg */
memcpy(&conn->raddr.addr, addr_cur->ai_addr,
addr_cur->ai_addrlen);
conn->raddr.salen = addr_cur->ai_addrlen;
/* Open a socket */
conn->sock = socket(addr_cur->ai_family, SOCK_STREAM, 0);
if (conn->sock < 0)
{
/*
2003-08-04 02:43:34 +02:00
* ignore socket() failure if we have more
* addresses to try
*/
if (addr_cur->ai_next != NULL)
{
conn->addr_cur = addr_cur->ai_next;
continue;
}
printfPQExpBuffer(&conn->errorMessage,
2003-08-04 02:43:34 +02:00
libpq_gettext("could not create socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
break;
}
/*
2003-08-04 02:43:34 +02:00
* Select socket options: no delay of outgoing data
* for TCP sockets, and nonblock mode. Fail if this
* fails.
*/
if (!IS_AF_UNIX(addr_cur->ai_family))
{
if (!connectNoDelay(conn))
{
closesocket(conn->sock);
conn->sock = -1;
conn->addr_cur = addr_cur->ai_next;
continue;
}
}
if (connectMakeNonblocking(conn) == 0)
{
closesocket(conn->sock);
conn->sock = -1;
conn->addr_cur = addr_cur->ai_next;
continue;
}
2003-08-04 02:43:34 +02:00
/*
2003-08-04 02:43:34 +02:00
* Start/make connection. This should not block,
* since we are in nonblock mode. If it does, well,
* too bad.
*/
2003-08-04 02:43:34 +02:00
retry_connect:
if (connect(conn->sock, addr_cur->ai_addr,
addr_cur->ai_addrlen) < 0)
{
if (SOCK_ERRNO == EINTR)
/* Interrupted system call - just try again */
goto retry_connect;
if (SOCK_ERRNO == EINPROGRESS ||
SOCK_ERRNO == EWOULDBLOCK ||
SOCK_ERRNO == 0)
{
/*
* This is fine - we're in non-blocking mode,
* and the connection is in progress. Tell
* caller to wait for write-ready on socket.
*/
conn->status = CONNECTION_STARTED;
return PGRES_POLLING_WRITING;
}
/* otherwise, trouble */
}
else
{
/*
* Hm, we're connected already --- seems the
2003-08-04 02:43:34 +02:00
* "nonblock connection" wasn't. Advance the
* state machine and go do the next stuff.
*/
conn->status = CONNECTION_STARTED;
goto keep_going;
}
2003-08-04 02:43:34 +02:00
/*
* This connection failed --- set up error report,
* then close socket (do it this way in case close()
2003-08-04 02:43:34 +02:00
* affects the value of errno...). We will ignore the
* connect() failure and keep going if there are more
* addresses.
*/
connectFailureMessage(conn, SOCK_ERRNO);
if (conn->sock >= 0)
{
closesocket(conn->sock);
conn->sock = -1;
}
2003-08-04 02:43:34 +02:00
/*
* Try the next address, if any.
*/
conn->addr_cur = addr_cur->ai_next;
2003-08-04 02:43:34 +02:00
} /* loop over addresses */
/*
* Ooops, no more addresses. An appropriate error message
* is already set up, so just set the right status.
*/
goto error_return;
}
case CONNECTION_STARTED:
{
int optval;
2003-08-04 02:43:34 +02:00
ACCEPT_TYPE_ARG3 optlen = sizeof(optval);
/*
* Write ready, since we've made it here, so the
* connection has been made ... or has failed.
*/
/*
* Now check (using getsockopt) that there is not an error
* state waiting for us on the socket.
*/
if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR,
(char *) &optval, &optlen) == -1)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get socket error status: %s\n"),
2003-08-04 02:43:34 +02:00
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
}
else if (optval != 0)
{
/*
* When using a nonblocking connect, we will typically
* see connect failures at this point, so provide a
* friendly error message.
*/
connectFailureMessage(conn, optval);
2003-08-04 02:43:34 +02:00
/*
* If more addresses remain, keep trying, just as in
2003-08-04 02:43:34 +02:00
* the case where connect() returned failure
* immediately.
*/
if (conn->addr_cur->ai_next != NULL)
{
if (conn->sock >= 0)
{
closesocket(conn->sock);
conn->sock = -1;
}
conn->addr_cur = conn->addr_cur->ai_next;
conn->status = CONNECTION_NEEDED;
goto keep_going;
}
goto error_return;
}
/* Fill in the client address */
conn->laddr.salen = sizeof(conn->laddr.addr);
2003-08-04 02:43:34 +02:00
if (getsockname(conn->sock,
(struct sockaddr *) & conn->laddr.addr,
&conn->laddr.salen) < 0)
{
printfPQExpBuffer(&conn->errorMessage,
2003-08-04 02:43:34 +02:00
libpq_gettext("could not get client address from socket: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
}
/*
* Make sure we can write before advancing to next step.
*/
conn->status = CONNECTION_MADE;
return PGRES_POLLING_WRITING;
}
case CONNECTION_MADE:
{
2003-08-04 02:43:34 +02:00
char *startpacket;
int packetlen;
#ifdef USE_SSL
2003-08-04 02:43:34 +02:00
/*
2003-08-04 02:43:34 +02:00
* If SSL is enabled and we haven't already got it
* running, request it instead of sending the startup
* message.
*/
if (IS_AF_UNIX(conn->raddr.addr.ss_family))
{
/* Don't bother requesting SSL over a Unix socket */
conn->allow_ssl_try = false;
}
if (conn->allow_ssl_try && !conn->wait_ssl_try &&
conn->ssl == NULL)
{
ProtocolVersion pv;
/*
* Send the SSL request packet.
*
2003-08-04 02:43:34 +02:00
* Theoretically, this could block, but it really
* shouldn't since we only got here if the socket is
* write-ready.
*/
pv = htonl(NEGOTIATE_SSL_CODE);
if (pqPacketSend(conn, 0, &pv, sizeof(pv)) != STATUS_OK)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send SSL negotiation packet: %s\n"),
2003-08-04 02:43:34 +02:00
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
}
/* Ok, wait for response */
conn->status = CONNECTION_SSL_STARTUP;
return PGRES_POLLING_READING;
}
2003-08-04 02:43:34 +02:00
#endif /* USE_SSL */
/*
* Build the startup packet.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
startpacket = pqBuildStartupPacket3(conn, &packetlen,
2003-08-04 02:43:34 +02:00
EnvironmentOptions);
else
startpacket = pqBuildStartupPacket2(conn, &packetlen,
2003-08-04 02:43:34 +02:00
EnvironmentOptions);
if (!startpacket)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("out of memory\n"));
goto error_return;
}
/*
* Send the startup packet.
*
* Theoretically, this could block, but it really shouldn't
* since we only got here if the socket is write-ready.
*/
if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not send startup packet: %s\n"),
2003-08-04 02:43:34 +02:00
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
free(startpacket);
goto error_return;
}
free(startpacket);
conn->status = CONNECTION_AWAITING_RESPONSE;
return PGRES_POLLING_READING;
}
/*
2003-08-04 02:43:34 +02:00
* Handle SSL negotiation: wait for postmaster messages and
* respond as necessary.
*/
case CONNECTION_SSL_STARTUP:
{
#ifdef USE_SSL
PostgresPollingStatusType pollres;
/*
2003-08-04 02:43:34 +02:00
* On first time through, get the postmaster's response to
* our SSL negotiation packet. Be careful to read only
* one byte (if there's more, it could be SSL data).
*/
if (conn->ssl == NULL)
{
char SSLok;
int nread;
2003-08-04 02:43:34 +02:00
retry_ssl_read:
nread = recv(conn->sock, &SSLok, 1, 0);
if (nread < 0)
{
if (SOCK_ERRNO == EINTR)
/* Interrupted system call - just try again */
goto retry_ssl_read;
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not receive server response to SSL negotiation packet: %s\n"),
2003-08-04 02:43:34 +02:00
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
goto error_return;
}
if (nread == 0)
/* caller failed to wait for data */
return PGRES_POLLING_READING;
if (SSLok == 'S')
{
/* Do one-time setup; this creates conn->ssl */
if (pqsecure_initialize(conn) == -1)
goto error_return;
}
else if (SSLok == 'N')
{
2003-08-04 02:43:34 +02:00
if (conn->sslmode[0] == 'r') /* "require" */
{
/* Require SSL, but server does not want it */
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
/* Otherwise, proceed with normal startup */
conn->allow_ssl_try = false;
conn->status = CONNECTION_MADE;
return PGRES_POLLING_WRITING;
}
else if (SSLok == 'E')
{
/* Received error - probably protocol mismatch */
if (conn->Pfdebug)
fprintf(conn->Pfdebug, "Postmaster reports error, attempting fallback to pre-7.0.\n");
2003-08-04 02:43:34 +02:00
if (conn->sslmode[0] == 'r') /* "require" */
{
/* Require SSL, but server is too old */
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("server does not support SSL, but SSL was required\n"));
goto error_return;
}
/* Otherwise, try again without SSL */
conn->allow_ssl_try = false;
/* Assume it ain't gonna handle protocol 3, either */
2003-08-04 02:43:34 +02:00
conn->pversion = PG_PROTOCOL(2, 0);
/* Must drop the old connection */
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED;
goto keep_going;
}
else
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("received invalid response to SSL negotiation: %c\n"),
SSLok);
goto error_return;
}
}
2003-08-04 02:43:34 +02:00
/*
* Begin or continue the SSL negotiation process.
*/
pollres = pqsecure_open_client(conn);
if (pollres == PGRES_POLLING_OK)
{
/* SSL handshake done, ready to send startup packet */
conn->status = CONNECTION_MADE;
return PGRES_POLLING_WRITING;
}
return pollres;
2003-08-04 02:43:34 +02:00
#else /* !USE_SSL */
/* can't get here */
goto error_return;
2003-08-04 02:43:34 +02:00
#endif /* USE_SSL */
}
/*
* Handle authentication exchange: wait for postmaster
* messages and respond as necessary.
*/
case CONNECTION_AWAITING_RESPONSE:
{
char beresp;
int msgLength;
int avail;
AuthRequest areq;
/*
* Scan the message from current point (note that if we
* find the message is incomplete, we will return without
* advancing inStart, and resume here next time).
*/
conn->inCursor = conn->inStart;
/* Read type byte */
if (pqGetc(&beresp, conn))
{
2002-08-27 17:02:50 +02:00
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/*
* Validate message type: we expect only an authentication
* request or an error here. Anything else probably means
* it's not Postgres on the other end at all.
*/
if (!(beresp == 'R' || beresp == 'E'))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
2003-08-04 02:43:34 +02:00
"server, but received %c\n"),
beresp);
goto error_return;
}
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
/* Read message length word */
if (pqGetInt(&msgLength, 4, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
else
{
/* Set phony message length to disable checks below */
msgLength = 8;
}
/*
* Try to validate message length before using it.
* Authentication requests can't be very large. Errors
2003-08-04 02:43:34 +02:00
* can be a little larger, but not huge. If we see a
* large apparent length in an error, it means we're
* really talking to a pre-3.0-protocol server; cope.
*/
if (beresp == 'R' && (msgLength < 8 || msgLength > 100))
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"expected authentication request from "
2003-08-04 02:43:34 +02:00
"server, but received %c\n"),
beresp);
goto error_return;
}
if (beresp == 'E' && (msgLength < 8 || msgLength > 30000))
{
/* Handle error from a pre-3.0 server */
2003-08-04 02:43:34 +02:00
conn->inCursor = conn->inStart + 1; /* reread data */
if (pqGets(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* OK, we read the message; mark data consumed */
conn->inStart = conn->inCursor;
/*
* The postmaster typically won't end its message with
* a newline, so add one to conform to libpq
* conventions.
*/
appendPQExpBufferChar(&conn->errorMessage, '\n');
/*
* If we tried to open the connection in 3.0 protocol,
* fall back to 2.0 protocol.
*/
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
2003-08-04 02:43:34 +02:00
conn->pversion = PG_PROTOCOL(2, 0);
/* Must drop the old connection */
pqsecure_close(conn);
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED;
goto keep_going;
}
goto error_return;
}
/*
* Can't process if message body isn't all here yet.
*
2003-08-04 02:43:34 +02:00
* (In protocol 2.0 case, we are assuming messages carry at
* least 4 bytes of data.)
*/
msgLength -= 4;
avail = conn->inEnd - conn->inCursor;
if (avail < msgLength)
{
/*
2003-08-04 02:43:34 +02:00
* Before returning, try to enlarge the input buffer
* if needed to hold the whole message; see notes in
* pqParseInput3.
*/
if (pqCheckInBufferSpace(conn->inCursor + msgLength, conn))
goto error_return;
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
/* Handle errors. */
if (beresp == 'E')
{
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
{
if (pqGetErrorNotice3(conn, true))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
else
{
if (pqGets(&conn->errorMessage, conn))
{
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
}
/* OK, we read the message; mark data consumed */
conn->inStart = conn->inCursor;
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
#ifdef USE_SSL
2003-08-04 02:43:34 +02:00
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
/*
* if sslmode is "allow" and we haven't tried an SSL
2003-08-04 02:43:34 +02:00
* connection already, then retry with an SSL
* connection
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
*/
if (conn->sslmode[0] == 'a' /* "allow" */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
&& conn->ssl == NULL
&& conn->allow_ssl_try
&& conn->wait_ssl_try)
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
{
/* only retry once */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->wait_ssl_try = false;
/* Must drop the old connection */
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED;
goto keep_going;
}
/*
* if sslmode is "prefer" and we're in an SSL
* connection, then do a non-SSL retry
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
*/
if (conn->sslmode[0] == 'p' /* "prefer" */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
&& conn->ssl
2003-08-04 02:43:34 +02:00
&& conn->allow_ssl_try /* redundant? */
&& !conn->wait_ssl_try) /* redundant? */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
{
/* only retry once */
At long last I put together a patch to support 4 client SSL negotiation modes (and replace the requiressl boolean). The four options were first spelled out by Magnus Hagander <mha@sollentuna.net> on 2000-08-23 in email to pgsql-hackers, archived here: http://archives.postgresql.org/pgsql-hackers/2000-08/msg00639.php My original less-flexible patch and the ensuing thread are archived at: http://dbforums.com/t623845.html Attached is a new patch, including documentation. To sum up, there's a new client parameter "sslmode" and environment variable "PGSSLMODE", with these options: sslmode description ------- ----------- disable Unencrypted non-SSL only allow Negotiate, prefer non-SSL prefer Negotiate, prefer SSL (default) require Require SSL The only change to the server is a new pg_hba.conf line type, "hostnossl", for specifying connections that are not allowed to use SSL (for example, to prevent servers on a local network from accidentally using SSL and wasting cycles). Thus the 3 pg_hba.conf line types are: pg_hba.conf line types ---------------------- host applies to either SSL or regular connections hostssl applies only to SSL connections hostnossl applies only to regular connections These client and server options, the postgresql.conf ssl = false option, and finally the possibility of compiling with no SSL support at all, make quite a range of combinations to test. I threw together a test script to try many of them out. It's in a separate tarball with its config files, a patch to psql so it'll announce SSL connections even in absence of a tty, and the test output. The test is especially informative when run on the same tty the postmaster was started on, so the FATAL: errors during negotiation are interleaved with the psql client output. I saw Tom write that new submissions for 7.4 have to be in before midnight local time, and since I'm on the east coast in the US, this just makes it in before the bell. :) Jon Jensen
2003-07-26 15:50:02 +02:00
conn->allow_ssl_try = false;
/* Must drop the old connection */
pqsecure_close(conn);
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED;
goto keep_going;
}
#endif
goto error_return;
}
/* It is an authentication request. */
/* Get the type of request. */
if (pqGetInt((int *) &areq, 4, conn))
{
/* We'll come back when there are more data */
return PGRES_POLLING_READING;
}
/* Get the password salt if there is one. */
2001-08-17 04:59:20 +02:00
if (areq == AUTH_REQ_MD5)
{
2001-08-17 04:59:20 +02:00
if (pqGetnchar(conn->md5Salt,
sizeof(conn->md5Salt), conn))
{
/* We'll come back when there are more data */
return PGRES_POLLING_READING;
}
}
if (areq == AUTH_REQ_CRYPT)
{
if (pqGetnchar(conn->cryptSalt,
sizeof(conn->cryptSalt), conn))
{
/* We'll come back when there are more data */
return PGRES_POLLING_READING;
}
}
/*
* OK, we successfully read the message; mark data
* consumed
*/
conn->inStart = conn->inCursor;
/* Respond to the request if necessary. */
/*
* Note that conn->pghost must be non-NULL if we are going
* to avoid the Kerberos code doing a hostname look-up.
*/
/*
* XXX fe-auth.c has not been fixed to support
* PQExpBuffers, so:
*/
if (fe_sendauth(areq, conn, conn->pghost, conn->pgpass,
conn->errorMessage.data) != STATUS_OK)
{
conn->errorMessage.len = strlen(conn->errorMessage.data);
goto error_return;
}
conn->errorMessage.len = strlen(conn->errorMessage.data);
/*
* Just make sure that any data sent by fe_sendauth is
* flushed out. Although this theoretically could block,
* it really shouldn't since we don't send large auth
* responses.
*/
if (pqFlush(conn))
goto error_return;
if (areq == AUTH_REQ_OK)
{
/* We are done with authentication exchange */
conn->status = CONNECTION_AUTH_OK;
/*
* Set asyncStatus so that PQsetResult will think that
* what comes back next is the result of a query. See
* below.
*/
conn->asyncStatus = PGASYNC_BUSY;
}
/* Look to see if we have more data yet. */
goto keep_going;
}
case CONNECTION_AUTH_OK:
{
/*
* Now we expect to hear from the backend. A ReadyForQuery
* message indicates that startup is successful, but we
* might also get an Error message indicating failure.
* (Notice messages indicating nonfatal warnings are also
* allowed by the protocol, as are ParameterStatus and
* BackendKeyData messages.) Easiest way to handle this is
* to let PQgetResult() read the messages. We just have to
2003-08-04 02:43:34 +02:00
* fake it out about the state of the connection, by
* setting asyncStatus = PGASYNC_BUSY (done above).
*/
if (PQisBusy(conn))
return PGRES_POLLING_READING;
res = PQgetResult(conn);
/*
* NULL return indicating we have gone to IDLE state is
* expected
*/
if (res)
{
if (res->resultStatus != PGRES_FATAL_ERROR)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("unexpected message from server during startup\n"));
/*
* if the resultStatus is FATAL, then
* conn->errorMessage already has a copy of the error;
* needn't copy it back. But add a newline if it's not
* there already, since postmaster error messages may
* not have one.
*/
if (conn->errorMessage.len <= 0 ||
conn->errorMessage.data[conn->errorMessage.len - 1] != '\n')
appendPQExpBufferChar(&conn->errorMessage, '\n');
PQclear(res);
goto error_return;
}
/* We can release the address list now. */
freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
conn->addrlist = NULL;
conn->addr_cur = NULL;
/* Fire up post-connection housekeeping if needed */
if (PG_PROTOCOL_MAJOR(conn->pversion) < 3)
{
conn->status = CONNECTION_SETENV;
conn->setenv_state = SETENV_STATE_OPTION_SEND;
conn->next_eo = EnvironmentOptions;
return PGRES_POLLING_WRITING;
}
/* Otherwise, we are open for business! */
conn->status = CONNECTION_OK;
return PGRES_POLLING_OK;
}
case CONNECTION_SETENV:
/*
2003-08-04 02:43:34 +02:00
* Do post-connection housekeeping (only needed in protocol
* 2.0).
*
2003-08-04 02:43:34 +02:00
* We pretend that the connection is OK for the duration of these
* queries.
*/
conn->status = CONNECTION_OK;
switch (pqSetenvPoll(conn))
{
case PGRES_POLLING_OK: /* Success */
break;
case PGRES_POLLING_READING: /* Still going */
conn->status = CONNECTION_SETENV;
return PGRES_POLLING_READING;
case PGRES_POLLING_WRITING: /* Still going */
conn->status = CONNECTION_SETENV;
return PGRES_POLLING_WRITING;
default:
goto error_return;
}
/* We are open for business! */
conn->status = CONNECTION_OK;
return PGRES_POLLING_OK;
default:
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext(
"invalid connection state %c, "
"probably indicative of memory corruption\n"
),
conn->status);
goto error_return;
}
/* Unreachable */
error_return:
/*
* We used to close the socket at this point, but that makes it
* awkward for those above us if they wish to remove this socket from
* their own records (an fd_set for example). We'll just have this
* socket closed when PQfinish is called (which is compulsory even
* after an error, since the connection structure must be freed).
*/
conn->status = CONNECTION_BAD;
return PGRES_POLLING_FAILED;
}
/*
* makeEmptyPGconn
* - create a PGconn data structure with (as yet) no interesting data
*/
static PGconn *
makeEmptyPGconn(void)
{
PGconn *conn;
#ifdef WIN32
/* needed to use the static libpq under windows as well */
2003-08-04 02:43:34 +02:00
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1, 1), &wsaData))
2003-08-04 02:43:34 +02:00
return (PGconn *) NULL;
WSASetLastError(0);
#endif
conn = (PGconn *) malloc(sizeof(PGconn));
if (conn == NULL)
return conn;
/* Zero all pointers and booleans */
MemSet((char *) conn, 0, sizeof(PGconn));
conn->noticeHooks.noticeRec = defaultNoticeReceiver;
conn->noticeHooks.noticeProc = defaultNoticeProcessor;
conn->status = CONNECTION_BAD;
conn->asyncStatus = PGASYNC_IDLE;
conn->xactStatus = PQTRANS_IDLE;
conn->setenv_state = SETENV_STATE_IDLE;
conn->client_encoding = PG_SQL_ASCII;
conn->verbosity = PQERRORS_DEFAULT;
conn->notifyList = DLNewList();
conn->sock = -1;
#ifdef USE_SSL
conn->allow_ssl_try = true;
conn->wait_ssl_try = false;
#endif
/*
2003-08-04 02:43:34 +02:00
* We try to send at least 8K at a time, which is the usual size of
* pipe buffers on Unix systems. That way, when we are sending a
* large amount of data, we avoid incurring extra kernel context swaps
* for partial bufferloads. The output buffer is initially made 16K
* in size, and we try to dump it after accumulating 8K.
*
* With the same goal of minimizing context swaps, the input buffer will
* be enlarged anytime it has less than 8K free, so we initially
* allocate twice that.
*/
conn->inBufSize = 16 * 1024;
conn->inBuffer = (char *) malloc(conn->inBufSize);
conn->outBufSize = 16 * 1024;
conn->outBuffer = (char *) malloc(conn->outBufSize);
conn->nonblocking = FALSE;
initPQExpBuffer(&conn->errorMessage);
initPQExpBuffer(&conn->workBuffer);
if (conn->inBuffer == NULL ||
conn->outBuffer == NULL ||
conn->errorMessage.data == NULL ||
conn->workBuffer.data == NULL)
{
/* out of memory already :-( */
freePGconn(conn);
conn = NULL;
}
return conn;
}
/*
* freePGconn
* - free the PGconn data structure
*/
static void
freePGconn(PGconn *conn)
{
if (!conn)
return;
pqClearAsyncResult(conn); /* deallocate result and curTuple */
if (conn->sock >= 0)
{
pqsecure_close(conn);
closesocket(conn->sock);
}
if (conn->pghost)
free(conn->pghost);
if (conn->pghostaddr)
free(conn->pghostaddr);
if (conn->pgport)
free(conn->pgport);
UUNET is looking into offering PostgreSQL as a part of a managed web hosting product, on both shared and dedicated machines. We currently offer Oracle and MySQL, and it would be a nice middle-ground. However, as shipped, PostgreSQL lacks the following features we need that MySQL has: 1. The ability to listen only on a particular IP address. Each hosting customer has their own IP address, on which all of their servers (http, ftp, real media, etc.) run. 2. The ability to place the Unix-domain socket in a mode 700 directory. This allows us to automatically create an empty database, with an empty DBA password, for new or upgrading customers without having to interactively set a DBA password and communicate it to (or from) the customer. This in turn cuts down our install and upgrade times. 3. The ability to connect to the Unix-domain socket from within a change-rooted environment. We run CGI programs chrooted to the user's home directory, which is another reason why we need to be able to specify where the Unix-domain socket is, instead of /tmp. 4. The ability to, if run as root, open a pid file in /var/run as root, and then setuid to the desired user. (mysqld -u can almost do this; I had to patch it, too). The patch below fixes problem 1-3. I plan to address #4, also, but haven't done so yet. These diffs are big enough that they should give the PG development team something to think about in the meantime :-) Also, I'm about to leave for 2 weeks' vacation, so I thought I'd get out what I have, which works (for the problems it tackles), now. With these changes, we can set up and run PostgreSQL with scripts the same way we can with apache or proftpd or mysql. In summary, this patch makes the following enhancements: 1. Adds an environment variable PGUNIXSOCKET, analogous to MYSQL_UNIX_PORT, and command line options -k --unix-socket to the relevant programs. 2. Adds a -h option to postmaster to set the hostname or IP address to listen on instead of the default INADDR_ANY. 3. Extends some library interfaces to support the above. 4. Fixes a few memory leaks in PQconnectdb(). The default behavior is unchanged from stock 7.0.2; if you don't use any of these new features, they don't change the operation. David J. MacKenzie
2000-11-13 16:18:15 +01:00
if (conn->pgunixsocket)
free(conn->pgunixsocket);
if (conn->pgtty)
free(conn->pgtty);
if (conn->connect_timeout)
free(conn->connect_timeout);
if (conn->pgoptions)
free(conn->pgoptions);
if (conn->dbName)
free(conn->dbName);
if (conn->pguser)
free(conn->pguser);
if (conn->pgpass)
free(conn->pgpass);
if (conn->sslmode)
free(conn->sslmode);
/* Note that conn->Pfdebug is not ours to close or free */
if (conn->notifyList)
DLFreeList(conn->notifyList);
freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
if (conn->lobjfuncs)
free(conn->lobjfuncs);
if (conn->inBuffer)
free(conn->inBuffer);
if (conn->outBuffer)
free(conn->outBuffer);
termPQExpBuffer(&conn->errorMessage);
termPQExpBuffer(&conn->workBuffer);
free(conn);
}
/*
* closePGconn
* - properly close a connection to the backend
*/
static void
closePGconn(PGconn *conn)
{
/*
* Note that the protocol doesn't allow us to send Terminate messages
* during the startup phase.
*/
if (conn->sock >= 0 && conn->status == CONNECTION_OK)
{
/*
* Try to send "close connection" message to backend. Ignore any
* error.
*/
pqPutMsgStart('X', false, conn);
pqPutMsgEnd(conn);
pqFlush(conn);
}
/*
* must reset the blocking status so a possible reconnect will work
* don't call PQsetnonblocking() because it will fail if it's unable
* to flush the connection.
*/
conn->nonblocking = FALSE;
/*
* Close the connection, reset all transient state, flush I/O buffers.
*/
if (conn->sock >= 0)
{
pqsecure_close(conn);
closesocket(conn->sock);
}
conn->sock = -1;
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
* absent */
conn->asyncStatus = PGASYNC_IDLE;
pqClearAsyncResult(conn); /* deallocate result and curTuple */
if (conn->lobjfuncs)
free(conn->lobjfuncs);
conn->lobjfuncs = NULL;
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
}
/*
PQfinish:
properly close a connection to the backend
also frees the PGconn data structure so it shouldn't be re-used
after this
*/
void
PQfinish(PGconn *conn)
{
if (conn)
{
closePGconn(conn);
freePGconn(conn);
}
}
/* PQreset :
resets the connection to the backend
closes the existing connection and makes a new one
*/
void
PQreset(PGconn *conn)
{
if (conn)
{
closePGconn(conn);
if (connectDBStart(conn))
(void) connectDBComplete(conn);
}
}
/* PQresetStart :
resets the connection to the backend
closes the existing connection and makes a new one
Returns 1 on success, 0 on failure.
*/
int
PQresetStart(PGconn *conn)
{
if (conn)
{
closePGconn(conn);
return connectDBStart(conn);
}
return 0;
}
/* PQresetPoll :
resets the connection to the backend
closes the existing connection and makes a new one
*/
PostgresPollingStatusType
PQresetPoll(PGconn *conn)
{
if (conn)
return PQconnectPoll(conn);
return PGRES_POLLING_FAILED;
}
/*
* PQrequestCancel: attempt to request cancellation of the current operation.
*
* The return value is TRUE if the cancel request was successfully
* dispatched, FALSE if not (in which case conn->errorMessage is set).
* Note: successful dispatch is no guarantee that there will be any effect at
* the backend. The application must read the operation result as usual.
*
* XXX it was a bad idea to have the error message returned in
* conn->errorMessage, since it could overwrite a message already there.
* Would be better to return it in a char array passed by the caller.
*
* CAUTION: we want this routine to be safely callable from a signal handler
* (for example, an application might want to call it in a SIGINT handler).
* This means we cannot use any C library routine that might be non-reentrant.
* malloc/free are often non-reentrant, and anything that might call them is
* just as dangerous. We avoid sprintf here for that reason. Building up
* error messages with strcpy/strcat is tedious but should be quite safe.
* We also save/restore errno in case the signal handler support doesn't.
*
* NOTE: this routine must not generate any error message longer than
* INITIAL_EXPBUFFER_SIZE (currently 256), since we dare not try to
* expand conn->errorMessage!
*/
int
PQrequestCancel(PGconn *conn)
{
int save_errno = SOCK_ERRNO;
int tmpsock = -1;
char sebuf[256];
struct
{
uint32 packetlen;
CancelRequestPacket cp;
} crp;
/* Check we have an open connection */
if (!conn)
return FALSE;
if (conn->sock < 0)
{
strcpy(conn->errorMessage.data,
"PQrequestCancel() -- connection is not open\n");
conn->errorMessage.len = strlen(conn->errorMessage.data);
#ifdef WIN32
WSASetLastError(save_errno);
#else
errno = save_errno;
#endif
return FALSE;
}
/*
* We need to open a temporary connection to the postmaster. Use the
* information saved by connectDB to do this with only kernel calls.
*/
if ((tmpsock = socket(conn->raddr.addr.ss_family, SOCK_STREAM, 0)) < 0)
{
strcpy(conn->errorMessage.data,
"PQrequestCancel() -- socket() failed: ");
goto cancel_errReturn;
}
retry3:
2003-08-04 02:43:34 +02:00
if (connect(tmpsock, (struct sockaddr *) & conn->raddr.addr,
conn->raddr.salen) < 0)
{
if (SOCK_ERRNO == EINTR)
/* Interrupted system call - we'll just try again */
goto retry3;
strcpy(conn->errorMessage.data,
"PQrequestCancel() -- connect() failed: ");
goto cancel_errReturn;
}
/*
* We needn't set nonblocking I/O or NODELAY options here.
*/
/* Create and send the cancel request packet. */
crp.packetlen = htonl((uint32) sizeof(crp));
crp.cp.cancelRequestCode = (MsgType) htonl(CANCEL_REQUEST_CODE);
crp.cp.backendPID = htonl(conn->be_pid);
crp.cp.cancelAuthCode = htonl(conn->be_key);
retry4:
if (send(tmpsock, (char *) &crp, sizeof(crp), 0) != (int) sizeof(crp))
{
if (SOCK_ERRNO == EINTR)
/* Interrupted system call - we'll just try again */
goto retry4;
strcpy(conn->errorMessage.data,
"PQrequestCancel() -- send() failed: ");
goto cancel_errReturn;
}
/* Sent it, done */
closesocket(tmpsock);
#ifdef WIN32
WSASetLastError(save_errno);
#else
errno = save_errno;
#endif
return TRUE;
cancel_errReturn:
strcat(conn->errorMessage.data, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
strcat(conn->errorMessage.data, "\n");
conn->errorMessage.len = strlen(conn->errorMessage.data);
if (tmpsock >= 0)
{
closesocket(tmpsock);
#ifdef WIN32
WSASetLastError(save_errno);
#else
errno = save_errno;
#endif
}
return FALSE;
}
/*
* pqPacketSend() -- convenience routine to send a message to server.
*
* pack_type: the single-byte message type code. (Pass zero for startup
* packets, which have no message type code.)
*
* buf, buf_len: contents of message. The given length includes only what
* is in buf; the message type and message length fields are added here.
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
*
* Note: all messages sent with this routine have a length word, whether
* it's protocol 2.0 or 3.0.
*/
int
pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len)
{
/* Start the message. */
if (pqPutMsgStart(pack_type, true, conn))
return STATUS_ERROR;
/* Send the message body. */
if (pqPutnchar(buf, buf_len, conn))
return STATUS_ERROR;
/* Finish the message. */
if (pqPutMsgEnd(conn))
return STATUS_ERROR;
/* Flush to ensure backend gets it. */
if (pqFlush(conn))
return STATUS_ERROR;
return STATUS_OK;
}
#ifndef SYSCONFDIR
2001-03-22 05:01:46 +01:00
#error "You must compile this file with SYSCONFDIR defined."
#endif
#define MAXBUFSIZE 256
2000-12-07 03:04:30 +01:00
static int
parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
{
2001-03-22 05:01:46 +01:00
char *service = conninfo_getval(options, "service");
char *serviceFile = SYSCONFDIR "/pg_service.conf";
int group_found = 0;
int linenr = 0,
i;
/*
* We have to special-case the environment variable PGSERVICE here,
* since this is and should be called before inserting environment
* defaults for other connection options.
*/
if (service == NULL)
service = getenv("PGSERVICE");
2001-03-22 05:01:46 +01:00
if (service != NULL)
{
FILE *f;
char buf[MAXBUFSIZE],
*line;
f = fopen(serviceFile, "r");
if (f == NULL)
{
printfPQExpBuffer(errorMessage, "ERROR: Service file '%s' not found\n",
serviceFile);
return 1;
}
while ((line = fgets(buf, MAXBUFSIZE - 1, f)) != NULL)
{
linenr++;
if (strlen(line) >= MAXBUFSIZE - 2)
{
fclose(f);
printfPQExpBuffer(errorMessage,
"ERROR: line %d too long in service file '%s'\n",
linenr,
serviceFile);
return 2;
}
/* ignore EOL at end of line */
if (strlen(line) && line[strlen(line) - 1] == '\n')
line[strlen(line) - 1] = 0;
/* ignore leading blanks */
while (*line && isspace((unsigned char) line[0]))
line++;
/* ignore comments and empty lines */
if (strlen(line) == 0 || line[0] == '#')
continue;
/* Check for right groupname */
if (line[0] == '[')
{
if (group_found)
{
/* group info already read */
fclose(f);
return 0;
}
if (strncmp(line + 1, service, strlen(service)) == 0 &&
line[strlen(service) + 1] == ']')
group_found = 1;
else
group_found = 0;
}
else
{
if (group_found)
{
/*
* Finally, we are in the right group and can parse
* the line
*/
char *key,
*val;
int found_keyword;
key = line;
val = strchr(line, '=');
2003-08-04 02:43:34 +02:00
if (val == NULL)
2001-03-22 05:01:46 +01:00
{
printfPQExpBuffer(errorMessage,
"ERROR: syntax error in service file '%s', line %d\n",
serviceFile,
linenr);
fclose(f);
return 3;
}
*val++ = '\0';
/*
2003-08-04 02:43:34 +02:00
* If not already set, set the database name to the
* name of the service
*/
for (i = 0; options[i].keyword; i++)
{
if (strcmp(options[i].keyword, "dbname") == 0)
{
if (options[i].val == NULL)
options[i].val = strdup(service);
break;
}
}
/*
* Set the parameter --- but don't override any
* previous explicit setting.
*/
2001-03-22 05:01:46 +01:00
found_keyword = 0;
for (i = 0; options[i].keyword; i++)
{
if (strcmp(options[i].keyword, key) == 0)
{
if (options[i].val == NULL)
options[i].val = strdup(val);
2001-03-22 05:01:46 +01:00
found_keyword = 1;
break;
2001-03-22 05:01:46 +01:00
}
}
if (!found_keyword)
{
printfPQExpBuffer(errorMessage,
"ERROR: syntax error in service file '%s', line %d\n",
serviceFile,
linenr);
fclose(f);
return 3;
}
}
}
}
fclose(f);
}
return 0;
}
/*
* Conninfo parser routine
*
* If successful, a malloc'd PQconninfoOption array is returned.
* If not successful, NULL is returned and an error message is
* left in errorMessage.
*/
static PQconninfoOption *
conninfo_parse(const char *conninfo, PQExpBuffer errorMessage)
{
char *pname;
char *pval;
char *buf;
char *tmp;
char *cp;
char *cp2;
PQconninfoOption *options;
PQconninfoOption *option;
char errortmp[PQERRORMSG_LENGTH];
/* Make a working copy of PQconninfoOptions */
options = malloc(sizeof(PQconninfoOptions));
if (options == NULL)
{
printfPQExpBuffer(errorMessage,
libpq_gettext("out of memory\n"));
return NULL;
}
memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
/* Need a modifiable copy of the input string */
if ((buf = strdup(conninfo)) == NULL)
{
printfPQExpBuffer(errorMessage,
libpq_gettext("out of memory\n"));
PQconninfoFree(options);
return NULL;
}
cp = buf;
while (*cp)
{
/* Skip blanks before the parameter name */
if (isspace((unsigned char) *cp))
{
cp++;
continue;
}
/* Get the parameter name */
pname = cp;
while (*cp)
{
if (*cp == '=')
break;
if (isspace((unsigned char) *cp))
{
*cp++ = '\0';
while (*cp)
{
if (!isspace((unsigned char) *cp))
break;
cp++;
}
break;
}
cp++;
}
/* Check that there is a following '=' */
if (*cp != '=')
{
printfPQExpBuffer(errorMessage,
libpq_gettext("missing \"=\" after \"%s\" in connection info string\n"),
pname);
PQconninfoFree(options);
free(buf);
return NULL;
}
*cp++ = '\0';
/* Skip blanks after the '=' */
while (*cp)
{
if (!isspace((unsigned char) *cp))
break;
cp++;
}
/* Get the parameter value */
pval = cp;
if (*cp != '\'')
{
cp2 = pval;
while (*cp)
{
if (isspace((unsigned char) *cp))
{
*cp++ = '\0';
break;
}
if (*cp == '\\')
{
cp++;
if (*cp != '\0')
*cp2++ = *cp++;
}
else
*cp2++ = *cp++;
}
*cp2 = '\0';
}
else
{
cp2 = pval;
cp++;
for (;;)
{
if (*cp == '\0')
{
printfPQExpBuffer(errorMessage,
libpq_gettext("unterminated quoted string in connection info string\n"));
PQconninfoFree(options);
free(buf);
return NULL;
}
if (*cp == '\\')
{
cp++;
if (*cp != '\0')
*cp2++ = *cp++;
continue;
}
if (*cp == '\'')
{
*cp2 = '\0';
cp++;
break;
}
*cp2++ = *cp++;
}
}
/*
* Now we have the name and the value. Search for the param
* record.
*/
for (option = options; option->keyword != NULL; option++)
{
if (strcmp(option->keyword, pname) == 0)
break;
}
if (option->keyword == NULL)
{
printfPQExpBuffer(errorMessage,
libpq_gettext("invalid connection option \"%s\"\n"),
pname);
PQconninfoFree(options);
free(buf);
return NULL;
}
/*
* Store the value
*/
if (option->val)
free(option->val);
option->val = strdup(pval);
}
/* Done with the modifiable input string */
free(buf);
/*
2003-08-04 02:43:34 +02:00
* If there's a service spec, use it to obtain any
* not-explicitly-given parameters.
*/
2001-03-22 05:01:46 +01:00
if (parseServiceInfo(options, errorMessage))
{
PQconninfoFree(options);
return NULL;
}
/*
* Get the fallback resources for parameters not specified in the
* conninfo string nor the service.
*/
for (option = options; option->keyword != NULL; option++)
{
if (option->val != NULL)
continue; /* Value was in conninfo or service */
/*
* Try to get the environment variable fallback
*/
if (option->envvar != NULL)
{
if ((tmp = getenv(option->envvar)) != NULL)
{
option->val = strdup(tmp);
continue;
}
}
/*
* No environment variable specified or this one isn't set - try
* compiled in
*/
if (option->compiled != NULL)
{
option->val = strdup(option->compiled);
continue;
}
/*
* Special handling for user
*/
if (strcmp(option->keyword, "user") == 0)
{
1998-09-20 06:51:12 +02:00
option->val = fe_getauthname(errortmp);
/* note any error message is thrown away */
1998-09-20 06:51:12 +02:00
continue;
}
}
return options;
}
static char *
conninfo_getval(PQconninfoOption *connOptions,
const char *keyword)
{
PQconninfoOption *option;
for (option = connOptions; option->keyword != NULL; option++)
{
if (strcmp(option->keyword, keyword) == 0)
return option->val;
}
return NULL;
}
void
PQconninfoFree(PQconninfoOption *connOptions)
{
PQconninfoOption *option;
if (connOptions == NULL)
return;
for (option = connOptions; option->keyword != NULL; option++)
{
if (option->val != NULL)
free(option->val);
}
free(connOptions);
}
/* =========== accessor functions for PGconn ========= */
char *
PQdb(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->dbName;
}
char *
PQuser(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->pguser;
}
char *
PQpass(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->pgpass;
}
char *
PQhost(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
2000-11-27 22:12:25 +01:00
return conn->pghost ? conn->pghost : conn->pgunixsocket;
}
char *
PQport(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->pgport;
}
char *
PQtty(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->pgtty;
}
char *
PQoptions(const PGconn *conn)
{
if (!conn)
return (char *) NULL;
return conn->pgoptions;
}
ConnStatusType
PQstatus(const PGconn *conn)
{
if (!conn)
return CONNECTION_BAD;
return conn->status;
}
PGTransactionStatusType
PQtransactionStatus(const PGconn *conn)
{
if (!conn || conn->status != CONNECTION_OK)
return PQTRANS_UNKNOWN;
if (conn->asyncStatus != PGASYNC_IDLE)
return PQTRANS_ACTIVE;
return conn->xactStatus;
}
const char *
PQparameterStatus(const PGconn *conn, const char *paramName)
{
const pgParameterStatus *pstatus;
if (!conn || !paramName)
return NULL;
for (pstatus = conn->pstatus; pstatus != NULL; pstatus = pstatus->next)
{
if (strcmp(pstatus->name, paramName) == 0)
return pstatus->value;
}
return NULL;
}
int
PQprotocolVersion(const PGconn *conn)
{
if (!conn)
return 0;
if (conn->status == CONNECTION_BAD)
return 0;
return PG_PROTOCOL_MAJOR(conn->pversion);
}
char *
PQerrorMessage(const PGconn *conn)
{
if (!conn)
return libpq_gettext("connection pointer is NULL\n");
return conn->errorMessage.data;
}
int
PQsocket(const PGconn *conn)
{
if (!conn)
return -1;
return conn->sock;
}
int
PQbackendPID(const PGconn *conn)
{
if (!conn || conn->status != CONNECTION_OK)
return 0;
return conn->be_pid;
}
2000-01-15 06:37:21 +01:00
int
PQclientEncoding(const PGconn *conn)
2000-01-15 06:37:21 +01:00
{
if (!conn || conn->status != CONNECTION_OK)
return -1;
return conn->client_encoding;
}
int
PQsetClientEncoding(PGconn *conn, const char *encoding)
{
char qbuf[128];
static char query[] = "set client_encoding to '%s'";
PGresult *res;
int status;
if (!conn || conn->status != CONNECTION_OK)
return -1;
if (!encoding)
return -1;
/* check query buffer overflow */
if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
return -1;
/* ok, now send a query */
sprintf(qbuf, query, encoding);
res = PQexec(conn, qbuf);
if (res == (PGresult *) NULL)
return -1;
if (res->resultStatus != PGRES_COMMAND_OK)
status = -1;
else
{
/* change libpq internal encoding */
conn->client_encoding = pg_char_to_encoding(encoding);
status = 0; /* everything is ok */
}
PQclear(res);
return (status);
}
PGVerbosity
PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
{
2003-08-04 02:43:34 +02:00
PGVerbosity old;
if (!conn)
return PQERRORS_DEFAULT;
old = conn->verbosity;
conn->verbosity = verbosity;
return old;
}
void
PQtrace(PGconn *conn, FILE *debug_port)
{
if (conn == NULL)
return;
PQuntrace(conn);
conn->Pfdebug = debug_port;
}
void
PQuntrace(PGconn *conn)
{
if (conn == NULL)
return;
if (conn->Pfdebug)
{
fflush(conn->Pfdebug);
conn->Pfdebug = NULL;
}
}
PQnoticeReceiver
PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg)
{
PQnoticeReceiver old;
if (conn == NULL)
return NULL;
old = conn->noticeHooks.noticeRec;
if (proc)
{
conn->noticeHooks.noticeRec = proc;
conn->noticeHooks.noticeRecArg = arg;
}
return old;
}
PQnoticeProcessor
PQsetNoticeProcessor(PGconn *conn, PQnoticeProcessor proc, void *arg)
{
PQnoticeProcessor old;
if (conn == NULL)
return NULL;
old = conn->noticeHooks.noticeProc;
if (proc)
{
conn->noticeHooks.noticeProc = proc;
conn->noticeHooks.noticeProcArg = arg;
}
return old;
}
/*
* The default notice message receiver just gets the standard notice text
* and sends it to the notice processor. This two-level setup exists
* mostly for backwards compatibility; perhaps we should deprecate use of
* PQsetNoticeProcessor?
*/
static void
defaultNoticeReceiver(void *arg, const PGresult *res)
{
(void) arg; /* not used */
if (res->noticeHooks.noticeProc != NULL)
(*res->noticeHooks.noticeProc) (res->noticeHooks.noticeProcArg,
PQresultErrorMessage(res));
}
/*
* The default notice message processor just prints the
* message on stderr. Applications can override this if they
* want the messages to go elsewhere (a window, for example).
* Note that simply discarding notices is probably a bad idea.
*/
static void
defaultNoticeProcessor(void *arg, const char *message)
{
(void) arg; /* not used */
/* Note: we expect the supplied string to end with a newline already. */
fprintf(stderr, "%s", message);
}
/*
* returns a pointer to the next token or NULL if the current
* token doesn't match
*/
static char *
pwdfMatchesString(char *buf, char *token)
{
2002-09-04 22:31:48 +02:00
char *tbuf,
*ttok;
bool bslash = false;
if (buf == NULL || token == NULL)
return NULL;
tbuf = buf;
ttok = token;
if (*tbuf == '*')
return tbuf + 2;
while (*tbuf != 0)
{
if (*tbuf == '\\' && !bslash)
{
tbuf++;
bslash = true;
}
if (*tbuf == ':' && *ttok == 0 && !bslash)
2002-09-04 22:31:48 +02:00
return tbuf + 1;
bslash = false;
if (*ttok == 0)
return NULL;
if (*tbuf == *ttok)
{
tbuf++;
ttok++;
}
else
return NULL;
}
return NULL;
}
/* Get a password from the password file. Return value is malloc'd. */
static char *
PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
{
2002-09-04 22:31:48 +02:00
FILE *fp;
char *pgpassfile;
char *home;
struct stat stat_buf;
2002-09-04 22:31:48 +02:00
#define LINELEN NAMEDATALEN*5
2002-09-04 22:31:48 +02:00
char buf[LINELEN];
if (dbname == NULL || strlen(dbname) == 0)
return NULL;
if (username == NULL || strlen(username) == 0)
return NULL;
if (hostname == NULL)
hostname = DefaultHost;
if (port == NULL)
port = DEF_PGPORT_STR;
/* Look for it in the home dir */
home = getenv("HOME");
if (!home)
return NULL;
pgpassfile = malloc(strlen(home) + 1 + strlen(PGPASSFILE) + 1);
if (!pgpassfile)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
return NULL;
}
sprintf(pgpassfile, "%s/%s", home, PGPASSFILE);
/* If password file cannot be opened, ignore it. */
if (stat(pgpassfile, &stat_buf) == -1)
{
free(pgpassfile);
return NULL;
}
#ifndef WIN32
/* If password file is insecure, alert the user and ignore it. */
if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
{
fprintf(stderr,
libpq_gettext("WARNING: Password file %s has world or group read access; permission should be u=rw (0600)\n"),
pgpassfile);
free(pgpassfile);
return NULL;
}
#endif
fp = fopen(pgpassfile, "r");
free(pgpassfile);
if (fp == NULL)
return NULL;
2002-09-04 22:31:48 +02:00
while (!feof(fp))
{
char *t = buf,
*ret;
int len;
2002-09-04 22:31:48 +02:00
fgets(buf, LINELEN - 1, fp);
len = strlen(buf);
if (len == 0)
continue;
/* Remove trailing newline */
if (buf[len - 1] == '\n')
buf[len - 1] = 0;
if ((t = pwdfMatchesString(t, hostname)) == NULL ||
2002-09-04 22:31:48 +02:00
(t = pwdfMatchesString(t, port)) == NULL ||
(t = pwdfMatchesString(t, dbname)) == NULL ||
(t = pwdfMatchesString(t, username)) == NULL)
continue;
ret = strdup(t);
fclose(fp);
return ret;
}
fclose(fp);
return NULL;
#undef LINELEN
}