mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
First phase of FE/BE protocol modifications: new StartupPacket layout
with variable-width fields. No more truncation of long user names. Also, libpq can now send its environment-variable-driven SET commands as part of the startup packet, saving round trips to server.
This commit is contained in:
parent
76fd678c06
commit
cb7fb3ca95
@ -1,5 +1,5 @@
|
||||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.117 2003/03/25 16:15:37 petere Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.118 2003/04/17 22:26:00 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="libpq">
|
||||
@ -193,7 +193,7 @@ PGconn *PQconnectdb(const char *conninfo);
|
||||
<term><literal>tty</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A file or <acronym>TTY</acronym> for optional debug output from the server.
|
||||
Ignored (formerly, this specified where to send server debug output).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -669,6 +669,9 @@ char *PQport(const PGconn *conn);
|
||||
<listitem>
|
||||
<para>
|
||||
Returns the debug <acronym>TTY</acronym> of the connection.
|
||||
(This is obsolete, since the server no longer pays attention
|
||||
to the <acronym>TTY</acronym> setting, but the function remains
|
||||
for backwards compatibility.)
|
||||
<synopsis>
|
||||
char *PQtty(const PGconn *conn);
|
||||
</synopsis>
|
||||
@ -2365,12 +2368,6 @@ the <productname>PostgreSQL</productname> server.
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<envar>PGTTY</envar> sets the file or <acronym>TTY</> on which debugging
|
||||
messages from the server are displayed.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<envar>PGREQUIRESSL</envar> sets whether or not the connection must be
|
||||
made over <acronym>SSL</acronym>. If set to
|
||||
<quote>1</quote>, <application>libpq</>
|
||||
@ -2678,7 +2675,7 @@ main()
|
||||
pgport = NULL; /* port of the backend server */
|
||||
pgoptions = NULL; /* special options to start up the backend
|
||||
* server */
|
||||
pgtty = NULL; /* debugging tty for the backend server */
|
||||
pgtty = NULL; /* unused */
|
||||
dbName = "template1";
|
||||
|
||||
/* make a connection to the database */
|
||||
@ -2826,7 +2823,7 @@ main()
|
||||
pgport = NULL; /* port of the backend server */
|
||||
pgoptions = NULL; /* special options to start up the backend
|
||||
* server */
|
||||
pgtty = NULL; /* debugging tty for the backend server */
|
||||
pgtty = NULL; /* unused */
|
||||
dbName = getenv("USER"); /* change this to the name of your test
|
||||
* database */
|
||||
|
||||
@ -2950,7 +2947,7 @@ main()
|
||||
pgport = NULL; /* port of the backend server */
|
||||
pgoptions = NULL; /* special options to start up the backend
|
||||
* server */
|
||||
pgtty = NULL; /* debugging tty for the backend server */
|
||||
pgtty = NULL; /* unused */
|
||||
|
||||
dbName = getenv("USER"); /* change this to the name of your test
|
||||
* database */
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.97 2003/02/14 14:05:00 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.98 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -29,7 +29,6 @@
|
||||
#include "libpq/crypt.h"
|
||||
#include "libpq/hba.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/password.h"
|
||||
#include "libpq/pqcomm.h"
|
||||
#include "libpq/pqformat.h"
|
||||
#include "miscadmin.h"
|
||||
@ -378,7 +377,7 @@ auth_failed(Port *port, int status)
|
||||
}
|
||||
|
||||
elog(FATAL, "%s authentication failed for user \"%s\"",
|
||||
authmethod, port->user);
|
||||
authmethod, port->user_name);
|
||||
/* doesn't return */
|
||||
}
|
||||
|
||||
@ -427,7 +426,7 @@ ClientAuthentication(Port *port)
|
||||
|
||||
elog(FATAL,
|
||||
"No pg_hba.conf entry for host %s, user %s, database %s",
|
||||
hostinfo, port->user, port->database);
|
||||
hostinfo, port->user_name, port->database_name);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -638,10 +637,12 @@ CheckPAMAuth(Port *port, char *user, char *password)
|
||||
* not allocated */
|
||||
|
||||
/* Optionally, one can set the service name in pg_hba.conf */
|
||||
if (port->auth_arg[0] == '\0')
|
||||
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@", &pam_passw_conv, &pamh);
|
||||
if (port->auth_arg && port->auth_arg[0] != '\0')
|
||||
retval = pam_start(port->auth_arg, "pgsql@",
|
||||
&pam_passw_conv, &pamh);
|
||||
else
|
||||
retval = pam_start(port->auth_arg, "pgsql@", &pam_passw_conv, &pamh);
|
||||
retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@",
|
||||
&pam_passw_conv, &pamh);
|
||||
|
||||
if (retval != PAM_SUCCESS)
|
||||
{
|
||||
@ -741,7 +742,7 @@ recv_and_check_password_packet(Port *port)
|
||||
/* Do not echo password to logs, for security. */
|
||||
elog(DEBUG5, "received password packet");
|
||||
|
||||
result = md5_crypt_verify(port, port->user, buf.data);
|
||||
result = md5_crypt_verify(port, port->user_name, buf.data);
|
||||
|
||||
pfree(buf.data);
|
||||
return result;
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.51 2002/12/05 18:52:42 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.52 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -87,15 +87,19 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
|
||||
/* pg_shadow plain, double-encrypt */
|
||||
char *crypt_pwd2 = palloc(MD5_PASSWD_LEN + 1);
|
||||
|
||||
if (!EncryptMD5(shadow_pass, port->user, strlen(port->user),
|
||||
if (!EncryptMD5(shadow_pass,
|
||||
port->user_name,
|
||||
strlen(port->user_name),
|
||||
crypt_pwd2))
|
||||
{
|
||||
pfree(crypt_pwd);
|
||||
pfree(crypt_pwd2);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
if (!EncryptMD5(crypt_pwd2 + strlen("md5"), port->md5Salt,
|
||||
sizeof(port->md5Salt), crypt_pwd))
|
||||
if (!EncryptMD5(crypt_pwd2 + strlen("md5"),
|
||||
port->md5Salt,
|
||||
sizeof(port->md5Salt),
|
||||
crypt_pwd))
|
||||
{
|
||||
pfree(crypt_pwd);
|
||||
pfree(crypt_pwd2);
|
||||
@ -117,7 +121,9 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
|
||||
{
|
||||
/* Encrypt user-supplied password to match MD5 in pg_shadow */
|
||||
crypt_client_pass = palloc(MD5_PASSWD_LEN + 1);
|
||||
if (!EncryptMD5(client_pass, port->user, strlen(port->user),
|
||||
if (!EncryptMD5(client_pass,
|
||||
port->user_name,
|
||||
strlen(port->user_name),
|
||||
crypt_client_pass))
|
||||
{
|
||||
pfree(crypt_client_pass);
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.98 2003/04/13 04:07:17 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.99 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -471,15 +471,17 @@ check_db(char *dbname, char *user, char *param_str)
|
||||
|
||||
/*
|
||||
* Scan the rest of a host record (after the mask field)
|
||||
* and return the interpretation of it as *userauth_p, auth_arg, and
|
||||
* and return the interpretation of it as *userauth_p, *auth_arg_p, and
|
||||
* *error_p. line points to the next token of the line.
|
||||
*/
|
||||
static void
|
||||
parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg,
|
||||
parse_hba_auth(List *line, UserAuth *userauth_p, char **auth_arg_p,
|
||||
bool *error_p)
|
||||
{
|
||||
char *token;
|
||||
|
||||
*auth_arg_p = NULL;
|
||||
|
||||
if (!line)
|
||||
*error_p = true;
|
||||
else
|
||||
@ -514,11 +516,10 @@ parse_hba_auth(List *line, UserAuth *userauth_p, char *auth_arg,
|
||||
if (!*error_p)
|
||||
{
|
||||
/* Get the authentication argument token, if any */
|
||||
if (!line)
|
||||
auth_arg[0] = '\0';
|
||||
else
|
||||
if (line)
|
||||
{
|
||||
StrNCpy(auth_arg, lfirst(line), MAX_AUTH_ARG - 1);
|
||||
token = lfirst(line);
|
||||
*auth_arg_p = pstrdup(token);
|
||||
/* If there is more on the line, it is an error */
|
||||
if (lnext(line))
|
||||
*error_p = true;
|
||||
@ -570,7 +571,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
|
||||
goto hba_syntax;
|
||||
|
||||
/* Read the rest of the line. */
|
||||
parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
|
||||
parse_hba_auth(line, &port->auth_method, &port->auth_arg, error_p);
|
||||
if (*error_p)
|
||||
goto hba_syntax;
|
||||
|
||||
@ -642,7 +643,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
|
||||
line = lnext(line);
|
||||
if (!line)
|
||||
goto hba_syntax;
|
||||
parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
|
||||
parse_hba_auth(line, &port->auth_method, &port->auth_arg, error_p);
|
||||
if (*error_p)
|
||||
goto hba_syntax;
|
||||
|
||||
@ -654,9 +655,9 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
|
||||
else
|
||||
goto hba_syntax;
|
||||
|
||||
if (!check_db(port->database, port->user, db))
|
||||
if (!check_db(port->database_name, port->user_name, db))
|
||||
return;
|
||||
if (!check_user(port->user, user))
|
||||
if (!check_user(port->user_name, user))
|
||||
return;
|
||||
|
||||
/* Success */
|
||||
@ -946,7 +947,7 @@ check_ident_usermap(const char *usermap_name,
|
||||
bool found_entry = false,
|
||||
error = false;
|
||||
|
||||
if (usermap_name[0] == '\0')
|
||||
if (usermap_name == NULL || usermap_name[0] == '\0')
|
||||
{
|
||||
elog(LOG, "check_ident_usermap: hba configuration file does not "
|
||||
"have the usermap field filled in in the entry that pertains "
|
||||
@ -1387,7 +1388,7 @@ authident(hbaPort *port)
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (check_ident_usermap(port->auth_arg, port->user, ident_user))
|
||||
if (check_ident_usermap(port->auth_arg, port->user_name, ident_user))
|
||||
return STATUS_OK;
|
||||
else
|
||||
return STATUS_ERROR;
|
||||
|
@ -37,7 +37,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.310 2003/04/06 22:45:22 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.311 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
*
|
||||
@ -105,11 +105,10 @@
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/ps_status.h"
|
||||
#include "bootstrap/bootstrap.h"
|
||||
|
||||
#include "pgstat.h"
|
||||
|
||||
|
||||
#define INVALID_SOCK (-1)
|
||||
#define ARGV_SIZE 64
|
||||
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t UnBlockSig,
|
||||
@ -1114,10 +1113,11 @@ initMasks(fd_set *rmask, fd_set *wmask)
|
||||
static int
|
||||
ProcessStartupPacket(Port *port, bool SSLdone)
|
||||
{
|
||||
StartupPacket *packet;
|
||||
enum CAC_state cac;
|
||||
int32 len;
|
||||
void *buf;
|
||||
ProtocolVersion proto;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
if (pq_getbytes((char *) &len, 4) == EOF)
|
||||
{
|
||||
@ -1128,11 +1128,20 @@ ProcessStartupPacket(Port *port, bool SSLdone)
|
||||
len = ntohl(len);
|
||||
len -= 4;
|
||||
|
||||
if (len < sizeof(ProtocolVersion) || len > sizeof(StartupPacket))
|
||||
if (len < (int32) sizeof(ProtocolVersion) ||
|
||||
len > MAX_STARTUP_PACKET_LENGTH)
|
||||
elog(FATAL, "invalid length of startup packet");
|
||||
|
||||
/* Ensure we see zeroes for any bytes not sent */
|
||||
buf = palloc0(sizeof(StartupPacket));
|
||||
/*
|
||||
* Allocate at least the size of an old-style startup packet, plus one
|
||||
* extra byte, and make sure all are zeroes. This ensures we will have
|
||||
* null termination of all strings, in both fixed- and variable-length
|
||||
* packet layouts.
|
||||
*/
|
||||
if (len <= (int32) sizeof(StartupPacket))
|
||||
buf = palloc0(sizeof(StartupPacket) + 1);
|
||||
else
|
||||
buf = palloc0(len + 1);
|
||||
|
||||
if (pq_getbytes(buf, len) == EOF)
|
||||
{
|
||||
@ -1140,21 +1149,19 @@ ProcessStartupPacket(Port *port, bool SSLdone)
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
packet = buf;
|
||||
|
||||
/*
|
||||
* The first field is either a protocol version number or a special
|
||||
* request code.
|
||||
*/
|
||||
port->proto = ntohl(packet->protoVersion);
|
||||
port->proto = proto = ntohl(*((ProtocolVersion *) buf));
|
||||
|
||||
if (port->proto == CANCEL_REQUEST_CODE)
|
||||
if (proto == CANCEL_REQUEST_CODE)
|
||||
{
|
||||
processCancelRequest(port, packet);
|
||||
processCancelRequest(port, buf);
|
||||
return 127; /* XXX */
|
||||
}
|
||||
|
||||
if (port->proto == NEGOTIATE_SSL_CODE && !SSLdone)
|
||||
if (proto == NEGOTIATE_SSL_CODE && !SSLdone)
|
||||
{
|
||||
char SSLok;
|
||||
|
||||
@ -1187,39 +1194,113 @@ ProcessStartupPacket(Port *port, bool SSLdone)
|
||||
|
||||
/* Check we can handle the protocol the frontend is using. */
|
||||
|
||||
if (PG_PROTOCOL_MAJOR(port->proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
||||
PG_PROTOCOL_MAJOR(port->proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
||||
(PG_PROTOCOL_MAJOR(port->proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
||||
PG_PROTOCOL_MINOR(port->proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
||||
elog(FATAL, "unsupported frontend protocol");
|
||||
if (PG_PROTOCOL_MAJOR(proto) < PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST) ||
|
||||
PG_PROTOCOL_MAJOR(proto) > PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) ||
|
||||
(PG_PROTOCOL_MAJOR(proto) == PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST) &&
|
||||
PG_PROTOCOL_MINOR(proto) > PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST)))
|
||||
elog(FATAL, "unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u",
|
||||
PG_PROTOCOL_MAJOR(proto), PG_PROTOCOL_MINOR(proto),
|
||||
PG_PROTOCOL_MAJOR(PG_PROTOCOL_EARLIEST),
|
||||
PG_PROTOCOL_MAJOR(PG_PROTOCOL_LATEST),
|
||||
PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST));
|
||||
|
||||
/*
|
||||
* Get the parameters from the startup packet as C strings. The
|
||||
* packet destination was cleared first so a short packet has zeros
|
||||
* silently added.
|
||||
* XXX temporary for 3.0 protocol development: we are using the minor
|
||||
* number as a test-version number. Insist it match exactly so people
|
||||
* don't get burnt by using yesterday's libpq with today's server.
|
||||
* XXX this must go away before release!!!
|
||||
*/
|
||||
StrNCpy(port->database, packet->database, sizeof(port->database));
|
||||
StrNCpy(port->user, packet->user, sizeof(port->user));
|
||||
StrNCpy(port->options, packet->options, sizeof(port->options));
|
||||
StrNCpy(port->tty, packet->tty, sizeof(port->tty));
|
||||
|
||||
/* The database defaults to the user name. */
|
||||
if (port->database[0] == '\0')
|
||||
StrNCpy(port->database, packet->user, sizeof(port->database));
|
||||
if (PG_PROTOCOL_MAJOR(proto) == 3 &&
|
||||
PG_PROTOCOL_MINOR(proto) != PG_PROTOCOL_MINOR(PG_PROTOCOL_LATEST))
|
||||
elog(FATAL, "Your development libpq is out of sync with the server");
|
||||
|
||||
/*
|
||||
* Truncate given database and user names to length of a Postgres
|
||||
* name. This avoids lookup failures when overlength names are given.
|
||||
* Now fetch parameters out of startup packet and save them into the
|
||||
* Port structure. All data structures attached to the Port struct
|
||||
* must be allocated in TopMemoryContext so that they won't disappear
|
||||
* when we pass them to PostgresMain (see DoBackend). We need not worry
|
||||
* about leaking this storage on failure, since we aren't in the postmaster
|
||||
* process anymore.
|
||||
*/
|
||||
if ((int) sizeof(port->database) >= NAMEDATALEN)
|
||||
port->database[NAMEDATALEN - 1] = '\0';
|
||||
if ((int) sizeof(port->user) >= NAMEDATALEN)
|
||||
port->user[NAMEDATALEN - 1] = '\0';
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
if (PG_PROTOCOL_MAJOR(proto) >= 3)
|
||||
{
|
||||
int32 offset = sizeof(ProtocolVersion);
|
||||
|
||||
/*
|
||||
* Scan packet body for name/option pairs. We can assume any
|
||||
* string beginning within the packet body is null-terminated,
|
||||
* thanks to zeroing extra byte above.
|
||||
*/
|
||||
port->guc_options = NIL;
|
||||
|
||||
while (offset < len)
|
||||
{
|
||||
char *nameptr = ((char *) buf) + offset;
|
||||
int32 valoffset;
|
||||
char *valptr;
|
||||
|
||||
if (*nameptr == '\0')
|
||||
break; /* found packet terminator */
|
||||
valoffset = offset + strlen(nameptr) + 1;
|
||||
if (valoffset >= len)
|
||||
break; /* missing value, will complain below */
|
||||
valptr = ((char *) buf) + valoffset;
|
||||
|
||||
if (strcmp(nameptr, "database") == 0)
|
||||
port->database_name = pstrdup(valptr);
|
||||
else if (strcmp(nameptr, "user") == 0)
|
||||
port->user_name = pstrdup(valptr);
|
||||
else if (strcmp(nameptr, "options") == 0)
|
||||
port->cmdline_options = pstrdup(valptr);
|
||||
else
|
||||
{
|
||||
/* Assume it's a generic GUC option */
|
||||
port->guc_options = lappend(port->guc_options,
|
||||
pstrdup(nameptr));
|
||||
port->guc_options = lappend(port->guc_options,
|
||||
pstrdup(valptr));
|
||||
}
|
||||
offset = valoffset + strlen(valptr) + 1;
|
||||
}
|
||||
/*
|
||||
* If we didn't find a packet terminator exactly at the end of the
|
||||
* given packet length, complain.
|
||||
*/
|
||||
if (offset != len-1)
|
||||
elog(FATAL, "invalid startup packet layout: expected terminator as last byte");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Get the parameters from the old-style, fixed-width-fields startup
|
||||
* packet as C strings. The packet destination was cleared first so a
|
||||
* short packet has zeros silently added. We have to be prepared to
|
||||
* truncate the pstrdup result for oversize fields, though.
|
||||
*/
|
||||
StartupPacket *packet = (StartupPacket *) buf;
|
||||
|
||||
port->database_name = pstrdup(packet->database);
|
||||
if (strlen(port->database_name) > sizeof(packet->database))
|
||||
port->database_name[sizeof(packet->database)] = '\0';
|
||||
port->user_name = pstrdup(packet->user);
|
||||
if (strlen(port->user_name) > sizeof(packet->user))
|
||||
port->user_name[sizeof(packet->user)] = '\0';
|
||||
port->cmdline_options = pstrdup(packet->options);
|
||||
if (strlen(port->cmdline_options) > sizeof(packet->options))
|
||||
port->cmdline_options[sizeof(packet->options)] = '\0';
|
||||
port->guc_options = NIL;
|
||||
}
|
||||
|
||||
/* Check a user name was given. */
|
||||
if (port->user[0] == '\0')
|
||||
if (port->user_name == NULL || port->user_name[0] == '\0')
|
||||
elog(FATAL, "no PostgreSQL user name specified in startup packet");
|
||||
|
||||
/* The database defaults to the user name. */
|
||||
if (port->database_name == NULL || port->database_name[0] == '\0')
|
||||
port->database_name = pstrdup(port->user_name);
|
||||
|
||||
if (Db_user_namespace)
|
||||
{
|
||||
/*
|
||||
@ -1228,19 +1309,35 @@ ProcessStartupPacket(Port *port, bool SSLdone)
|
||||
* string or they may fake as a local user of another database
|
||||
* attaching to this database.
|
||||
*/
|
||||
if (strchr(port->user, '@') == port->user + strlen(port->user) - 1)
|
||||
*strchr(port->user, '@') = '\0';
|
||||
if (strchr(port->user_name, '@') ==
|
||||
port->user_name + strlen(port->user_name) - 1)
|
||||
*strchr(port->user_name, '@') = '\0';
|
||||
else
|
||||
{
|
||||
/* Append '@' and dbname */
|
||||
char hold_user[SM_DATABASE_USER + 1];
|
||||
char *db_user;
|
||||
|
||||
snprintf(hold_user, SM_DATABASE_USER + 1, "%s@%s", port->user,
|
||||
port->database);
|
||||
strcpy(port->user, hold_user);
|
||||
db_user = palloc(strlen(port->user_name) +
|
||||
strlen(port->database_name) + 2);
|
||||
sprintf(db_user, "%s@%s", port->user_name, port->database_name);
|
||||
port->user_name = db_user;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate given database and user names to length of a Postgres
|
||||
* name. This avoids lookup failures when overlength names are given.
|
||||
*/
|
||||
if (strlen(port->database_name) >= NAMEDATALEN)
|
||||
port->database_name[NAMEDATALEN - 1] = '\0';
|
||||
if (strlen(port->user_name) >= NAMEDATALEN)
|
||||
port->user_name[NAMEDATALEN - 1] = '\0';
|
||||
|
||||
/*
|
||||
* Done putting stuff in TopMemoryContext.
|
||||
*/
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
/*
|
||||
* If we're going to reject the connection due to database state, say
|
||||
* so now instead of wasting cycles on an authentication exchange.
|
||||
@ -2076,13 +2173,11 @@ static int
|
||||
DoBackend(Port *port)
|
||||
{
|
||||
char *remote_host;
|
||||
char *av[ARGV_SIZE * 2];
|
||||
int ac = 0;
|
||||
char debugbuf[ARGV_SIZE];
|
||||
char protobuf[ARGV_SIZE];
|
||||
char dbbuf[ARGV_SIZE];
|
||||
char optbuf[ARGV_SIZE];
|
||||
char ttybuf[ARGV_SIZE];
|
||||
char **av;
|
||||
int maxac;
|
||||
int ac;
|
||||
char debugbuf[32];
|
||||
char protobuf[32];
|
||||
int i;
|
||||
int status;
|
||||
struct timeval now;
|
||||
@ -2225,7 +2320,7 @@ DoBackend(Port *port)
|
||||
* title for ps. It's good to do this as early as possible in
|
||||
* startup.
|
||||
*/
|
||||
init_ps_display(port->user, port->database, remote_host);
|
||||
init_ps_display(port->user_name, port->database_name, remote_host);
|
||||
set_ps_display("authentication");
|
||||
|
||||
/*
|
||||
@ -2243,7 +2338,7 @@ DoBackend(Port *port)
|
||||
|
||||
if (Log_connections)
|
||||
elog(LOG, "connection authorized: user=%s database=%s",
|
||||
port->user, port->database);
|
||||
port->user_name, port->database_name);
|
||||
|
||||
/*
|
||||
* Don't want backend to be able to see the postmaster random number
|
||||
@ -2260,8 +2355,20 @@ DoBackend(Port *port)
|
||||
* The layout of the command line is
|
||||
* postgres [secure switches] -p databasename [insecure switches]
|
||||
* where the switches after -p come from the client request.
|
||||
*
|
||||
* The maximum possible number of commandline arguments that could come
|
||||
* from ExtraOptions or port->cmdline_options is (strlen + 1) / 2; see
|
||||
* split_opts().
|
||||
* ----------------
|
||||
*/
|
||||
maxac = 10; /* for fixed args supplied below */
|
||||
maxac += (strlen(ExtraOptions) + 1) / 2;
|
||||
if (port->cmdline_options)
|
||||
maxac += (strlen(port->cmdline_options) + 1) / 2;
|
||||
|
||||
av = (char **) MemoryContextAlloc(TopMemoryContext,
|
||||
maxac * sizeof(char *));
|
||||
ac = 0;
|
||||
|
||||
av[ac++] = "postgres";
|
||||
|
||||
@ -2270,7 +2377,7 @@ DoBackend(Port *port)
|
||||
*/
|
||||
if (debug_flag > 0)
|
||||
{
|
||||
sprintf(debugbuf, "-d%d", debug_flag);
|
||||
snprintf(debugbuf, sizeof(debugbuf), "-d%d", debug_flag);
|
||||
av[ac++] = debugbuf;
|
||||
}
|
||||
|
||||
@ -2283,7 +2390,7 @@ DoBackend(Port *port)
|
||||
split_opts(av, &ac, ExtraOptions);
|
||||
|
||||
/* Tell the backend what protocol the frontend is using. */
|
||||
sprintf(protobuf, "-v%u", port->proto);
|
||||
snprintf(protobuf, sizeof(protobuf), "-v%u", port->proto);
|
||||
av[ac++] = protobuf;
|
||||
|
||||
/*
|
||||
@ -2291,38 +2398,25 @@ DoBackend(Port *port)
|
||||
* database to use. -p marks the end of secure switches.
|
||||
*/
|
||||
av[ac++] = "-p";
|
||||
|
||||
StrNCpy(dbbuf, port->database, ARGV_SIZE);
|
||||
av[ac++] = dbbuf;
|
||||
av[ac++] = port->database_name;
|
||||
|
||||
/*
|
||||
* Pass the (insecure) option switches from the connection request.
|
||||
* (It's OK to mangle port->cmdline_options now.)
|
||||
*/
|
||||
StrNCpy(optbuf, port->options, ARGV_SIZE);
|
||||
split_opts(av, &ac, optbuf);
|
||||
|
||||
/*
|
||||
* Pass the (insecure) debug output file request.
|
||||
*
|
||||
* NOTE: currently, this is useless code, since the backend will not
|
||||
* honor an insecure -o switch. I left it here since the backend
|
||||
* could be modified to allow insecure -o, given adequate checking
|
||||
* that the specified filename is something safe to write on.
|
||||
*/
|
||||
if (port->tty[0])
|
||||
{
|
||||
StrNCpy(ttybuf, port->tty, ARGV_SIZE);
|
||||
av[ac++] = "-o";
|
||||
av[ac++] = ttybuf;
|
||||
}
|
||||
if (port->cmdline_options)
|
||||
split_opts(av, &ac, port->cmdline_options);
|
||||
|
||||
av[ac] = (char *) NULL;
|
||||
|
||||
Assert(ac < maxac);
|
||||
|
||||
/*
|
||||
* Release postmaster's working memory context so that backend can
|
||||
* recycle the space. Note this does not trash *MyProcPort, because
|
||||
* ConnCreate() allocated that space with malloc() ... else we'd need
|
||||
* to copy the Port data here.
|
||||
* to copy the Port data here. Also, subsidiary data such as the
|
||||
* username isn't lost either; see ProcessStartupPacket().
|
||||
*/
|
||||
MemoryContextSwitchTo(TopMemoryContext);
|
||||
MemoryContextDelete(PostmasterContext);
|
||||
@ -2339,7 +2433,7 @@ DoBackend(Port *port)
|
||||
ClientAuthInProgress = false; /* client_min_messages is active
|
||||
* now */
|
||||
|
||||
return (PostgresMain(ac, av, port->user));
|
||||
return (PostgresMain(ac, av, port->user_name));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2578,11 +2672,10 @@ SSDataBase(int xlop)
|
||||
if ((pid = fork()) == 0) /* child */
|
||||
{
|
||||
const char *statmsg;
|
||||
char *av[ARGV_SIZE * 2];
|
||||
char *av[10];
|
||||
int ac = 0;
|
||||
char nbbuf[ARGV_SIZE];
|
||||
char dbbuf[ARGV_SIZE];
|
||||
char xlbuf[ARGV_SIZE];
|
||||
char nbbuf[32];
|
||||
char xlbuf[32];
|
||||
|
||||
#ifdef LINUX_PROFILE
|
||||
setitimer(ITIMER_PROF, &prof_itimer, NULL);
|
||||
@ -2626,19 +2719,19 @@ SSDataBase(int xlop)
|
||||
/* Set up command-line arguments for subprocess */
|
||||
av[ac++] = "postgres";
|
||||
|
||||
sprintf(nbbuf, "-B%d", NBuffers);
|
||||
snprintf(nbbuf, sizeof(nbbuf), "-B%d", NBuffers);
|
||||
av[ac++] = nbbuf;
|
||||
|
||||
sprintf(xlbuf, "-x%d", xlop);
|
||||
snprintf(xlbuf, sizeof(xlbuf), "-x%d", xlop);
|
||||
av[ac++] = xlbuf;
|
||||
|
||||
av[ac++] = "-p";
|
||||
|
||||
StrNCpy(dbbuf, "template1", ARGV_SIZE);
|
||||
av[ac++] = dbbuf;
|
||||
av[ac++] = "template1";
|
||||
|
||||
av[ac] = (char *) NULL;
|
||||
|
||||
Assert(ac < lengthof(av));
|
||||
|
||||
BootstrapMain(ac, av);
|
||||
ExitPostmaster(0);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.320 2003/03/24 18:33:52 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.321 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
@ -1611,6 +1611,26 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
if (debug_flag >= 5)
|
||||
SetConfigOption("debug_print_rewritten", "true", ctx, gucsource);
|
||||
|
||||
/*
|
||||
* Process any additional GUC variable settings passed in startup packet.
|
||||
*/
|
||||
if (MyProcPort != NULL)
|
||||
{
|
||||
List *gucopts = MyProcPort->guc_options;
|
||||
|
||||
while (gucopts)
|
||||
{
|
||||
char *name,
|
||||
*value;
|
||||
|
||||
name = lfirst(gucopts);
|
||||
gucopts = lnext(gucopts);
|
||||
value = lfirst(gucopts);
|
||||
gucopts = lnext(gucopts);
|
||||
SetConfigOption(name, value, PGC_BACKEND, PGC_S_CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Post-processing for command line options.
|
||||
*/
|
||||
@ -1795,7 +1815,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface ");
|
||||
puts("$Revision: 1.320 $ $Date: 2003/03/24 18:33:52 $\n");
|
||||
puts("$Revision: 1.321 $ $Date: 2003/04/17 22:26:01 $\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: auth.h,v 1.21 2002/06/20 20:29:49 momjian Exp $
|
||||
* $Id: auth.h,v 1.22 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -21,7 +21,7 @@
|
||||
*----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void ClientAuthentication(Port *port);
|
||||
extern void ClientAuthentication(Port *port);
|
||||
|
||||
#define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */
|
||||
#define PG_KRB5_VERSION "PGVER5.1"
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Interface to hba.c
|
||||
*
|
||||
*
|
||||
* $Id: hba.h,v 1.32 2002/04/04 04:25:54 momjian Exp $
|
||||
* $Id: hba.h,v 1.33 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,8 +26,6 @@
|
||||
#define IDENT_PORT 113
|
||||
/* Standard TCP port number for Ident service. Assigned by IANA */
|
||||
|
||||
#define MAX_AUTH_ARG 80 /* Max size of an authentication arg */
|
||||
|
||||
typedef enum UserAuth
|
||||
{
|
||||
uaReject,
|
||||
|
@ -11,15 +11,13 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-be.h,v 1.34 2002/08/29 03:22:01 tgl Exp $
|
||||
* $Id: libpq-be.h,v 1.35 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef LIBPQ_BE_H
|
||||
#define LIBPQ_BE_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "libpq/hba.h"
|
||||
#include "libpq/pqcomm.h"
|
||||
|
||||
@ -32,29 +30,36 @@
|
||||
/*
|
||||
* This is used by the postmaster in its communication with frontends. It
|
||||
* contains all state information needed during this communication before the
|
||||
* backend is run.
|
||||
* backend is run. The Port structure is kept in malloc'd memory and is
|
||||
* still available when a backend is running (see MyProcPort). The data
|
||||
* it points to must also be malloc'd, or else palloc'd in TopMemoryContext,
|
||||
* so that it survives into PostgresMain execution!
|
||||
*/
|
||||
|
||||
typedef struct Port
|
||||
{
|
||||
int sock; /* File descriptor */
|
||||
ProtocolVersion proto; /* FE/BE protocol version */
|
||||
SockAddr laddr; /* local addr (postmaster) */
|
||||
SockAddr raddr; /* remote addr (client) */
|
||||
char md5Salt[4]; /* Password salt */
|
||||
char cryptSalt[2]; /* Password salt */
|
||||
|
||||
/*
|
||||
* Information that needs to be held during the fe/be authentication
|
||||
* handshake.
|
||||
* Information that needs to be saved from the startup packet and passed
|
||||
* into backend execution. "char *" fields are NULL if not set.
|
||||
* guc_options points to a List of alternating option names and values.
|
||||
*/
|
||||
char *database_name;
|
||||
char *user_name;
|
||||
char *cmdline_options;
|
||||
List *guc_options;
|
||||
|
||||
ProtocolVersion proto;
|
||||
char database[SM_DATABASE + 1];
|
||||
char user[SM_DATABASE_USER + 1];
|
||||
char options[SM_OPTIONS + 1];
|
||||
char tty[SM_TTY + 1];
|
||||
char auth_arg[MAX_AUTH_ARG];
|
||||
/*
|
||||
* Information that needs to be held during the authentication cycle.
|
||||
*/
|
||||
UserAuth auth_method;
|
||||
char *auth_arg;
|
||||
char md5Salt[4]; /* Password salt */
|
||||
char cryptSalt[2]; /* Password salt */
|
||||
|
||||
/*
|
||||
* SSL structures
|
||||
|
@ -1,6 +0,0 @@
|
||||
#ifndef PASSWORD_H
|
||||
#define PASSWORD_H
|
||||
|
||||
int verify_password(const Port *port, const char *user, const char *password);
|
||||
|
||||
#endif
|
@ -9,14 +9,13 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pqcomm.h,v 1.75 2003/01/06 09:58:36 petere Exp $
|
||||
* $Id: pqcomm.h,v 1.76 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PQCOMM_H
|
||||
#define PQCOMM_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef WIN32
|
||||
#include <winsock.h>
|
||||
/* workaround for clashing defines of "ERROR" */
|
||||
@ -93,7 +92,7 @@ typedef union SockAddr
|
||||
* functionality).
|
||||
*
|
||||
* If a backend supports version m.n of the protocol it must actually support
|
||||
* versions m.0..n]. Backend support for version m-1 can be dropped after a
|
||||
* versions m.[0..n]. Backend support for version m-1 can be dropped after a
|
||||
* `reasonable' length of time.
|
||||
*
|
||||
* A frontend isn't required to support anything other than the current
|
||||
@ -107,27 +106,26 @@ typedef union SockAddr
|
||||
/* The earliest and latest frontend/backend protocol version supported. */
|
||||
|
||||
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0)
|
||||
#define PG_PROTOCOL_LATEST PG_PROTOCOL(2,0)
|
||||
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,100) /* XXX temporary value */
|
||||
|
||||
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
|
||||
|
||||
typedef ProtocolVersion MsgType;
|
||||
|
||||
|
||||
/*
|
||||
* All packets sent to the postmaster start with the length. This is omitted
|
||||
* from the different packet definitions specified below.
|
||||
* Packet lengths are 4 bytes in network byte order.
|
||||
*
|
||||
* The initial length is omitted from the packet layouts appearing below.
|
||||
*/
|
||||
|
||||
typedef uint32 PacketLen;
|
||||
|
||||
|
||||
/*
|
||||
* Startup message parameters sizes. These must not be changed without changing
|
||||
* the protocol version. These are all strings that are '\0' terminated only if
|
||||
* there is room.
|
||||
*/
|
||||
|
||||
/*
|
||||
* FIXME: remove the fixed size limitations on the database name, user
|
||||
* name, and options fields and use a variable length field instead. The
|
||||
* actual limits on database & user name will then be NAMEDATALEN, which
|
||||
* can be changed without changing the FE/BE protocol. -neilc,2002/08/27
|
||||
* Old-style startup packet layout with fixed-width fields. This is used in
|
||||
* protocol 1.0 and 2.0, but not in later versions. Note that the fields
|
||||
* in this layout are '\0' terminated only if there is room.
|
||||
*/
|
||||
|
||||
#define SM_DATABASE 64
|
||||
@ -138,11 +136,6 @@ typedef uint32 PacketLen;
|
||||
#define SM_UNUSED 64
|
||||
#define SM_TTY 64
|
||||
|
||||
typedef uint32 ProtocolVersion; /* Fe/Be protocol version number */
|
||||
|
||||
typedef ProtocolVersion MsgType;
|
||||
|
||||
|
||||
typedef struct StartupPacket
|
||||
{
|
||||
ProtocolVersion protoVersion; /* Protocol version */
|
||||
@ -156,7 +149,16 @@ typedef struct StartupPacket
|
||||
|
||||
extern bool Db_user_namespace;
|
||||
|
||||
/* These are the authentication requests sent by the backend. */
|
||||
/*
|
||||
* In protocol 3.0 and later, the startup packet length is not fixed, but
|
||||
* we set an arbitrary limit on it anyway. This is just to prevent simple
|
||||
* denial-of-service attacks via sending enough data to run the server
|
||||
* out of memory.
|
||||
*/
|
||||
#define MAX_STARTUP_PACKET_LENGTH 10000
|
||||
|
||||
|
||||
/* These are the authentication request codes sent by the backend. */
|
||||
|
||||
#define AUTH_REQ_OK 0 /* User is authenticated */
|
||||
#define AUTH_REQ_KRB4 1 /* Kerberos V4 */
|
||||
@ -169,12 +171,12 @@ extern bool Db_user_namespace;
|
||||
typedef uint32 AuthRequest;
|
||||
|
||||
|
||||
/* A client can also send a cancel-current-operation request to the postmaster.
|
||||
/*
|
||||
* A client can also send a cancel-current-operation request to the postmaster.
|
||||
* This is uglier than sending it directly to the client's backend, but it
|
||||
* avoids depending on out-of-band communication facilities.
|
||||
*/
|
||||
|
||||
/* The cancel request code must not match any protocol version number
|
||||
*
|
||||
* The cancel request code must not match any protocol version number
|
||||
* we're ever likely to use. This random choice should do.
|
||||
*/
|
||||
#define CANCEL_REQUEST_CODE PG_PROTOCOL(1234,5678)
|
||||
|
@ -10,7 +10,7 @@
|
||||
* exceed INITIAL_EXPBUFFER_SIZE (currently 256 bytes).
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.74 2003/03/10 22:28:21 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-auth.c,v 1.75 2003/04/17 22:26:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -559,7 +559,7 @@ pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
|
||||
default:
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
ret = pqPacketSend(conn, crypt_pwd, strlen(crypt_pwd) + 1);
|
||||
ret = pqPacketSend(conn, 0, crypt_pwd, strlen(crypt_pwd) + 1);
|
||||
if (areq == AUTH_REQ_MD5)
|
||||
free(crypt_pwd);
|
||||
return ret;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.231 2003/04/04 20:42:13 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.232 2003/04/17 22:26:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -64,9 +64,6 @@ inet_aton(const char *cp, struct in_addr * inp)
|
||||
#endif
|
||||
|
||||
|
||||
#define NOTIFYLIST_INITIAL_SIZE 10
|
||||
#define NOTIFYLIST_GROWBY 10
|
||||
|
||||
#define PGPASSFILE ".pgpass"
|
||||
|
||||
/* ----------
|
||||
@ -128,6 +125,10 @@ static const PQconninfoOption PQconninfoOptions[] = {
|
||||
{"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},
|
||||
|
||||
@ -182,12 +183,13 @@ static PQconninfoOption *conninfo_parse(const char *conninfo,
|
||||
PQExpBuffer errorMessage);
|
||||
static char *conninfo_getval(PQconninfoOption *connOptions,
|
||||
const char *keyword);
|
||||
static int build_startup_packet(const PGconn *conn, char *packet);
|
||||
static void defaultNoticeProcessor(void *arg, const char *message);
|
||||
static int parseServiceInfo(PQconninfoOption *options,
|
||||
PQExpBuffer errorMessage);
|
||||
char *pwdfMatchesString(char *buf, char *token);
|
||||
char *PasswordFromFile(char *hostname, char *port, char *dbname,
|
||||
char *username);
|
||||
static char *pwdfMatchesString(char *buf, char *token);
|
||||
static char *PasswordFromFile(char *hostname, char *port, char *dbname,
|
||||
char *username);
|
||||
|
||||
/*
|
||||
* Connecting to a Database
|
||||
@ -396,7 +398,7 @@ PQconndefaults(void)
|
||||
* is NULL or a null string.
|
||||
*
|
||||
* PGTTY identifies tty to which to send messages if <pgtty> argument
|
||||
* is NULL or a null string.
|
||||
* is NULL or a null string. (No longer used by backend.)
|
||||
*
|
||||
* PGOPTIONS identifies connection options if <pgoptions> argument is
|
||||
* NULL or a null string.
|
||||
@ -792,10 +794,6 @@ connectDBStart(PGconn *conn)
|
||||
{
|
||||
int portnum;
|
||||
char portstr[64];
|
||||
#ifdef USE_SSL
|
||||
StartupPacket np; /* Used to negotiate SSL connection */
|
||||
char SSLok;
|
||||
#endif
|
||||
struct addrinfo *addrs = NULL;
|
||||
struct addrinfo *addr_cur = NULL;
|
||||
struct addrinfo hint;
|
||||
@ -980,9 +978,11 @@ retry1:
|
||||
/* Attempt to negotiate SSL usage */
|
||||
if (conn->allow_ssl_try)
|
||||
{
|
||||
memset((char *) &np, 0, sizeof(np));
|
||||
np.protoVersion = htonl(NEGOTIATE_SSL_CODE);
|
||||
if (pqPacketSend(conn, (char *) &np, sizeof(StartupPacket)) != STATUS_OK)
|
||||
ProtocolVersion pv;
|
||||
char SSLok;
|
||||
|
||||
pv = htonl(NEGOTIATE_SSL_CODE);
|
||||
if (pqPacketSend(conn, 0, &pv, sizeof(ProtocolVersion)) != STATUS_OK)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not send SSL negotiation packet: %s\n"),
|
||||
@ -1284,22 +1284,21 @@ keep_going: /* We will come back to here until there
|
||||
|
||||
case CONNECTION_MADE:
|
||||
{
|
||||
StartupPacket sp;
|
||||
char *startpacket;
|
||||
int packetlen;
|
||||
|
||||
/*
|
||||
* Initialize the startup packet.
|
||||
* Build the startup packet.
|
||||
*/
|
||||
|
||||
MemSet((char *) &sp, 0, sizeof(StartupPacket));
|
||||
|
||||
sp.protoVersion = (ProtocolVersion) htonl(PG_PROTOCOL_LIBPQ);
|
||||
|
||||
strncpy(sp.user, conn->pguser, SM_USER);
|
||||
strncpy(sp.database, conn->dbName, SM_DATABASE);
|
||||
strncpy(sp.tty, conn->pgtty, SM_TTY);
|
||||
|
||||
if (conn->pgoptions)
|
||||
strncpy(sp.options, conn->pgoptions, SM_OPTIONS);
|
||||
packetlen = build_startup_packet(conn, NULL);
|
||||
startpacket = (char *) malloc(packetlen);
|
||||
if (!startpacket)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("out of memory\n"));
|
||||
goto error_return;
|
||||
}
|
||||
packetlen = build_startup_packet(conn, startpacket);
|
||||
|
||||
/*
|
||||
* Send the startup packet.
|
||||
@ -1307,16 +1306,17 @@ keep_going: /* We will come back to here until there
|
||||
* Theoretically, this could block, but it really shouldn't
|
||||
* since we only got here if the socket is write-ready.
|
||||
*/
|
||||
|
||||
if (pqPacketSend(conn, (char *) &sp,
|
||||
sizeof(StartupPacket)) != STATUS_OK)
|
||||
if (pqPacketSend(conn, 0, startpacket, packetlen) != STATUS_OK)
|
||||
{
|
||||
printfPQExpBuffer(&conn->errorMessage,
|
||||
libpq_gettext("could not send startup packet: %s\n"),
|
||||
SOCK_STRERROR(SOCK_ERRNO));
|
||||
free(startpacket);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
free(startpacket);
|
||||
|
||||
conn->status = CONNECTION_AWAITING_RESPONSE;
|
||||
return PGRES_POLLING_READING;
|
||||
}
|
||||
@ -1576,7 +1576,6 @@ PQsetenvStart(PGconn *conn)
|
||||
return false;
|
||||
|
||||
conn->setenv_state = SETENV_STATE_ENCODINGS_SEND;
|
||||
conn->next_eo = EnvironmentOptions;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1600,7 +1599,6 @@ PQsetenvPoll(PGconn *conn)
|
||||
{
|
||||
/* These are reading states */
|
||||
case SETENV_STATE_ENCODINGS_WAIT:
|
||||
case SETENV_STATE_OPTION_WAIT:
|
||||
{
|
||||
/* Load waiting data */
|
||||
int n = pqReadData(conn);
|
||||
@ -1615,7 +1613,6 @@ PQsetenvPoll(PGconn *conn)
|
||||
|
||||
/* These are writing states, so we just proceed. */
|
||||
case SETENV_STATE_ENCODINGS_SEND:
|
||||
case SETENV_STATE_OPTION_SEND:
|
||||
break;
|
||||
|
||||
/* Should we raise an error if called when not active? */
|
||||
@ -1669,7 +1666,7 @@ PQsetenvPoll(PGconn *conn)
|
||||
conn->client_encoding = encoding;
|
||||
|
||||
/* Move on to setting the environment options */
|
||||
conn->setenv_state = SETENV_STATE_OPTION_SEND;
|
||||
conn->setenv_state = SETENV_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1708,80 +1705,11 @@ PQsetenvPoll(PGconn *conn)
|
||||
* NULL result indicates that the query is
|
||||
* finished
|
||||
*/
|
||||
/* Move on to setting the environment options */
|
||||
conn->setenv_state = SETENV_STATE_OPTION_SEND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SETENV_STATE_OPTION_SEND:
|
||||
{
|
||||
/* Send an Environment Option */
|
||||
char setQuery[100]; /* note length limits in
|
||||
* sprintf's below */
|
||||
|
||||
if (conn->next_eo->envName)
|
||||
{
|
||||
const char *val;
|
||||
|
||||
if ((val = getenv(conn->next_eo->envName)))
|
||||
{
|
||||
if (strcasecmp(val, "default") == 0)
|
||||
sprintf(setQuery, "SET %s = %.60s",
|
||||
conn->next_eo->pgName, val);
|
||||
else
|
||||
sprintf(setQuery, "SET %s = '%.60s'",
|
||||
conn->next_eo->pgName, val);
|
||||
#ifdef CONNECTDEBUG
|
||||
printf("Use environment variable %s to send %s\n",
|
||||
conn->next_eo->envName, setQuery);
|
||||
#endif
|
||||
if (!PQsendQuery(conn, setQuery))
|
||||
goto error_return;
|
||||
|
||||
conn->setenv_state = SETENV_STATE_OPTION_WAIT;
|
||||
}
|
||||
else
|
||||
conn->next_eo++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No more options to send, so we are done. */
|
||||
conn->setenv_state = SETENV_STATE_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SETENV_STATE_OPTION_WAIT:
|
||||
{
|
||||
if (PQisBusy(conn))
|
||||
return PGRES_POLLING_READING;
|
||||
|
||||
res = PQgetResult(conn);
|
||||
|
||||
if (res)
|
||||
{
|
||||
if (PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||
{
|
||||
PQclear(res);
|
||||
goto error_return;
|
||||
}
|
||||
PQclear(res);
|
||||
/* Keep reading until PQgetResult returns NULL */
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* NULL result indicates that the query is
|
||||
* finished
|
||||
*/
|
||||
/* Send the next option */
|
||||
conn->next_eo++;
|
||||
conn->setenv_state = SETENV_STATE_OPTION_SEND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SETENV_STATE_IDLE:
|
||||
return PGRES_POLLING_OK;
|
||||
|
||||
@ -2225,24 +2153,34 @@ cancel_errReturn:
|
||||
|
||||
/*
|
||||
* pqPacketSend() -- send a single-packet message.
|
||||
* this is like PacketSend(), defined in backend/libpq/pqpacket.c
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
int
|
||||
pqPacketSend(PGconn *conn, const char *buf, size_t len)
|
||||
pqPacketSend(PGconn *conn, char pack_type,
|
||||
const void *buf, size_t buf_len)
|
||||
{
|
||||
/* Send the total packet size. */
|
||||
|
||||
if (pqPutInt(4 + len, 4, conn))
|
||||
/* Send the message type. */
|
||||
if (pack_type != 0)
|
||||
if (pqPutc(pack_type, conn))
|
||||
return STATUS_ERROR;
|
||||
|
||||
/* Send the (self-inclusive) message length word. */
|
||||
if (pqPutInt(buf_len + 4, 4, conn))
|
||||
return STATUS_ERROR;
|
||||
|
||||
/* Send the packet itself. */
|
||||
|
||||
if (pqPutnchar(buf, len, conn))
|
||||
/* Send the message body. */
|
||||
if (pqPutnchar(buf, buf_len, conn))
|
||||
return STATUS_ERROR;
|
||||
|
||||
/* Flush to ensure backend gets it. */
|
||||
if (pqFlush(conn))
|
||||
return STATUS_ERROR;
|
||||
|
||||
@ -2661,6 +2599,87 @@ PQconninfoFree(PQconninfoOption *connOptions)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Build a startup packet given a filled-in PGconn structure.
|
||||
*
|
||||
* We need to figure out how much space is needed, then fill it in.
|
||||
* To avoid duplicate logic, this routine is called twice: the first time
|
||||
* (with packet == NULL) just counts the space needed, the second time
|
||||
* (with packet == allocated space) fills it in. Return value is the number
|
||||
* of bytes used.
|
||||
*/
|
||||
static int
|
||||
build_startup_packet(const PGconn *conn, char *packet)
|
||||
{
|
||||
int packet_len = 0;
|
||||
const struct EnvironmentOptions *next_eo;
|
||||
|
||||
/* Protocol version comes first. */
|
||||
if (packet)
|
||||
{
|
||||
ProtocolVersion pv = htonl(PG_PROTOCOL_LIBPQ);
|
||||
|
||||
memcpy(packet + packet_len, &pv, sizeof(ProtocolVersion));
|
||||
}
|
||||
packet_len += sizeof(ProtocolVersion);
|
||||
|
||||
/* Add user name, database name, options */
|
||||
if (conn->pguser)
|
||||
{
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, "user");
|
||||
packet_len += strlen("user") + 1;
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, conn->pguser);
|
||||
packet_len += strlen(conn->pguser) + 1;
|
||||
}
|
||||
if (conn->dbName)
|
||||
{
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, "database");
|
||||
packet_len += strlen("database") + 1;
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, conn->dbName);
|
||||
packet_len += strlen(conn->dbName) + 1;
|
||||
}
|
||||
if (conn->pgoptions)
|
||||
{
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, "options");
|
||||
packet_len += strlen("options") + 1;
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, conn->pgoptions);
|
||||
packet_len += strlen(conn->pgoptions) + 1;
|
||||
}
|
||||
|
||||
/* Add any environment-driven GUC settings needed */
|
||||
for (next_eo = EnvironmentOptions; next_eo->envName; next_eo++)
|
||||
{
|
||||
const char *val;
|
||||
|
||||
if ((val = getenv(next_eo->envName)) != NULL)
|
||||
{
|
||||
if (strcasecmp(val, "default") != 0)
|
||||
{
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, next_eo->pgName);
|
||||
packet_len += strlen(next_eo->pgName) + 1;
|
||||
if (packet)
|
||||
strcpy(packet + packet_len, val);
|
||||
packet_len += strlen(val) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add trailing terminator */
|
||||
if (packet)
|
||||
packet[packet_len] = '\0';
|
||||
packet_len++;
|
||||
|
||||
return packet_len;
|
||||
}
|
||||
|
||||
|
||||
/* =========== accessor functions for PGconn ========= */
|
||||
char *
|
||||
PQdb(const PGconn *conn)
|
||||
@ -2850,9 +2869,11 @@ defaultNoticeProcessor(void *arg, const char *message)
|
||||
fprintf(stderr, "%s", message);
|
||||
}
|
||||
|
||||
/* returns a pointer to the next token or NULL if the current
|
||||
* token doesn't match */
|
||||
char *
|
||||
/*
|
||||
* returns a pointer to the next token or NULL if the current
|
||||
* token doesn't match
|
||||
*/
|
||||
static char *
|
||||
pwdfMatchesString(char *buf, char *token)
|
||||
{
|
||||
char *tbuf,
|
||||
@ -2889,7 +2910,7 @@ pwdfMatchesString(char *buf, char *token)
|
||||
}
|
||||
|
||||
/* Get a password from the password file. Return value is malloc'd. */
|
||||
char *
|
||||
static char *
|
||||
PasswordFromFile(char *hostname, char *port, char *dbname, char *username)
|
||||
{
|
||||
FILE *fp;
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: libpq-int.h,v 1.60 2002/10/16 02:55:30 momjian Exp $
|
||||
* $Id: libpq-int.h,v 1.61 2003/04/17 22:26:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
|
||||
* pqcomm.h describe what the backend knows, not what libpq knows.
|
||||
*/
|
||||
|
||||
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(2,0)
|
||||
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,100) /* XXX temporary value */
|
||||
|
||||
/*
|
||||
* POSTGRES backend dependent Constants.
|
||||
@ -181,8 +181,6 @@ typedef enum
|
||||
/* PGSetenvStatusType defines the state of the PQSetenv state machine */
|
||||
typedef enum
|
||||
{
|
||||
SETENV_STATE_OPTION_SEND, /* About to send an Environment Option */
|
||||
SETENV_STATE_OPTION_WAIT, /* Waiting for above send to complete */
|
||||
SETENV_STATE_ENCODINGS_SEND, /* About to send an "encodings" query */
|
||||
SETENV_STATE_ENCODINGS_WAIT, /* Waiting for query to complete */
|
||||
SETENV_STATE_IDLE
|
||||
@ -274,7 +272,6 @@ struct pg_conn
|
||||
|
||||
/* Status for sending environment info. Used during PQSetenv only. */
|
||||
PGSetenvStatusType setenv_state;
|
||||
const struct EnvironmentOptions *next_eo;
|
||||
|
||||
#ifdef USE_SSL
|
||||
bool allow_ssl_try; /* Allowed to try SSL negotiation */
|
||||
@ -312,7 +309,8 @@ extern char *const pgresStatus[];
|
||||
|
||||
/* === in fe-connect.c === */
|
||||
|
||||
extern int pqPacketSend(PGconn *conn, const char *buf, size_t len);
|
||||
extern int pqPacketSend(PGconn *conn, char pack_type,
|
||||
const void *buf, size_t buf_len);
|
||||
|
||||
/* === in fe-exec.c === */
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
--
|
||||
-- INTERVAL
|
||||
--
|
||||
SET DATESTYLE = DEFAULT;
|
||||
SET DATESTYLE = 'ISO';
|
||||
-- check acceptance of "time zone style"
|
||||
SELECT INTERVAL '01:00' AS "One hour";
|
||||
One hour
|
||||
|
@ -2,7 +2,7 @@
|
||||
-- INTERVAL
|
||||
--
|
||||
|
||||
SET DATESTYLE = DEFAULT;
|
||||
SET DATESTYLE = 'ISO';
|
||||
|
||||
-- check acceptance of "time zone style"
|
||||
SELECT INTERVAL '01:00' AS "One hour";
|
||||
|
Loading…
Reference in New Issue
Block a user