1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00
I've completed the patch to fix the protocol and authentication issues I
was discussing a couple of weeks ago.  The particular changes are:

- the protocol has a version number
- network byte order is used throughout
- the pg_hba.conf file is used to specify what method is used to
  authenticate a frontend (either password, ident, trust, reject, krb4
  or krb5)
- support for multiplexed backends is removed
- appropriate changes to man pages
- the -a switch to many programs to specify an authentication service
  no longer has any effect
- the libpq.so version number has changed to 1.1

The new backend still supports the old protocol so old interfaces won't
break.
This commit is contained in:
Marc G. Fournier
1998-01-26 01:42:53 +00:00
parent 91d983aa11
commit d5bbe2aca5
41 changed files with 1611 additions and 2288 deletions

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.20 1997/12/09 03:10:31 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.21 1998/01/26 01:41:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,39 +16,6 @@
*
* backend (postmaster) routines:
* be_recvauth receive authentication information
* be_setauthsvc do/do not permit an authentication service
* be_getauthsvc is an authentication service permitted?
*
* NOTES
* To add a new authentication system:
* 0. If you can't do your authentication over an existing socket,
* you lose -- get ready to hack around this framework instead of
* using it. Otherwise, you can assume you have an initialized
* and empty connection to work with. (Please don't leave leftover
* gunk in the connection after the authentication transactions, or
* the POSTGRES routines that follow will be very unhappy.)
* 1. Write a set of routines that:
* let a client figure out what user/principal name to use
* send authentication information (client side)
* receive authentication information (server side)
* You can include both routines in this file, using #ifdef FRONTEND
* to separate them.
* 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
* 3. Edit the static "struct authsvc" array and the generic
* {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
* the new service. You may have to change the arguments of these
* routines; they basically just reflect what Kerberos v4 needs.
* 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
* to add library and CFLAGS hooks -- basically, grep the Makefile
* hierarchy for KRBVERS to see where you need to add things.
*
* Send mail to post_hackers@postgres.Berkeley.EDU if you have to make
* any changes to arguments, etc. Context diffs would be nice, too.
*
* Someday, this cruft will go away and magically be replaced by a
* nice interface based on the GSS API or something. For now, though,
* there's no (stable) UNIX security API to work with...
*
*/
#include <stdio.h>
#include <string.h>
@@ -68,66 +35,21 @@
#include <libpq/auth.h>
#include <libpq/libpq.h>
#include <libpq/libpq-be.h>
#include <libpq/hba.h>
#include <libpq/password.h>
#include <libpq/crypt.h>
static int be_getauthsvc(MsgType msgtype);
/*----------------------------------------------------------------
* common definitions for generic fe/be routines
*----------------------------------------------------------------
*/
static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler)());
static void handle_done_auth(Port *port);
static void handle_krb4_auth(Port *port);
static void handle_krb5_auth(Port *port);
static void handle_password_auth(Port *port);
static void readPasswordPacket(char *arg, PacketLen len, char *pkt);
static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt);
static int old_be_recvauth(Port *port);
static int map_old_to_new(Port *port, UserAuth old, int status);
struct authsvc
{
char name[16]; /* service nickname (for command line) */
MsgType msgtype; /* startup packet header type */
int allowed; /* initially allowed (before command line
* option parsing)? */
};
/*
* Command-line parsing routines use this structure to map nicknames
* onto service types (and the startup packets to use with them).
*
* Programs receiving an authentication request use this structure to
* decide which authentication service types are currently permitted.
* By default, all authentication systems compiled into the system are
* allowed. Unauthenticated connections are disallowed unless there
* isn't any authentication system.
*/
#if defined(HBA)
static int useHostBasedAuth = 1;
#else
static int useHostBasedAuth = 0;
#endif
#if defined(KRB4) || defined(KRB5) || defined(HBA)
#define UNAUTH_ALLOWED 0
#else
#define UNAUTH_ALLOWED 1
#endif
static struct authsvc authsvcs[] = {
{"unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED},
{"hba", STARTUP_HBA_MSG, 1},
{"krb4", STARTUP_KRB4_MSG, 1},
{"krb5", STARTUP_KRB5_MSG, 1},
#if defined(KRB5)
{"kerberos", STARTUP_KRB5_MSG, 1},
#else
{"kerberos", STARTUP_KRB4_MSG, 1},
#endif
{"password", STARTUP_PASSWORD_MSG, 1},
{"crypt", STARTUP_CRYPT_MSG, 1}
};
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#ifdef KRB4
/* This has to be ifdef'd out because krb.h does exist. This needs
@@ -140,10 +62,6 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#include <krb.h>
#ifdef FRONTEND
/* moves to src/libpq/fe-auth.c */
#else /* !FRONTEND */
/*
* pg_krb4_recvauth -- server routine to receive authentication information
* from the client
@@ -154,10 +72,7 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
* unauthenticated connections.)
*/
static int
pg_krb4_recvauth(int sock,
struct sockaddr_in * laddr,
struct sockaddr_in * raddr,
char *username)
pg_krb4_recvauth(Port *)
{
long krbopts = 0; /* one-way authentication */
KTEXT_ST clttkt;
@@ -170,12 +85,12 @@ pg_krb4_recvauth(int sock,
strcpy(instance, "*"); /* don't care, but arg gets expanded
* anyway */
status = krb_recvauth(krbopts,
sock,
port->sock,
&clttkt,
PG_KRB_SRVNAM,
instance,
raddr,
laddr,
&port->raddr.in,
&port->laddr.in,
&auth_data,
PG_KRB_SRVTAB,
key_sched,
@@ -198,12 +113,11 @@ pg_krb4_recvauth(int sock,
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
if (username && *username &&
strncmp(username, auth_data.pname, NAMEDATALEN))
if (strncmp(port->user, auth_data.pname, SM_USER))
{
sprintf(PQerrormsg,
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
username,
port->username,
auth_data.pname);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
@@ -212,14 +126,9 @@ pg_krb4_recvauth(int sock,
return (STATUS_OK);
}
#endif /* !FRONTEND */
#else
static int
pg_krb4_recvauth(int sock,
struct sockaddr_in * laddr,
struct sockaddr_in * raddr,
char *username)
pg_krb4_recvauth(Port *port)
{
sprintf(PQerrormsg,
"pg_krb4_recvauth: Kerberos not implemented on this "
@@ -267,10 +176,6 @@ pg_an_to_ln(char *aname)
return (aname);
}
#ifdef FRONTEND
/* moves to src/libpq/fe-auth.c */
#else /* !FRONTEND */
/*
* pg_krb5_recvauth -- server routine to receive authentication information
* from the client
@@ -294,10 +199,7 @@ pg_an_to_ln(char *aname)
* but kdb5_edit allows you to select which principals to dump. Yay!)
*/
static int
pg_krb5_recvauth(int sock,
struct sockaddr_in * laddr,
struct sockaddr_in * raddr,
char *username)
pg_krb5_recvauth(Port *port)
{
char servbuf[MAXHOSTNAMELEN + 1 +
sizeof(PG_KRB_SRVNAM)];
@@ -334,9 +236,9 @@ pg_krb5_recvauth(int sock,
* krb5_sendauth needs this to verify the address in the client
* authenticator.
*/
sender_addr.addrtype = raddr->sin_family;
sender_addr.length = sizeof(raddr->sin_addr);
sender_addr.contents = (krb5_octet *) & (raddr->sin_addr);
sender_addr.addrtype = port->raddr.in.sin_family;
sender_addr.length = sizeof(port->raddr.in.sin_addr);
sender_addr.contents = (krb5_octet *) & (port->raddr.in.sin_addr);
if (strcmp(PG_KRB_SRVTAB, ""))
{
@@ -344,7 +246,7 @@ pg_krb5_recvauth(int sock,
keyprocarg = PG_KRB_SRVTAB;
}
if (code = krb5_recvauth((krb5_pointer) & sock,
if (code = krb5_recvauth((krb5_pointer) & port->sock,
PG_KRB5_VERSION,
server,
&sender_addr,
@@ -390,11 +292,11 @@ pg_krb5_recvauth(int sock,
return (STATUS_ERROR);
}
kusername = pg_an_to_ln(kusername);
if (username && strncmp(username, kusername, NAMEDATALEN))
if (strncmp(username, kusername, SM_USER))
{
sprintf(PQerrormsg,
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
username, kusername);
port->username, kusername);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
pfree(kusername);
@@ -404,15 +306,9 @@ pg_krb5_recvauth(int sock,
return (STATUS_OK);
}
#endif /* !FRONTEND */
#else
static int
pg_krb5_recvauth(int sock,
struct sockaddr_in * laddr,
struct sockaddr_in * raddr,
char *username)
pg_krb5_recvauth(Port *port)
{
sprintf(PQerrormsg,
"pg_krb5_recvauth: Kerberos not implemented on this "
@@ -425,246 +321,360 @@ pg_krb5_recvauth(int sock,
#endif /* KRB5 */
static int
pg_password_recvauth(Port *port, char *database, char *DataDir)
{
PacketBuf buf;
char *user,
*password;
if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
/*
* Handle a v0 password packet.
*/
static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
{
Port *port;
PasswordPacketV0 *pp;
char *user, *password, *cp, *start;
port = (Port *)arg;
pp = (PasswordPacketV0 *)pkt;
/*
* The packet is supposed to comprise the user name and the password
* as C strings. Be careful the check that this is the case.
*/
user = password = NULL;
len -= sizeof (pp->unused);
cp = start = pp->data;
while (len > 0)
if (*cp++ == '\0')
{
sprintf(PQerrormsg,
"pg_password_recvauth: failed to receive authentication packet.\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
if (user == NULL)
user = start;
else
{
password = start;
break;
}
start = cp;
}
user = buf.data;
password = buf.data + strlen(user) + 1;
if (user == NULL || password == NULL)
{
sprintf(PQerrormsg,
"pg_password_recvauth: badly formed password packet.\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return verify_password(user, password, port, database, DataDir);
auth_failed(port);
}
else if (map_old_to_new(port, uaPassword,
verify_password(port->auth_arg, user, password)) != STATUS_OK)
auth_failed(port);
}
static int
crypt_recvauth(Port *port)
/*
* Tell the user the authentication failed, but not why.
*/
void auth_failed(Port *port)
{
PacketBuf buf;
char *user,
*password;
if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
{
sprintf(PQerrormsg,
"crypt_recvauth: failed to receive authentication packet.\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
user = buf.data;
password = buf.data + strlen(user) + 1;
return crypt_verify(port, user, password);
PacketSendError(&port->pktInfo, "User authentication failed");
}
/*
* be_recvauth -- server demux routine for incoming authentication information
*/
int
be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo *sp)
void be_recvauth(Port *port)
{
MsgType msgtype;
AuthRequest areq;
void (*auth_handler)();
/*
* A message type of STARTUP_MSG (which once upon a time was the only
* startup message type) means user wants us to choose. "unauth" is
* what used to be the only choice, but installation may choose "hba"
* instead.
* Get the authentication method to use for this frontend/database
* combination.
*/
if (msgtype_arg == STARTUP_MSG)
{
if (useHostBasedAuth)
msgtype = STARTUP_HBA_MSG;
else
msgtype = STARTUP_UNAUTH_MSG;
}
else
msgtype = msgtype_arg;
if (!username)
if (hba_getauthmethod(&port->raddr, port->database, port->auth_arg,
&port->auth_method) != STATUS_OK)
{
sprintf(PQerrormsg,
"be_recvauth: no user name passed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
if (!port)
{
sprintf(PQerrormsg,
"be_recvauth: no port structure passed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
PacketSendError(&port->pktInfo, "Error getting authentication method");
return;
}
switch (msgtype)
{
case STARTUP_KRB4_MSG:
if (!be_getauthsvc(msgtype))
{
sprintf(PQerrormsg,
"be_recvauth: krb4 authentication disallowed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
if (pg_krb4_recvauth(port->sock, (struct sockaddr_in *) &port->laddr,
(struct sockaddr_in *) &port->raddr,
username) != STATUS_OK)
{
sprintf(PQerrormsg,
"be_recvauth: krb4 authentication failed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
break;
case STARTUP_KRB5_MSG:
if (!be_getauthsvc(msgtype))
{
sprintf(PQerrormsg,
"be_recvauth: krb5 authentication disallowed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
if (pg_krb5_recvauth(port->sock, (struct sockaddr_in *) &port->laddr,
(struct sockaddr_in *) &port->raddr,
username) != STATUS_OK)
{
sprintf(PQerrormsg,
"be_recvauth: krb5 authentication failed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
break;
case STARTUP_UNAUTH_MSG:
if (!be_getauthsvc(msgtype))
{
sprintf(PQerrormsg,
"be_recvauth: "
"unauthenticated connections disallowed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
break;
case STARTUP_HBA_MSG:
if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK)
{
sprintf(PQerrormsg,
"be_recvauth: host-based authentication failed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
break;
case STARTUP_PASSWORD_MSG:
if (!be_getauthsvc(msgtype))
{
sprintf(PQerrormsg,
"be_recvauth: "
"plaintext password authentication disallowed\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
if (pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK)
{
/* Handle old style authentication. */
/*
* pg_password_recvauth or lower-level routines have
* already set
*/
/* the error message */
return (STATUS_ERROR);
}
break;
case STARTUP_CRYPT_MSG:
if (crypt_recvauth(port) != STATUS_OK)
return STATUS_ERROR;
break;
default:
sprintf(PQerrormsg,
"be_recvauth: unrecognized message type: %d\n",
msgtype);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
if (PG_PROTOCOL_MAJOR(port->proto) == 0)
{
if (old_be_recvauth(port) != STATUS_OK)
auth_failed(port);
return;
}
return (STATUS_OK);
/* Handle new style authentication. */
switch (port->auth_method)
{
case uaReject:
auth_failed(port);
return;
case uaKrb4:
areq = AUTH_REQ_KRB4;
auth_handler = handle_krb4_auth;
break;
case uaKrb5:
areq = AUTH_REQ_KRB5;
auth_handler = handle_krb5_auth;
break;
case uaTrust:
areq = AUTH_REQ_OK;
auth_handler = handle_done_auth;
break;
case uaIdent:
if (authident(&port->raddr.in, &port->laddr.in, port->user,
port->auth_arg) != STATUS_OK)
{
auth_failed(port);
return;
}
areq = AUTH_REQ_OK;
auth_handler = handle_done_auth;
break;
case uaPassword:
areq = AUTH_REQ_PASSWORD;
auth_handler = handle_password_auth;
break;
case uaCrypt:
areq = AUTH_REQ_CRYPT;
auth_handler = handle_password_auth;
break;
}
/* Tell the frontend what we want next. */
sendAuthRequest(port, areq, auth_handler);
}
/*
* be_setauthsvc -- enable/disable the authentication services currently
* selected for use by the backend
* be_getauthsvc -- returns whether a particular authentication system
* (indicated by its message type) is permitted by the
* current selections
*
* be_setauthsvc encodes the command-line syntax that
* -a "<service-name>"
* enables a service, whereas
* -a "no<service-name>"
* disables it.
* Send an authentication request packet to the frontend.
*/
void
be_setauthsvc(char *name)
{
int i,
j;
int turnon = 1;
if (!name)
return;
if (!strncmp("no", name, 2))
static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler)())
{
char *dp, *sp;
int i;
uint32 net_areq;
/* Convert to a byte stream. */
net_areq = htonl(areq);
dp = port->pktInfo.pkt.ar.data;
sp = (char *)&net_areq;
*dp++ = 'R';
for (i = 1; i <= 4; ++i)
*dp++ = *sp++;
/* Add the salt for encrypted passwords. */
if (areq == AUTH_REQ_CRYPT)
{
turnon = 0;
name += 2;
}
if (name[0] == '\0')
return;
for (i = 0; i < n_authsvcs; ++i)
if (!strcmp(name, authsvcs[i].name))
{
for (j = 0; j < n_authsvcs; ++j)
if (authsvcs[j].msgtype == authsvcs[i].msgtype)
authsvcs[j].allowed = turnon;
break;
}
if (i == n_authsvcs)
{
sprintf(PQerrormsg,
"be_setauthsvc: invalid name %s, ignoring...\n",
name);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
*dp++ = port->salt[0];
*dp++ = port->salt[1];
i += 2;
}
PacketSendSetup(&port -> pktInfo, i, handler, (char *)port);
}
/*
* Called when we have told the front end that it is authorised.
*/
static void handle_done_auth(Port *port)
{
/*
* Don't generate any more traffic. This will cause the backend to
* start.
*/
return;
}
static int
be_getauthsvc(MsgType msgtype)
{
int i;
for (i = 0; i < n_authsvcs; ++i)
if (msgtype == authsvcs[i].msgtype)
return (authsvcs[i].allowed);
return (0);
/*
* Called when we have told the front end that it should use Kerberos V4
* authentication.
*/
static void handle_krb4_auth(Port *port)
{
if (pg_krb4_recvauth(port) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
}
/*
* Called when we have told the front end that it should use Kerberos V5
* authentication.
*/
static void handle_krb5_auth(Port *port)
{
if (pg_krb5_recvauth(port) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
}
/*
* Called when we have told the front end that it should use password
* authentication.
*/
static void handle_password_auth(Port *port)
{
/* Set up the read of the password packet. */
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (char *)port);
}
/*
* Called when we have received the password packet.
*/
static void readPasswordPacket(char *arg, PacketLen len, char *pkt)
{
char password[sizeof (PasswordPacket) + 1];
Port *port;
port = (Port *)arg;
/* Silently truncate a password that is too big. */
if (len > sizeof (PasswordPacket))
len = sizeof (PasswordPacket);
StrNCpy(password, ((PasswordPacket *)pkt)->passwd, len);
/*
* Use the local flat password file if clear passwords are used and the
* file is specified. Otherwise use the password in the pg_user table,
* encrypted or not.
*/
if (port->auth_method == uaPassword && port->auth_arg[0] != '\0')
{
if (verify_password(port->auth_arg, port->user, password) != STATUS_OK)
auth_failed(port);
}
else if (crypt_verify(port, port->user, password) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
}
/*
* Server demux routine for incoming authentication information for protocol
* version 0.
*/
static int old_be_recvauth(Port *port)
{
int status;
MsgType msgtype = (MsgType)port->proto;
/* Handle the authentication that's offered. */
switch (msgtype)
{
case STARTUP_KRB4_MSG:
status = map_old_to_new(port,uaKrb4,pg_krb4_recvauth(port));
break;
case STARTUP_KRB5_MSG:
status = map_old_to_new(port,uaKrb5,pg_krb5_recvauth(port));
break;
case STARTUP_MSG:
status = map_old_to_new(port,uaTrust,STATUS_OK);
break;
case STARTUP_PASSWORD_MSG:
PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
(char *)port);
return STATUS_OK;
default:
fprintf(stderr, "Invalid startup message type: %u\n", msgtype);
return STATUS_OK;
}
return status;
}
/*
* The old style authentication has been done. Modify the result of this (eg.
* allow the connection anyway, disallow it anyway, or use the result)
* depending on what authentication we really want to use.
*/
static int map_old_to_new(Port *port, UserAuth old, int status)
{
switch (port->auth_method)
{
case uaCrypt:
case uaReject:
status = STATUS_ERROR;
break;
case uaKrb4:
if (old != uaKrb4)
status = STATUS_ERROR;
break;
case uaKrb5:
if (old != uaKrb5)
status = STATUS_ERROR;
break;
case uaTrust:
status = STATUS_OK;
break;
case uaIdent:
status = authident(&port->raddr.in, &port->laddr.in,
port->user, port->auth_arg);
break;
case uaPassword:
if (old != uaPassword)
status = STATUS_ERROR;
break;
}
return status;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.9 1997/09/12 04:07:50 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.10 1998/01/26 01:41:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,7 @@
#include <postgres.h>
#include <lib/dllist.h>
#include <libpq/libpq-be.h>
#include <libpq/libpq.h>
#include <access/heapam.h>
#include <access/htup.h>
#include <storage/buf.h>

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.13 1998/01/07 21:03:16 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.14 1998/01/26 01:41:06 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,7 +27,7 @@
#include <tcop/fastpath.h>
#include <tcop/tcopprot.h>
#include <lib/dllist.h>
#include <libpq/libpq-be.h>
#include <libpq/libpq.h>
#include <fmgr.h>
#include <utils/exc.h>
#include <utils/builtins.h>

View File

@@ -17,9 +17,6 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#include "postgres.h"
#include "miscadmin.h"
@@ -27,6 +24,10 @@
#include "storage/fd.h"
#include "libpq/crypt.h"
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
char** pwd_cache = NULL;
int pwd_cache_count = 0;
@@ -219,6 +220,7 @@ int crypt_getloginfo(const char* user, char** passwd, char** valuntil) {
/*-------------------------------------------------------------------------*/
#ifdef 0
MsgType crypt_salt(const char* user) {
char* passwd;
@@ -237,6 +239,7 @@ MsgType crypt_salt(const char* user) {
if (valuntil) free((void*)valuntil);
return STARTUP_SALT_MSG;
}
#endif
/*-------------------------------------------------------------------------*/
@@ -258,7 +261,13 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) {
return STATUS_ERROR;
}
crypt_pwd = crypt(passwd, port->salt);
/*
* Compare with the encrypted or plain password depending on the
* authentication method being used for this connection.
*/
crypt_pwd = (port->auth_method == uaCrypt ? crypt(passwd, port->salt) : passwd);
if (!strcmp(pgpass, crypt_pwd)) {
/* check here to be sure we are not past valuntil
*/

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.25 1997/12/09 03:10:38 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.26 1998/01/26 01:41:08 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -97,84 +97,56 @@ read_through_eol(FILE *file)
static void
read_hba_entry2(FILE *file, enum Userauth * userauth_p, char usermap_name[],
bool *error_p, bool *matches_p, bool find_password_entries)
read_hba_entry2(FILE *file, UserAuth * userauth_p, char auth_arg[],
bool *error_p)
{
/*--------------------------------------------------------------------------
Read from file FILE the rest of a host record, after the mask field,
and return the interpretation of it as *userauth_p, usermap_name, and
and return the interpretation of it as *userauth_p, auth_arg, and
*error_p.
---------------------------------------------------------------------------*/
char buf[MAX_TOKEN];
bool userauth_valid;
/* Get authentication type token. */
next_token(file, buf, sizeof(buf));
userauth_valid = false;
if (buf[0] == '\0')
if (strcmp(buf, "trust") == 0)
*userauth_p = uaTrust;
else if (strcmp(buf, "ident") == 0)
*userauth_p = uaIdent;
else if (strcmp(buf, "password") == 0)
*userauth_p = uaPassword;
else if (strcmp(buf, "krb4") == 0)
*userauth_p = uaKrb4;
else if (strcmp(buf, "krb5") == 0)
*userauth_p = uaKrb5;
else if (strcmp(buf, "reject") == 0)
*userauth_p = uaReject;
else if (strcmp(buf, "crypt") == 0)
*userauth_p = uaCrypt;
else
{
*error_p = true;
}
else
{
userauth_valid = true;
if (strcmp(buf, "trust") == 0)
{
*userauth_p = Trust;
}
else if (strcmp(buf, "ident") == 0)
{
*userauth_p = Ident;
}
else if (strcmp(buf, "password") == 0)
{
*userauth_p = Password;
}
else
{
userauth_valid = false;
}
if ((find_password_entries && strcmp(buf, "password") == 0) ||
(!find_password_entries && strcmp(buf, "password") != 0))
{
*matches_p = true;
}
else
{
*matches_p = false;
}
if (buf[0] != '\0')
read_through_eol(file);
}
if (!userauth_valid || !*matches_p || *error_p)
if (!*error_p)
{
if (!userauth_valid)
{
*error_p = true;
}
read_through_eol(file);
}
else
{
/* Get the map name token, if any */
/* Get the authentication argument token, if any */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
{
*error_p = false;
usermap_name[0] = '\0';
}
auth_arg[0] = '\0';
else
{
strncpy(usermap_name, buf, USERMAP_NAME_SIZE);
StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
next_token(file, buf, sizeof(buf));
if (buf[0] != '\0')
{
*error_p = true;
read_through_eol(file);
}
else
*error_p = false;
}
}
}
@@ -182,139 +154,150 @@ read_hba_entry2(FILE *file, enum Userauth * userauth_p, char usermap_name[],
static void
process_hba_record(FILE *file,
const struct in_addr ip_addr, const char database[],
process_hba_record(FILE *file, SockAddr *raddr, const char database[],
bool *matches_p, bool *error_p,
enum Userauth * userauth_p, char usermap_name[],
bool find_password_entries)
UserAuth * userauth_p, char auth_arg[])
{
/*---------------------------------------------------------------------------
Process the non-comment record in the config file that is next on the file.
See if it applies to a connection to a host with IP address "ip_addr"
See if it applies to a connection to a host with IP address "*raddr"
to a database named "database[]". If so, return *matches_p true
and *userauth_p and usermap_name[] as the values from the entry.
If not, return matches_p false. If the record has a syntax error,
and *userauth_p and auth_arg[] as the values from the entry.
If not, leave *matches_p as it was. If the record has a syntax error,
return *error_p true, after issuing a message to stderr. If no error,
leave *error_p as it was.
---------------------------------------------------------------------------*/
char buf[MAX_TOKEN]; /* A token from the record */
char db[MAX_TOKEN], buf[MAX_TOKEN];
/* Read the record type field. */
/* Read the record type field */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
*matches_p = false;
return;
/* Check the record type. */
if (strcmp(buf, "local") == 0)
{
/* Get the database. */
next_token(file, db, sizeof(db));
if (db[0] == '\0')
goto syntax;
/* Read the rest of the line. */
read_hba_entry2(file, userauth_p, auth_arg, error_p);
/*
* For now, disallow methods that need AF_INET sockets to work.
*/
if (!*error_p &&
(*userauth_p == uaIdent ||
*userauth_p == uaKrb4 ||
*userauth_p == uaKrb5))
*error_p = true;
if (*error_p)
goto syntax;
/*
* If this record isn't for our database, or this is the wrong
* sort of connection, ignore it.
*/
if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0) ||
raddr->sa.sa_family != AF_UNIX)
return;
}
else if (strcmp(buf, "host") == 0)
{
struct in_addr file_ip_addr, mask;
/* Get the database. */
next_token(file, db, sizeof(db));
if (db[0] == '\0')
goto syntax;
/* Read the IP address field. */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
goto syntax;
/* Remember the IP address field and go get mask field. */
if (!inet_aton(buf, &file_ip_addr))
{
read_through_eol(file);
goto syntax;
}
/* Read the mask field. */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
goto syntax;
if (!inet_aton(buf, &mask))
{
read_through_eol(file);
goto syntax;
}
/*
* This is the record we're looking for. Read the rest of the
* info from it.
*/
read_hba_entry2(file, userauth_p, auth_arg, error_p);
if (*error_p)
goto syntax;
/*
* If this record isn't for our database, or this is the wrong
* sort of connection, ignore it.
*/
if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0) ||
raddr->sa.sa_family != AF_INET ||
((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
return;
}
else
{
/* if this isn't a "host" record, it can't match. */
if (strcmp(buf, "host") != 0)
{
*matches_p = false;
read_through_eol(file);
}
else
{
/* It's a "host" record. Read the database name field. */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
*matches_p = false;
else
{
/* If this record isn't for our database, ignore it. */
if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0)
{
*matches_p = false;
read_through_eol(file);
}
else
{
/* Read the IP address field */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
*matches_p = false;
else
{
int valid; /* Field is valid dotted
* decimal */
/*
* Remember the IP address field and go get mask
* field
*/
struct in_addr file_ip_addr; /* IP address field
* value */
valid = inet_aton(buf, &file_ip_addr);
if (!valid)
{
*matches_p = false;
read_through_eol(file);
}
else
{
/* Read the mask field */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
*matches_p = false;
else
{
struct in_addr mask;
/*
* Got mask. Now see if this record is
* for our host.
*/
valid = inet_aton(buf, &mask);
if (!valid)
{
*matches_p = false;
read_through_eol(file);
}
else
{
if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr)
!= 0x0000)
{
*matches_p = false;
read_through_eol(file);
}
else
{
/*
* This is the record we're
* looking for. Read the rest of
* the info from it.
*/
read_hba_entry2(file, userauth_p, usermap_name,
error_p, matches_p, find_password_entries);
if (*error_p)
{
sprintf(PQerrormsg,
"process_hba_record: invalid syntax in "
"hba config file "
"for host record for IP address %s\n",
inet_ntoa(file_ip_addr));
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
}
}
}
}
}
}
}
}
}
read_through_eol(file);
goto syntax;
}
*matches_p = true;
return;
syntax:
sprintf(PQerrormsg,
"process_hba_record: invalid syntax in pg_hba.conf file\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
*error_p = true;
}
static void
process_open_config_file(FILE *file,
const struct in_addr ip_addr, const char database[],
bool *host_ok_p, enum Userauth * userauth_p,
char usermap_name[], bool find_password_entries)
process_open_config_file(FILE *file, SockAddr *raddr, const char database[],
bool *host_ok_p, UserAuth * userauth_p,
char auth_arg[])
{
/*---------------------------------------------------------------------------
This function does the same thing as find_hba_entry, only with
@@ -348,36 +331,26 @@ process_open_config_file(FILE *file,
read_through_eol(file);
else
{
process_hba_record(file, ip_addr, database,
&found_entry, &error, userauth_p, usermap_name,
find_password_entries);
process_hba_record(file, raddr, database,
&found_entry, &error, userauth_p, auth_arg);
}
}
}
if (found_entry)
{
if (error)
*host_ok_p = false;
else
*host_ok_p = true;
}
else
*host_ok_p = false;
if (found_entry && !error)
*host_ok_p = true;
}
void
find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
const char database[],
bool *host_ok_p, enum Userauth * userauth_p,
char usermap_name[], bool find_password_entries)
static void
find_hba_entry(SockAddr *raddr, const char database[], bool *host_ok_p,
UserAuth * userauth_p, char auth_arg[])
{
/*--------------------------------------------------------------------------
Read the config file and find an entry that allows connection from
host "ip_addr" to database "database". If not found, return
*host_ok_p == false. If found, return *userauth_p and *usermap_name
representing the contents of that entry.
host "*raddr" to database "database". If found, return *host_ok_p == true
and *userauth_p and *auth_arg representing the contents of that entry.
When a record has invalid syntax, we either ignore it or reject the
connection (depending on where it's invalid). No message or anything.
@@ -436,8 +409,6 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
{
/* The open of the config file failed. */
*host_ok_p = false;
sprintf(PQerrormsg,
"find_hba_entry: Host-based authentication config file "
"does not exist or permissions are not setup correctly! "
@@ -448,8 +419,8 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
}
else
{
process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p,
usermap_name, find_password_entries);
process_open_config_file(file, raddr, database, host_ok_p, userauth_p,
auth_arg);
FreeFile(file);
}
pfree(conf_file);
@@ -754,8 +725,7 @@ verify_against_open_usermap(FILE *file,
static void
verify_against_usermap(const char DataDir[],
const char pguser[],
verify_against_usermap(const char pguser[],
const char ident_username[],
const char usermap_name[],
bool *checks_out_p)
@@ -834,20 +804,20 @@ verify_against_usermap(const char DataDir[],
static void
authident(const char DataDir[],
const Port port, const char postgres_username[],
const char usermap_name[],
bool *authentic_p)
int
authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr,
const char postgres_username[],
const char auth_arg[])
{
/*---------------------------------------------------------------------------
Talk to the ident server on the remote host and find out who owns the
connection described by "port". Then look in the usermap file under
the usermap usermap_name[] and see if that user is equivalent to
the usermap auth_arg[] and see if that user is equivalent to
Postgres user user[].
Return *authentic_p true iff yes.
Return STATUS_OK if yes.
---------------------------------------------------------------------------*/
bool checks_out;
bool ident_failed;
/* We were unable to get ident to give us a username */
@@ -855,120 +825,35 @@ authident(const char DataDir[],
/* The username returned by ident */
ident(port.raddr.in.sin_addr, port.laddr.in.sin_addr,
port.raddr.in.sin_port, port.laddr.in.sin_port,
ident(raddr->sin_addr, laddr->sin_addr,
raddr->sin_port, laddr->sin_port,
&ident_failed, ident_username);
if (ident_failed)
*authentic_p = false;
else
{
bool checks_out;
return STATUS_ERROR;
verify_against_usermap(DataDir,
postgres_username, ident_username, usermap_name,
verify_against_usermap(postgres_username, ident_username, auth_arg,
&checks_out);
if (checks_out)
*authentic_p = true;
else
*authentic_p = false;
}
return (checks_out ? STATUS_OK : STATUS_ERROR);
}
extern int
hba_recvauth(const Port *port, const char database[], const char user[],
const char DataDir[])
hba_getauthmethod(SockAddr *raddr, char *database, char *auth_arg,
UserAuth *auth_method)
{
/*---------------------------------------------------------------------------
Determine if the TCP connection described by "port" is with someone
allowed to act as user "user" and access database "database". Return
STATUS_OK if yes; STATUS_ERROR if not.
Determine what authentication method should be used when accessing database
"database" from frontend "raddr". Return the method, an optional argument,
and STATUS_OK.
----------------------------------------------------------------------------*/
bool host_ok;
/*
* There's an entry for this database and remote host in the pg_hba
* file
*/
char usermap_name[USERMAP_NAME_SIZE + 1];
host_ok = false;
/*
* The name of the map pg_hba specifies for this connection (or
* special value "SAMEUSER")
*/
enum Userauth userauth;
find_hba_entry(raddr, database, &host_ok, auth_method, auth_arg);
/*
* The type of user authentication pg_hba specifies for this
* connection
*/
int retvalue;
/* UNIX socket always OK, for now */
if (port->raddr.in.sin_family == AF_UNIX)
return STATUS_OK;
/* Our eventual return value */
find_hba_entry(DataDir, port->raddr.in.sin_addr, database,
&host_ok, &userauth, usermap_name,
false /* don't find password entries of type
'password' */ );
if (!host_ok)
retvalue = STATUS_ERROR;
else
{
switch (userauth)
{
case Trust:
retvalue = STATUS_OK;
break;
case Ident:
{
/*
* Here's where we need to call up ident and
* authenticate the user
*/
bool authentic; /* He is who he says he
* is. */
authident(DataDir, *port, user, usermap_name, &authentic);
if (authentic)
retvalue = STATUS_OK;
else
retvalue = STATUS_ERROR;
}
break;
default:
retvalue = STATUS_ERROR;
Assert(false);
}
}
return (retvalue);
return (host_ok ? STATUS_OK : STATUS_ERROR);
}
/*----------------------------------------------------------------
* This version of hba was written by Bryan Henderson
* in September 1996 for Release 6.0. It changed the format of the
* hba file and added ident function.
*
* Here are some notes about the original host based authentication
* the preceded this one.
*
* based on the securelib package originally written by William
* LeFebvre, EECS Department, Northwestern University
* (phil@eecs.nwu.edu) - orginal configuration file code handling
* by Sam Horrocks (sam@ics.uci.edu)
*
* modified and adapted for use with Postgres95 by Paul Fisher
* (pnfisher@unity.ncsu.edu)
*
-----------------------------------------------------------------*/

View File

@@ -1,6 +1,6 @@
#include <postgres.h>
#include <miscadmin.h>
#include <libpq/password.h>
#include <libpq/hba.h>
#include <libpq/libpq.h>
#include <storage/fd.h>
#include <string.h>
@@ -10,56 +10,15 @@
#endif
int
verify_password(char *user, char *password, Port *port,
char *database, char *DataDir)
verify_password(char *auth_arg, char *user, char *password)
{
bool host_ok;
enum Userauth userauth;
char pw_file_name[PWFILE_NAME_SIZE + 1];
char *pw_file_fullname;
FILE *pw_file;
char *pw_file_fullname;
FILE *pw_file;
char pw_file_line[255];
char *p,
*test_user,
*test_pw;
find_hba_entry(DataDir, port->raddr.in.sin_addr, database,
&host_ok, &userauth, pw_file_name, true);
if (!host_ok)
{
sprintf(PQerrormsg,
"verify_password: couldn't find entry for connecting host\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
if (userauth != Password)
{
sprintf(PQerrormsg,
"verify_password: couldn't find entry of type 'password' "
"for this host\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
if (!pw_file_name || pw_file_name[0] == '\0')
{
sprintf(PQerrormsg,
"verify_password: no password file specified\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
return STATUS_ERROR;
}
pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(pw_file_name) + 2);
pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(auth_arg) + 2);
strcpy(pw_file_fullname, DataDir);
strcat(pw_file_fullname, "/");
strcat(pw_file_fullname, pw_file_name);
strcat(pw_file_fullname, auth_arg);
pw_file = AllocateFile(pw_file_fullname, "r");
if (!pw_file)
@@ -69,12 +28,17 @@ verify_password(char *user, char *password, Port *port,
pw_file_fullname);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
pfree(pw_file_fullname);
return STATUS_ERROR;
}
while (!feof(pw_file))
{
fgets(pw_file_line, 255, pw_file);
char pw_file_line[255], *p, *test_user, *test_pw;
fgets(pw_file_line, sizeof (pw_file_line), pw_file);
p = pw_file_line;
test_user = strtok(p, ":");
@@ -97,6 +61,9 @@ verify_password(char *user, char *password, Port *port,
if (strcmp(crypt(password, test_pw), test_pw) == 0)
{
/* it matched. */
pfree(pw_file_fullname);
return STATUS_OK;
}
@@ -105,6 +72,9 @@ verify_password(char *user, char *password, Port *port,
user);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
pfree(pw_file_fullname);
return STATUS_ERROR;
}
}
@@ -114,5 +84,8 @@ verify_password(char *user, char *password, Port *port,
user);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
pfree(pw_file_fullname);
return STATUS_ERROR;
}

View File

@@ -4,6 +4,7 @@
#
# This file controls what hosts are allowed to connect to what databases
# and specifies some options on how users on a particular host are identified.
# It is read each time a host tries to make a connection to a database.
#
# Each line (terminated by a newline character) is a record. A record cannot
# be continued across two lines.
@@ -29,13 +30,14 @@
# Record type "host"
# ------------------
#
# This record identifies a set of hosts that are permitted to connect to
# databases. No hosts are permitted to connect except as specified by a
# "host" record.
# This record identifies a set of network hosts that are permitted to connect
# to databases. No network hosts are permitted to connect except as specified
# by a "host" record. See the record type "local" to specify permitted
# connections using UNIX sockets.
#
# Format:
#
# host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [MAP]
# host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [AUTH_ARGUMENT]
#
# DBNAME is the name of a Postgres database, or "all" to indicate all
# databases.
@@ -49,33 +51,54 @@
# under the Postgres username he supplies in his connection parameters.
#
# ident: Authentication is done by the ident server on the remote
# host, via the ident (RFC 1413) protocol.
# host, via the ident (RFC 1413) protocol. AUTH_ARGUMENT, if
# specified, is a map name to be found in the pg_ident.conf file.
# That table maps from ident usernames to Postgres usernames. The
# special map name "sameuser" indicates an implied map (not found
# in pg_ident.conf) that maps every ident username to the identical
# Postgres username.
#
# trust: No authentication is done. Trust that the user has the
# authority to user whatever username he says he does.
# Before Postgres Version 6, all authentication was this way.
#
# MAP is the name of a map that matches an authenticated principal with
# a Postgres username. If USERNAME is "trust", this value is ignored and
# may be absent.
# reject: Reject the connection.
#
# In the case of USERAUTH=ident, this is a map name to be found in the
# pg_ident.conf file. That table maps from ident usernames to Postgres
# usernames. The special map name "sameuser" indicates an implied map
# (not found in pg_ident.conf) that maps every ident username to the identical
# Postgres username.
# password: Authentication is done by matching a password supplied in clear
# by the host. If AUTH_ARGUMENT is specified then the password is
# compared with the user's entry in that file (in the $PGDATA
# directory). See pg_passwd(1). If it is omitted then the
# password is compared with the user's entry in the pg_user table.
#
# crypt: Authentication is done by matching an encrypted password supplied
# by the host with that held for the user in the pg_user table.
#
# krb4: Kerberos V4 authentication is used.
#
# krb5: Kerberos V5 authentication is used.
# Record type "local"
# ------------------
#
# This record identifies the authentication to use when connecting to a
# particular database via a local UNIX socket.
#
# Format:
#
# local DBNAME USERAUTH [AUTH_ARGUMENT]
#
# The format is the same as that of the "host" record type except that the
# IP_ADDRESS and ADDRESS_MASK are omitted and the "ident", "krb4" and "krb5"
# values of USERAUTH are no allowed.
# For backwards compatibility, PostgreSQL also accepts pre-Version 6 records,
# which look like:
#
# all 127.0.0.1 0.0.0.0
#
#
# TYPE DATABASE IP_ADDRESS MASK USERAUTH MAP
host all 127.0.0.1 255.255.255.255 trust
#host all 127.0.0.1 255.255.255.255 trust
# The above allows any user on the local system to connect to any database
# under any username.
@@ -86,10 +109,11 @@ host all 127.0.0.1 255.255.255.255 trust
# connect to database template1 as the same username that ident on that host
# identifies him as (typically his Unix username).
#host all 192.168.0.1 255.255.255.255 reject
#host all 0.0.0.0 0.0.0.0 trust
# The above would allow anyone anywhere to connect to any database under
# any username.
# The above would allow anyone anywhere except from 192.168.0.1 to connect to
# any database under any username.
#host all 192.168.0.0 255.255.255.0 ident omicron
#

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.34 1998/01/25 05:13:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.35 1998/01/26 01:41:11 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -269,28 +270,6 @@ int
pq_getnchar(char *s, int off, int maxlen)
{
return pqGetNBytes(s + off, maxlen, Pfin);
#if 0
int c = '\0';
if (Pfin == (FILE *) NULL)
{
/* elog(DEBUG, "Input descriptor is null"); */
return (EOF);
}
s += off;
while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
*s++ = c;
/* -----------------
* If EOF reached let caller know
* -----------------
*/
if (c == EOF)
return (EOF);
return (!EOF);
#endif
}
/* --------------------------------
@@ -591,11 +570,7 @@ do_unlink()
int
StreamServerPort(char *hostName, short portName, int *fdP)
{
union
{
struct sockaddr_in in;
struct sockaddr_un un;
} saddr;
SockAddr saddr;
int fd,
err,
family;
@@ -624,20 +599,19 @@ StreamServerPort(char *hostName, short portName, int *fdP)
return (STATUS_ERROR);
}
bzero(&saddr, sizeof(saddr));
saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
saddr.un.sun_family = family;
len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);
}
else
{
saddr.in.sin_family = family;
saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.in.sin_port = htons(portName);
len = sizeof saddr.in;
len = sizeof (struct sockaddr_in);
}
err = bind(fd, (struct sockaddr *) & saddr, len);
err = bind(fd, &saddr.sa, len);
if (err < 0)
{
sprintf(PQerrormsg,
@@ -685,7 +659,7 @@ StreamConnection(int server_fd, Port *port)
{
int len,
addrlen;
int family = port->raddr.in.sin_family;
int family = port->raddr.sa.sa_family;
/* accept connection (and fill in the client (remote) address) */
len = family == AF_INET ?
@@ -726,8 +700,6 @@ StreamConnection(int server_fd, Port *port)
}
}
port->mask = 1 << port->sock;
/* reset to non-blocking */
fcntl(port->sock, F_SETFL, 1);
@@ -788,7 +760,7 @@ StreamOpen(char *hostName, short portName, Port *port)
len = UNIXSOCK_PATH(port->raddr.un, portName);
}
/* connect to the server */
if ((port->sock = socket(port->raddr.in.sin_family, SOCK_STREAM, 0)) < 0)
if ((port->sock = socket(port->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
{
sprintf(PQerrormsg,
"FATAL: StreamOpen: socket() failed: errno=%d\n",
@@ -797,7 +769,7 @@ StreamOpen(char *hostName, short portName, Port *port)
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
err = connect(port->sock, (struct sockaddr *) & port->raddr, len);
err = connect(port->sock, &port->raddr.sa, len);
if (err < 0)
{
sprintf(PQerrormsg,
@@ -809,8 +781,7 @@ StreamOpen(char *hostName, short portName, Port *port)
}
/* fill in the client address */
if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
&len) < 0)
if (getsockname(port->sock, &port->laddr.sa, &len) < 0)
{
sprintf(PQerrormsg,
"FATAL: StreamOpen: getsockname() failed: errno=%d\n",
@@ -822,32 +793,3 @@ StreamOpen(char *hostName, short portName, Port *port)
return (STATUS_OK);
}
static char *authentication_type_name[] = {
0, 0, 0, 0, 0, 0, 0,
"the default authentication type",
0, 0,
"Kerberos v4",
"Kerberos v5",
"host-based authentication",
"unauthenication",
"plaintext password authentication"
};
char *
name_of_authentication_type(int type)
{
char *result = 0;
if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
{
result = authentication_type_name[type];
}
if (result == 0)
{
result = "<unknown authentication type>";
}
return result;
}

View File

@@ -1,122 +1,150 @@
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include "postgres.h"
#include "libpq/pqcomm.h"
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
/* --------------------------------------------------------------------- */
/* These definitions for ntoh/hton are the other way around from the
* default system definitions, so we roll our own here.
/*
* The backend supports the old little endian byte order and the current
* network byte order.
*/
#ifndef FRONTEND
#include "libpq/libpq-be.h"
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#ifndef BYTE_ORDER
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#define ntoh_s(n) n
#define ntoh_l(n) n
#define hton_s(n) n
#define hton_l(n) n
#else /* BYTE_ORDER != LITTLE_ENDIAN */
#define ntoh_s(n) n
#define ntoh_l(n) n
#define hton_s(n) n
#define hton_l(n) n
#else
#if BYTE_ORDER == BIG_ENDIAN
#define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
| ((u_char *)&n)[0])
#define ntoh_l(n) (uint32) (((u_char *)&n)[3] << 24 \
| ((u_char *)&n)[2] << 16 \
| ((u_char *)&n)[1] << 8 \
| ((u_char *)&n)[0])
#define hton_s(n) (ntoh_s(n))
#define hton_l(n) (ntoh_l(n))
#define ntoh_s(n) (uint16)(((u_char *)&n)[1] << 8 \
| ((u_char *)&n)[0])
#define ntoh_l(n) (uint32)(((u_char *)&n)[3] << 24 \
| ((u_char *)&n)[2] << 16 \
| ((u_char *)&n)[1] << 8 \
| ((u_char *)&n)[0])
#define hton_s(n) (ntoh_s(n))
#define hton_l(n) (ntoh_l(n))
#else
/* BYTE_ORDER != BIG_ENDIAN */
#if BYTE_ORDER == PDP_ENDIAN
#error PDP_ENDIAN macros not written yet
#else
/* BYTE_ORDER != anything known */
#error BYTE_ORDER not defined as anything understood
#endif /* BYTE_ORDER == PDP_ENDIAN */
#endif /* BYTE_ORDER == BIG_ENDIAN */
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
#endif
#endif
#endif
#endif
/* --------------------------------------------------------------------- */
int
pqPutShort(int integer, FILE *f)
{
int retval = 0;
u_short n,
s;
uint16 n;
s = integer;
n = hton_s(s);
if (fwrite(&n, sizeof(u_short), 1, f) != 1)
retval = EOF;
#ifdef FRONTEND
n = htons((uint16)integer);
#else
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(integer) : htons((uint16)integer));
#endif
return retval;
if (fwrite(&n, 2, 1, f) != 1)
return EOF;
return 0;
}
/* --------------------------------------------------------------------- */
int
pqPutLong(int integer, FILE *f)
{
int retval = 0;
uint32 n;
uint32 n;
n = hton_l(integer);
if (fwrite(&n, sizeof(uint32), 1, f) != 1)
retval = EOF;
#ifdef FRONTEND
n = htonl((uint32)integer);
#else
n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(integer) : htonl((uint32)integer));
#endif
return retval;
if (fwrite(&n, 4, 1, f) != 1)
return EOF;
return 0;
}
/* --------------------------------------------------------------------- */
int
pqGetShort(int *result, FILE *f)
{
int retval = 0;
u_short n;
uint16 n;
if (fread(&n, sizeof(u_short), 1, f) != 1)
retval = EOF;
if (fread(&n, 2, 1, f) != 1)
return EOF;
*result = ntoh_s(n);
return retval;
#ifdef FRONTEND
*result = (int)ntohs(n);
#else
*result = (int)((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_s(n) : ntohs(n));
#endif
return 0;
}
/* --------------------------------------------------------------------- */
int
pqGetLong(int *result, FILE *f)
{
int retval = 0;
uint32 n;
uint32 n;
if (fread(&n, sizeof(uint32), 1, f) != 1)
retval = EOF;
if (fread(&n, 4, 1, f) != 1)
return EOF;
*result = ntoh_l(n);
return retval;
#ifdef FRONTEND
*result = (int)ntohl(n);
#else
*result = (int)((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_l(n) : ntohl(n));
#endif
return 0;
}
/* --------------------------------------------------------------------- */
/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s.
/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s (which must be 1
byte longer) and terminate it with a '\0'.
Return 0 if ok.
*/
int
pqGetNBytes(char *s, size_t len, FILE *f)
{
int cnt;
int cnt;
if (f == NULL)
return EOF;
cnt = fread(s, 1, len, f);
s[cnt] = '\0';
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
return (cnt == len) ? 0 : EOF;
}
@@ -126,7 +154,7 @@ int
pqPutNBytes(const char *s, size_t len, FILE *f)
{
if (f == NULL)
return 0;
return EOF;
if (fwrite(s, 1, len, f) != len)
return EOF;
@@ -138,15 +166,27 @@ pqPutNBytes(const char *s, size_t len, FILE *f)
int
pqGetString(char *s, size_t len, FILE *f)
{
int c;
int c;
if (f == NULL)
return EOF;
while (len-- && (c = getc(f)) != EOF && c)
*s++ = c;
/*
* Keep on reading until we get the terminating '\0' and discard those
* bytes we don't have room for.
*/
while ((c = getc(f)) != EOF && c != '\0')
if (len > 1)
{
*s++ = c;
len--;
}
*s = '\0';
/* mjl: actually needs up to len+1 bytes, is this okay? XXX */
if (c == EOF)
return EOF;
return 0;
}
@@ -183,5 +223,3 @@ pqPutByte(int c, FILE *f)
return (putc(c, f) == c) ? 0 : EOF;
}
/* --------------------------------------------------------------------- */

View File

@@ -8,36 +8,14 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.12 1997/12/09 03:10:51 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.13 1998/01/26 01:41:12 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/* NOTES
* This is the module that understands the lowest-level part
* of the communication protocol. All of the trickiness in
* this module is for making sure that non-blocking I/O in
* the Postmaster works correctly. Check the notes in PacketRecv
* on non-blocking I/O.
*
* Data Structures:
* Port has two important functions. (1) It records the
* sock/addr used in communication. (2) It holds partially
* read in messages. This is especially important when
* we haven't seen enough to construct a complete packet
* header.
*
* PacketBuf -- None of the clients of this module should know
* what goes into a packet hdr (although they know how big
* it is). This routine is in charge of host to net order
* conversion for headers. Data conversion is someone elses
* responsibility.
*
* IMPORTANT: these routines are called by backends, clients, and
* the Postmaster.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@@ -50,260 +28,158 @@
#include <storage/ipc.h>
#include <libpq/libpq.h>
/*
* PacketReceive -- receive a packet on a port.
*
* RETURNS: connection id of the packet sender, if one
* is available.
*
* Set up a packet read for the postmaster event loop.
*/
int
PacketReceive(Port *port, /* receive port */
PacketBuf *buf, /* MAX_PACKET_SIZE-worth of buffer space */
bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
void PacketReceiveSetup(Packet *pkt, void (*iodone)(), char *arg)
{
PacketLen max_size = sizeof(PacketBuf);
PacketLen cc; /* character count -- bytes recvd */
PacketLen packetLen; /* remaining packet chars to read */
Addr tmp; /* curr recv buf pointer */
int hdrLen;
int flag;
int decr;
pkt->nrtodo = sizeof (pkt->len);
pkt->ptr = (char *)&pkt->len;
pkt->iodone = iodone;
pkt->arg = arg;
pkt->state = ReadingPacketLength;
}
hdrLen = sizeof(buf->len);
if (nonBlocking == NON_BLOCKING)
/*
* Read a packet fragment. Return STATUS_OK if the connection should stay
* open.
*/
int PacketReceiveFragment(Packet *pkt, int sock)
{
int got;
if ((got = read(sock,pkt->ptr,pkt->nrtodo)) > 0)
{
flag = MSG_PEEK;
decr = 0;
pkt->nrtodo -= got;
pkt->ptr += got;
/* See if we have got what we need for the packet length. */
if (pkt->nrtodo == 0 && pkt->state == ReadingPacketLength)
{
pkt->len = ntohl(pkt->len);
if (pkt->len < sizeof (pkt->len) ||
pkt->len > sizeof (pkt->len) + sizeof (pkt->pkt))
{
PacketSendError(pkt,"Invalid packet length");
return STATUS_OK;
}
/* Set up for the rest of the packet. */
pkt->nrtodo = pkt->len - sizeof (pkt->len);
pkt->ptr = (char *)&pkt->pkt;
pkt->state = ReadingPacket;
}
/* See if we have got what we need for the packet. */
if (pkt->nrtodo == 0 && pkt->state == ReadingPacket)
{
pkt->state = Idle;
/* Special case to close the connection. */
if (pkt->iodone == NULL)
return STATUS_ERROR;
(*pkt->iodone)(pkt->arg, pkt->len - sizeof (pkt->len),
(char *)&pkt->pkt);
}
return STATUS_OK;
}
else
if (got == 0)
return STATUS_ERROR;
if (errno == EINTR)
return STATUS_OK;
fprintf(stderr, "read() system call failed\n");
return STATUS_ERROR;
}
/*
* Set up a packet write for the postmaster event loop.
*/
void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone)(), char *arg)
{
pkt->nrtodo = nbytes;
pkt->ptr = (char *)&pkt->pkt;
pkt->iodone = iodone;
pkt->arg = arg;
pkt->state = WritingPacket;
}
/*
* Write a packet fragment. Return STATUS_OK if the connection should stay
* open.
*/
int PacketSendFragment(Packet *pkt, int sock)
{
int done;
if ((done = write(sock,pkt->ptr,pkt->nrtodo)) > 0)
{
flag = 0;
decr = hdrLen;
pkt->nrtodo -= done;
pkt->ptr += done;
/* See if we have written the whole packet. */
if (pkt->nrtodo == 0)
{
pkt->state = Idle;
/* Special case to close the connection. */
if (pkt->iodone == NULL)
return STATUS_ERROR;
(*pkt->iodone)(pkt->arg);
}
return STATUS_OK;
}
if (done == 0)
return STATUS_ERROR;
if (errno == EINTR)
return STATUS_OK;
fprintf(stderr, "write() system call failed\n");
return STATUS_ERROR;
}
/*
* Send an error message from the postmaster to the frontend.
*/
void PacketSendError(Packet *pkt, char *errormsg)
{
fprintf(stderr, "%s\n", errormsg);
pkt->pkt.em.data[0] = 'E';
StrNCpy(&pkt->pkt.em.data[1], errormsg, sizeof (pkt->pkt.em.data) - 2);
/*
* Assume port->nBytes is zero unless we were interrupted during
* non-blocking I/O. This first recv() is to get the hdr information
* so we know how many bytes to read. Life would be very complicated
* if we read too much data (buffering).
* The NULL i/o callback will cause the connection to be broken when
* the error message has been sent.
*/
tmp = ((Addr) buf) + port->nBytes;
if (port->nBytes >= hdrLen)
{
packetLen = ntohl(buf->len) - port->nBytes;
}
else
{
/* peeking into the incoming message */
cc = recv(port->sock, (char *) &(buf->len), hdrLen, flag);
if (cc < hdrLen)
{
/* if cc is negative, the system call failed */
if (cc < 0)
{
return (STATUS_ERROR);
}
/*
* cc == 0 means the connection was broken at the other end.
*/
else if (!cc)
{
return (STATUS_INVALID);
}
else
{
/*
* Worst case. We didn't even read in enough data to get
* the header length. since we are using a data stream,
* this happens only if the client is mallicious.
*
* Don't save the number of bytes we've read so far. Since we
* only peeked at the incoming message, the kernel is
* going to keep it for us.
*/
return (STATUS_NOT_DONE);
}
}
else
{
/*
* This is an attempt to shield the Postmaster from mallicious
* attacks by placing tighter restrictions on the reported
* packet length.
*
* Check for negative packet length
*/
if ((buf->len) <= 0)
{
return (STATUS_INVALID);
}
/*
* Check for oversize packet
*/
if ((ntohl(buf->len)) > max_size)
{
return (STATUS_INVALID);
}
/*
* great. got the header. now get the true length (including
* header size).
*/
packetLen = ntohl(buf->len);
/*
* if someone is sending us junk, close the connection
*/
if (packetLen > max_size)
{
port->nBytes = packetLen;
return (STATUS_BAD_PACKET);
}
packetLen -= decr;
tmp += decr - port->nBytes;
}
}
/*
* Now that we know how big it is, read the packet. We read the
* entire packet, since the last call was just a peek.
*/
while (packetLen)
{
cc = read(port->sock, tmp, packetLen);
if (cc < 0)
return (STATUS_ERROR);
/*
* cc == 0 means the connection was broken at the other end.
*/
else if (!cc)
return (STATUS_INVALID);
/*
fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
packetLen, cc);
*/
tmp += cc;
packetLen -= cc;
/* if non-blocking, we're done. */
if (nonBlocking && packetLen)
{
port->nBytes += cc;
return (STATUS_NOT_DONE);
}
}
port->nBytes = 0;
return (STATUS_OK);
PacketSendSetup(pkt, strlen(pkt->pkt.em.data) + 1, NULL, NULL);
}
/*
* PacketSend -- send a single-packet message.
*
* RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
* SIDE_EFFECTS: may block.
* NOTES: Non-blocking writes would significantly complicate
* buffer management. For now, we're not going to do it.
*
*/
int
PacketSend(Port *port,
PacketBuf *buf,
PacketLen len,
bool nonBlocking)
{
PacketLen doneLen;
Assert(!nonBlocking);
Assert(buf);
doneLen = write(port->sock, buf, len);
if (doneLen < len)
{
sprintf(PQerrormsg,
"FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
errno);
fputs(PQerrormsg, stderr);
return (STATUS_ERROR);
}
return (STATUS_OK);
}
/*
* StartupInfo2PacketBuf -
* convert the fields of the StartupInfo to a PacketBuf
*
*/
/* moved to src/libpq/fe-connect.c */
/*
PacketBuf*
StartupInfo2PacketBuf(StartupInfo* s)
{
PacketBuf* res;
char* tmp;
res = (PacketBuf*)palloc(sizeof(PacketBuf));
res->len = htonl(sizeof(PacketBuf));
res->data[0] = '\0';
tmp= res->data;
strncpy(tmp, s->database, sizeof(s->database));
tmp += sizeof(s->database);
strncpy(tmp, s->user, sizeof(s->user));
tmp += sizeof(s->user);
strncpy(tmp, s->options, sizeof(s->options));
tmp += sizeof(s->options);
strncpy(tmp, s->execFile, sizeof(s->execFile));
tmp += sizeof(s->execFile);
strncpy(tmp, s->tty, sizeof(s->execFile));
return res;
}
*/
/*
* PacketBuf2StartupInfo -
* convert the fields of the StartupInfo to a PacketBuf
*
*/
/* moved to postmaster.c
StartupInfo*
PacketBuf2StartupInfo(PacketBuf* p)
{
StartupInfo* res;
char* tmp;
res = (StartupInfo*)palloc(sizeof(StartupInfo));
res->database[0]='\0';
res->user[0]='\0';
res->options[0]='\0';
res->execFile[0]='\0';
res->tty[0]='\0';
tmp= p->data;
strncpy(res->database,tmp,sizeof(res->database));
tmp += sizeof(res->database);
strncpy(res->user,tmp, sizeof(res->user));
tmp += sizeof(res->user);
strncpy(res->options,tmp, sizeof(res->options));
tmp += sizeof(res->options);
strncpy(res->execFile,tmp, sizeof(res->execFile));
tmp += sizeof(res->execFile);
strncpy(res->tty,tmp, sizeof(res->tty));
return res;
}
*/

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.69 1998/01/25 05:13:35 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.70 1998/01/26 01:41:15 scrappy Exp $
*
* NOTES
*
@@ -102,7 +102,8 @@
#endif
#endif
#define LINGER_TIME 3
#define INVALID_SOCK (-1)
#define ARGV_SIZE 64
/*
* Max time in seconds for socket to linger (close() to block) waiting
@@ -182,28 +183,24 @@ static int SendStop = 0;
static int NetServer = 0; /* if not zero, postmaster listen for
* non-local connections */
static int MultiplexedBackends = 0;
static int MultiplexedBackendPort;
/*
* postmaster.c - function prototypes
*/
static void pmdaemonize(void);
static void
ConnStartup(Port *port, int *status,
char *errormsg, const int errormsg_len);
static int ConnCreate(int serverFd, int *newFdP);
static Port *ConnCreate(int serverFd);
static void reset_shared(short port);
static void pmdie(SIGNAL_ARGS);
static void reaper(SIGNAL_ARGS);
static void dumpstatus(SIGNAL_ARGS);
static void CleanupProc(int pid, int exitstatus);
static int DoExec(StartupInfo *packet, int portFd);
static int DoExec(Port *port);
static void ExitPostmaster(int status);
static void usage(const char *);
static int ServerLoop(void);
static int BackendStartup(StartupInfo *packet, Port *port, int *pidPtr);
static void send_error_reply(Port *port, const char *errormsg);
static int BackendStartup(Port *port);
static void readStartupPacket(char *arg, PacketLen len, char *pkt);
static int initMasks(fd_set *rmask, fd_set *wmask);
static void RandomSalt(char* salt);
extern char *optarg;
@@ -307,8 +304,7 @@ PostmasterMain(int argc, char *argv[])
switch (opt)
{
case 'a':
/* Set the authentication system. */
be_setauthsvc(optarg);
/* Can no longer set authentication method. */
break;
case 'B':
@@ -354,8 +350,7 @@ PostmasterMain(int argc, char *argv[])
NetServer = 1;
break;
case 'm':
MultiplexedBackends = 1;
MultiplexedBackendPort = atoi(optarg);
/* Multiplexed backends no longer supported. */
break;
case 'M':
@@ -501,13 +496,11 @@ static void
usage(const char *progname)
{
fprintf(stderr, "usage: %s [options..]\n", progname);
fprintf(stderr, "\t-a authsys\tdo/do not permit use of an authentication system\n");
fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");
fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");
fprintf(stderr, "\t-D datadir\tset data directory\n");
fprintf(stderr, "\t-i \tlisten on TCP/IP sockets as well as Unix domain socket\n");
fprintf(stderr, "\t-m \tstart up multiplexing backends\n");
fprintf(stderr, "\t-n\t\tdon't reinitialize shared memory after abnormal exit\n");
fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
fprintf(stderr, "\t-p port\t\tspecify port for postmaster to listen on\n");
@@ -519,15 +512,9 @@ usage(const char *progname)
static int
ServerLoop(void)
{
fd_set rmask,
basemask;
int nSockets,
nSelected,
status,
oldFd,
newFd;
Dlelem *next,
*curr;
fd_set readmask, writemask;
int nSockets;
Dlelem *curr;
/*
* GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented an
@@ -541,16 +528,8 @@ ServerLoop(void)
int orgsigmask = sigblock(0);
#endif
FD_ZERO(&basemask);
FD_SET(ServerSock_UNIX, &basemask);
nSockets = ServerSock_UNIX;
if (ServerSock_INET != INVALID_SOCK)
{
FD_SET(ServerSock_INET, &basemask);
if (ServerSock_INET > ServerSock_UNIX)
nSockets = ServerSock_INET;
}
nSockets++;
nSockets = initMasks(&readmask, &writemask);
#ifdef HAVE_SIGPROCMASK
sigprocmask(0, 0, &oldsigmask);
@@ -559,17 +538,19 @@ ServerLoop(void)
#endif
for (;;)
{
Port *port;
fd_set rmask, wmask;
#ifdef HAVE_SIGPROCMASK
sigprocmask(SIG_SETMASK, &oldsigmask, 0);
#else
sigsetmask(orgsigmask);
#endif
newFd = -1;
memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
if ((nSelected = select(nSockets, &rmask,
(fd_set *) NULL,
(fd_set *) NULL,
(struct timeval *) NULL)) < 0)
memmove((char *) &rmask, (char *) &readmask, sizeof(fd_set));
memmove((char *) &wmask, (char *) &writemask, sizeof(fd_set));
if (select(nSockets, &rmask, &wmask, (fd_set *) NULL,
(struct timeval *) NULL) < 0)
{
if (errno == EINTR)
continue;
@@ -589,344 +570,209 @@ ServerLoop(void)
#else
sigblock(sigmask(SIGCHLD)); /* XXX[TRH] portability */
#endif
if (DebugLvl > 1)
{
fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
progname, nSelected);
}
/* new connection pending on our well-known port's socket */
oldFd = -1;
if (FD_ISSET(ServerSock_UNIX, &rmask))
oldFd = ServerSock_UNIX;
else if (ServerSock_INET != INVALID_SOCK &&
FD_ISSET(ServerSock_INET, &rmask))
oldFd = ServerSock_INET;
if (oldFd >= 0)
{
/*
* connect and make an addition to PortList. If the
* connection dies and we notice it, just forget about the
* whole thing.
*/
if (ConnCreate(oldFd, &newFd) == STATUS_OK)
{
if (newFd >= nSockets)
nSockets = newFd + 1;
FD_SET(newFd, &rmask);
FD_SET(newFd, &basemask);
if (DebugLvl)
fprintf(stderr, "%s: ServerLoop: connect on %d\n",
progname, newFd);
}
else if (DebugLvl)
fprintf(stderr,
"%s: ServerLoop: connect failed: (%d) %s\n",
progname, errno, strerror(errno));
--nSelected;
FD_CLR(oldFd, &rmask);
}
if (ServerSock_UNIX != INVALID_SOCK &&
FD_ISSET(ServerSock_UNIX, &rmask) &&
(port = ConnCreate(ServerSock_UNIX)) != NULL)
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(char *)port);
if (DebugLvl > 1)
{
fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
progname, nSelected);
curr = DLGetHead(PortList);
while (curr)
{
Port *port = DLE_VAL(curr);
if (ServerSock_INET != INVALID_SOCK &&
FD_ISSET(ServerSock_INET, &rmask) &&
(port = ConnCreate(ServerSock_INET)) != NULL)
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(char *)port);
fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
progname, port->sock,
FD_ISSET(port->sock, &rmask)
? "" :
" not");
curr = DLGetSucc(curr);
}
}
/* Build up new masks for select(). */
nSockets = initMasks(&readmask, &writemask);
curr = DLGetHead(PortList);
while (curr)
{
Port *port = (Port *) DLE_VAL(curr);
int lastbytes = port->nBytes;
int status = STATUS_OK;
Dlelem *next;
if (FD_ISSET(port->sock, &rmask) && port->sock != newFd)
if (FD_ISSET(port->sock, &rmask))
{
if (DebugLvl > 1)
fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
fprintf(stderr, "%s: ServerLoop:\t\thandling reading %d\n",
progname, port->sock);
--nSelected;
if (PacketReceiveFragment(&port->pktInfo, port->sock) != STATUS_OK)
status = STATUS_ERROR;
}
if (FD_ISSET(port->sock, &wmask))
{
if (DebugLvl > 1)
fprintf(stderr, "%s: ServerLoop:\t\thandling writing %d\n",
progname, port->sock);
if (PacketSendFragment(&port->pktInfo, port->sock) != STATUS_OK)
status = STATUS_ERROR;
}
/* Get this before the connection might be closed. */
next = DLGetSucc(curr);
/*
* If there is no error and no outstanding data transfer
* going on, then the authentication handshake must be
* complete to the postmaster's satisfaction. So,
* start the backend.
*/
if (status == STATUS_OK && port->pktInfo.state == Idle)
{
/*
* Read the incoming packet into its packet buffer. Read
* the connection id out of the packet so we know who the
* packet is from.
* If the backend start fails then keep the
* connection open to report it. Otherwise,
* pretend there is an error to close the
* connection which will now be managed by the
* backend.
*/
receive_again:
status = PacketReceive(port, &port->buf, NON_BLOCKING);
switch (status)
{
case STATUS_OK:
/* Here is where we check for a USER login packet. If there is one, then
* we must deterine whether the login has a password in pg_user. If so, send
* back a salt to crypt() the password with. Otherwise, send an unsalt packet
* back and read the real startup packet.
*/
if (ntohl(port->buf.msgtype) == STARTUP_USER_MSG) {
PacketLen plen;
port->buf.msgtype = htonl(crypt_salt(port->buf.data));
plen = sizeof(port->buf.len) + sizeof(port->buf.msgtype) + 2;
port->buf.len = htonl(plen);
RandomSalt(port->salt);
memcpy((void*)port->buf.data, (void*)port->salt, 2);
if (BackendStartup(port) != STATUS_OK)
PacketSendError(&port->pktInfo,
"Backend startup failed");
else
status = STATUS_ERROR;
}
status = PacketSend(port, &port->buf, plen, BLOCKING);
if (status != STATUS_OK)
break;
/* Close the connection if required. */
/* port->nBytes = 0; */
goto receive_again;
} else {
int CSstatus; /* Completion status of
* ConnStartup */
char errormsg[200]; /* error msg from
* ConnStartup */
ConnStartup(port, &CSstatus, errormsg, sizeof(errormsg));
if (CSstatus == STATUS_ERROR)
send_error_reply(port, errormsg);
ActiveBackends = TRUE;
}
/* FALLTHROUGH */
case STATUS_INVALID:
if (DebugLvl)
fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
progname, port->sock);
break;
case STATUS_BAD_PACKET:
/*
* This is a bogus client, kill the connection and
* forget the whole thing.
*/
if (DebugLvl)
fprintf(stderr, "%s: ServerLoop:\t\tbad packet format (reported packet size of %d read on port %d\n", progname, port->nBytes, port->sock);
break;
case STATUS_NOT_DONE:
if (DebugLvl)
fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
progname, port->nBytes, port->sock);
/*
* If we've received at least a PacketHdr's worth
* of data and we're still receiving data each
* time we read, we're ok. If the client gives us
* less than a PacketHdr at the beginning, just
* kill the connection and forget about the whole
* thing.
*/
if (lastbytes < port->nBytes)
{
if (DebugLvl)
fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
progname, port->sock);
curr = DLGetSucc(curr);
continue;
}
break;
case STATUS_ERROR: /* system call error - die */
fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
progname);
return (STATUS_ERROR);
}
FD_CLR(port->sock, &basemask);
if (status != STATUS_OK)
{
StreamClose(port->sock);
next = DLGetSucc(curr);
DLRemove(curr);
free(port);
DLFreeElem(curr);
curr = next;
continue;
}
curr = DLGetSucc(curr);
}
Assert(nSelected == 0);
}
}
/*
ConnStartup: get the startup packet from the front end (client),
authenticate the user, and start up a backend.
If all goes well, return *status == STATUS_OK.
Otherwise, return *status == STATUS_ERROR and return a text string
explaining why in the "errormsg_len" bytes at "errormsg",
*/
static void
ConnStartup(Port *port, int *status,
char *errormsg, const int errormsg_len)
{
MsgType msgType;
char namebuf[NAMEDATALEN];
int pid;
PacketBuf *p;
StartupInfo sp;
char *tmp;
p = &port->buf;
sp.database[0] = '\0';
sp.user[0] = '\0';
sp.options[0] = '\0';
sp.execFile[0] = '\0';
sp.tty[0] = '\0';
tmp = p->data;
strncpy(sp.database, tmp, sizeof(sp.database));
tmp += sizeof(sp.database);
strncpy(sp.user, tmp, sizeof(sp.user));
tmp += sizeof(sp.user);
strncpy(sp.options, tmp, sizeof(sp.options));
tmp += sizeof(sp.options);
strncpy(sp.execFile, tmp, sizeof(sp.execFile));
tmp += sizeof(sp.execFile);
strncpy(sp.tty, tmp, sizeof(sp.tty));
msgType = (MsgType) ntohl(port->buf.msgtype);
StrNCpy(namebuf, sp.user, NAMEDATALEN);
if (!namebuf[0])
{
strncpy(errormsg,
"No Postgres username specified in startup packet.",
errormsg_len);
*status = STATUS_ERROR;
}
else
{
if (be_recvauth(msgType, port, namebuf, &sp) != STATUS_OK)
{
char buffer[200 + sizeof(namebuf)];
sprintf(buffer,
"Failed to authenticate client as Postgres user '%s' "
"using %s: %s",
namebuf, name_of_authentication_type(msgType), PQerrormsg);
strncpy(errormsg, buffer, errormsg_len);
*status = STATUS_ERROR;
}
else
{
if (BackendStartup(&sp, port, &pid) != STATUS_OK)
{
strncpy(errormsg, "Startup (fork) of backend failed.",
errormsg_len);
*status = STATUS_ERROR;
}
else
{
errormsg[0] = '\0'; /* just for robustness */
*status = STATUS_OK;
/* Set the masks for this connection. */
if (nSockets <= port->sock)
nSockets = port->sock + 1;
if (port->pktInfo.state == WritingPacket)
FD_SET(port->sock, &writemask);
else
FD_SET(port->sock, &readmask);
}
curr = next;
}
}
if (*status == STATUS_ERROR)
fprintf(stderr, "%s: ConnStartup: %s\n", progname, errormsg);
}
/*
send_error_reply: send a reply to the front end telling it that
the connection was a bust, and why.
* Initialise the read and write masks for select() for the well-known ports
* we are listening on. Return the number of sockets to listen on.
*/
"port" tells to whom and how to send the reply. "errormsg" is
the string of text telling what the problem was.
It should be noted that we're executing a pretty messy protocol
here. The postmaster does not reply when the connection is
successful, but rather just hands the connection off to the
backend and the backend waits for a query from the frontend.
Thus, the frontend is not expecting any reply in regards to the
connect request.
But when the connection fails, we send this reply that starts
with "E". The frontend only gets this reply when it sends its
first query and waits for the reply. Nobody receives that query,
but this reply is already in the pipe, so that's what the
frontend sees.
Note that the backend closes the socket immediately after sending
the reply, so to give the frontend a fighting chance to see the
error info, we set the socket to linger up to 3 seconds waiting
for the frontend to retrieve the message. That's all the delay
we can afford, since we have other clients to serve and the
postmaster will be blocked the whole time. Also, if there is no
message space in the socket for the reply (shouldn't be a
problem) the postmaster will block until the frontend reads the
reply.
*/
static void
send_error_reply(Port *port, const char *errormsg)
static int initMasks(fd_set *rmask, fd_set *wmask)
{
int rc; /* return code from write */
char *reply;
int nsocks = -1;
/*
* The literal reply string we put into the socket. This is a pointer
* to storage we malloc.
*/
const struct linger linger_parm = {true, LINGER_TIME};
FD_ZERO(rmask);
FD_ZERO(wmask);
/*
* A parameter for setsockopt() that tells it to have close() block
* for a while waiting for the frontend to read its outstanding
* messages.
*/
if (ServerSock_UNIX != INVALID_SOCK)
{
FD_SET(ServerSock_UNIX, rmask);
reply = malloc(strlen(errormsg) + 10);
if (ServerSock_UNIX > nsocks)
nsocks = ServerSock_UNIX;
}
sprintf(reply, "E%s", errormsg);
if (ServerSock_INET != INVALID_SOCK)
{
FD_SET(ServerSock_INET, rmask);
rc = write(port->sock, (Addr) reply, strlen(reply) + 1);
if (rc < 0)
fprintf(stderr,
"%s: ServerLoop:\t\t"
"Failed to send error reply to front end\n",
progname);
else if (rc < strlen(reply) + 1)
fprintf(stderr,
"%s: ServerLoop:\t\t"
"Only partial error reply sent to front end.\n",
progname);
if (ServerSock_INET > nsocks)
nsocks = ServerSock_INET;
}
free(reply);
return (nsocks + 1);
}
/*
* Now we have to make sure frontend has a chance to see what we just
* wrote.
*/
rc = setsockopt(port->sock, SOL_SOCKET, SO_LINGER,
&linger_parm, sizeof(linger_parm));
/*
* Called when the startup packet has been read.
*/
static void readStartupPacket(char *arg, PacketLen len, char *pkt)
{
Port *port;
StartupPacket *si;
port = (Port *)arg;
si = (StartupPacket *)pkt;
/* At the moment the startup packet must be a fixed length. */
if (len != sizeof (StartupPacket))
{
PacketSendError(&port->pktInfo, "Invalid startup packet.");
return;
}
/* Get the parameters from the startup packet as C strings. */
StrNCpy(port->database, si->database, sizeof (port->database) - 1);
StrNCpy(port->user, si->user, sizeof (port->user) - 1);
StrNCpy(port->options, si->options, sizeof (port->options) - 1);
StrNCpy(port->tty, si->tty, sizeof (port->tty) - 1);
/* The database defaults to the user name. */
if (port->database[0] == '\0')
StrNCpy(port->database, si->user, sizeof (port->database) - 1);
/* Check we can handle the protocol the frontend is using. */
port->proto = ntohl(si->protoVersion);
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)))
{
PacketSendError(&port->pktInfo, "Unsupported frontend protocol.");
return;
}
/* Check a user name was given. */
if (port->user[0] == '\0')
{
PacketSendError(&port->pktInfo,
"No Postgres username specified in startup packet.");
return;
}
/* Start the authentication itself. */
be_recvauth(port);
}
/*
* ConnCreate -- create a local connection data structure
*/
static int
ConnCreate(int serverFd, int *newFdP)
static Port *
ConnCreate(int serverFd)
{
int status;
Port *port;
@@ -937,18 +783,20 @@ ConnCreate(int serverFd, int *newFdP)
ExitPostmaster(1);
}
if ((status = StreamConnection(serverFd, port)) != STATUS_OK)
if (StreamConnection(serverFd, port) != STATUS_OK)
{
StreamClose(port->sock);
free(port);
port = NULL;
}
else
{
DLAddHead(PortList, DLNewElem(port));
*newFdP = port->sock;
RandomSalt(port->salt);
port->pktInfo.state = Idle;
}
return (status);
return port;
}
/*
@@ -1125,9 +973,7 @@ CleanupProc(int pid,
*
*/
static int
BackendStartup(StartupInfo *packet, /* client's startup packet */
Port *port,
int *pidPtr)
BackendStartup(Port *port)
{
Backend *bn; /* for backend cleanup */
int pid,
@@ -1148,7 +994,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
putenv(envEntry[0]);
sprintf(envEntry[1], "POSTID=%d", NextBackendId);
putenv(envEntry[1]);
sprintf(envEntry[2], "PG_USER=%s", packet->user);
sprintf(envEntry[2], "PG_USER=%s", port->user);
putenv(envEntry[2]);
if (!getenv("PGDATA"))
{
@@ -1173,7 +1019,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
if ((pid = FORK()) == 0)
{ /* child */
if (DoExec(packet, port->sock))
if (DoExec(port))
fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
progname, pid);
/* use _exit to keep from double-flushing stdio */
@@ -1190,8 +1036,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
if (DebugLvl)
fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
progname, pid, packet->user,
(packet->database[0] == '\0' ? packet->user : packet->database),
progname, pid, port->user, port->database,
port->sock);
/* adjust backend counter */
@@ -1212,10 +1057,7 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
bn->pid = pid;
DLAddHead(BackendList, DLNewElem(bn));
if (MultiplexedBackends)
MultiplexedBackendPort++;
*pidPtr = pid;
ActiveBackends = TRUE;
return (STATUS_OK);
}
@@ -1262,19 +1104,19 @@ split_opts(char **argv, int *argcp, char *s)
* If execv() fails, return status.
*/
static int
DoExec(StartupInfo *packet, int portFd)
DoExec(Port *port)
{
char execbuf[MAXPATHLEN];
char portbuf[ARGV_SIZE];
char mbbuf[ARGV_SIZE];
char debugbuf[ARGV_SIZE];
char ttybuf[ARGV_SIZE + 1];
char protobuf[ARGV_SIZE + 1];
char argbuf[(2 * ARGV_SIZE) + 1];
/*
* each argument takes at least three chars, so we can't have more
* than ARGV_SIZE arguments in (2 * ARGV_SIZE) chars (i.e.,
* packet->options plus ExtraOptions)...
* port->options plus ExtraOptions)...
*/
char *av[ARGV_SIZE];
char dbbuf[ARGV_SIZE + 1];
@@ -1304,34 +1146,30 @@ DoExec(StartupInfo *packet, int portFd)
av[ac++] = "-Q";
/* Pass the requested debugging output file */
if (packet->tty[0])
if (port->tty[0])
{
strncpy(ttybuf, packet->tty, ARGV_SIZE);
strncpy(ttybuf, port->tty, ARGV_SIZE);
av[ac++] = "-o";
av[ac++] = ttybuf;
}
/* tell the multiplexed backend to start on a certain port */
if (MultiplexedBackends)
{
sprintf(mbbuf, "-m %d", MultiplexedBackendPort);
av[ac++] = mbbuf;
}
/* Tell the backend the descriptor of the fe/be socket */
sprintf(portbuf, "-P%d", portFd);
sprintf(portbuf, "-P%d", port->sock);
av[ac++] = portbuf;
StrNCpy(argbuf, packet->options, ARGV_SIZE);
StrNCpy(argbuf, port->options, ARGV_SIZE);
strncat(argbuf, ExtraOptions, ARGV_SIZE);
argbuf[(2 * ARGV_SIZE)] = '\0';
split_opts(av, &ac, argbuf);
if (packet->database[0])
StrNCpy(dbbuf, packet->database, ARGV_SIZE);
else
StrNCpy(dbbuf, packet->user, NAMEDATALEN);
StrNCpy(dbbuf, port->database, ARGV_SIZE);
av[ac++] = dbbuf;
/* Tell the backend what protocol the frontend is using. */
sprintf(protobuf, "-v %u", port->proto);
av[ac++] = protobuf;
av[ac] = (char *) NULL;
if (DebugLvl > 1)
@@ -1375,10 +1213,7 @@ dumpstatus(SIGNAL_ARGS)
Port *port = DLE_VAL(curr);
fprintf(stderr, "%s: dumpstatus:\n", progname);
fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%lx, raddr=0x%lx\n",
port->sock, port->nBytes,
(long int) port->laddr.in.sin_addr.s_addr,
(long int) port->raddr.in.sin_addr.s_addr);
fprintf(stderr, "\tsock %d\n", port->sock);
curr = DLGetSucc(curr);
}
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.15 1997/12/06 22:57:02 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.16 1998/01/26 01:41:23 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,7 +29,7 @@
#include "postgres.h"
#include "access/htup.h"
#include "libpq/libpq-be.h"
#include "libpq/libpq.h"
#include "access/printtup.h"
#include "utils/portal.h"
#include "utils/palloc.h"

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.11 1998/01/11 21:16:01 scrappy Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.12 1998/01/26 01:41:28 scrappy Exp $
*
* NOTES
* This cruft is the server side of PQfn.
@@ -336,7 +336,7 @@ HandleFunctionRequest()
else
{ /* ... fixed */
/* XXX cross our fingers and trust "argsize" */
if (!(p = palloc(argsize)))
if (!(p = palloc(argsize + 1)))
{
elog(ERROR, "HandleFunctionRequest: palloc failed");
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.62 1998/01/25 05:14:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.63 1998/01/26 01:41:35 scrappy Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -47,8 +47,8 @@
#include "commands/async.h"
#include "executor/execdebug.h"
#include "executor/executor.h"
#include "lib/dllist.h"
#include "libpq/libpq.h"
#include "libpq/libpq-be.h"
#include "libpq/pqsignal.h"
#include "nodes/pg_list.h"
#include "nodes/print.h"
@@ -131,18 +131,6 @@ static int ShowPlannerStats;
int ShowExecutorStats;
FILE *StatFp;
typedef struct frontend
{
bool fn_connected;
Port fn_port;
FILE *fn_Pfin; /* the input fd */
FILE *fn_Pfout; /* the output fd */
bool fn_done; /* set after the frontend closes its
* connection */
} FrontEnd;
static Dllist *frontendList;
/* ----------------
* people who want to use EOF should #define DONTUSENEWLINE in
* tcop/tcopdebug.h
@@ -188,8 +176,8 @@ int _exec_repeat_ = 1;
* ----------------------------------------------------------------
*/
static char InteractiveBackend(char *inBuf);
static char SocketBackend(char *inBuf, bool multiplexedBackend);
static char ReadCommand(char *inBuf, bool multiplexedBackend);
static char SocketBackend(char *inBuf);
static char ReadCommand(char *inBuf);
/* ----------------------------------------------------------------
@@ -305,7 +293,7 @@ InteractiveBackend(char *inBuf)
*/
static char
SocketBackend(char *inBuf, bool multiplexedBackend)
SocketBackend(char *inBuf)
{
char qtype[2];
char result = '\0';
@@ -321,12 +309,7 @@ SocketBackend(char *inBuf, bool multiplexedBackend)
* when front-end applications quits/dies
* ------------
*/
if (multiplexedBackend)
{
return 'X';
}
else
exitpg(0);
exitpg(0);
}
switch (*qtype)
@@ -380,10 +363,10 @@ SocketBackend(char *inBuf, bool multiplexedBackend)
* ----------------
*/
static char
ReadCommand(char *inBuf, bool multiplexedBackend)
ReadCommand(char *inBuf)
{
if (IsUnderPostmaster || multiplexedBackend)
return SocketBackend(inBuf, multiplexedBackend);
if (IsUnderPostmaster)
return SocketBackend(inBuf);
else
return InteractiveBackend(inBuf);
}
@@ -793,7 +776,7 @@ static void
usage(char *progname)
{
fprintf(stderr,
"Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
"Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-v protocol] [\t -o filename]\n",
progname);
fprintf(stderr, "\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
fprintf(stderr, " b: consider bushy plan trees during optimization\n");
@@ -809,7 +792,6 @@ usage(char *progname)
fprintf(stderr, " K: set locking debug level [0|1|2]\n");
#endif
fprintf(stderr, " L: turn off locking\n");
fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
fprintf(stderr, " M: start as postmaster\n");
fprintf(stderr, " N: don't use newline as query delimiter\n");
fprintf(stderr, " o: send stdout and stderr to given filename \n");
@@ -820,6 +802,7 @@ usage(char *progname)
fprintf(stderr, " s: show stats after each query\n");
fprintf(stderr, " t: trace component execution times\n");
fprintf(stderr, " T: execute all possible plans for each query\n");
fprintf(stderr, " v: set protocol version being used by frontend\n");
fprintf(stderr, " x: control expensive function optimization\n");
}
@@ -845,24 +828,6 @@ PostgresMain(int argc, char *argv[])
char parser_input[MAX_PARSE_BUFFER];
char *userName;
bool multiplexedBackend;
char *hostName; /* the host name of the backend server */
int serverSock;
int serverPortnum = 0;
int nSelected; /* number of descriptors ready from
* select(); */
int maxFd = 0; /* max file descriptor + 1 */
fd_set rmask,
basemask;
FrontEnd *newFE,
*currentFE = NULL;
int numFE = 0; /* keep track of number of active
* frontends */
Port *newPort;
int newFd;
Dlelem *curr;
int status;
char *DBDate = NULL;
extern int optind;
extern char *optarg;
@@ -906,7 +871,6 @@ PostgresMain(int argc, char *argv[])
* get hostname is either the environment variable PGHOST or NULL
* NULL means Unix-socket only
*/
hostName = getenv("PGHOST");
DataDir = getenv("PGDATA");
/*
* Try to get initial values for date styles and formats.
@@ -933,9 +897,8 @@ PostgresMain(int argc, char *argv[])
else if (strcasecmp(DBDate, "EURO") == 0)
EuroDates = TRUE;
}
multiplexedBackend = false;
while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQS:st:x:F"))
while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQS:st:v:x:F"))
!= EOF)
switch (flag)
{
@@ -1051,16 +1014,7 @@ PostgresMain(int argc, char *argv[])
break;
case 'm':
/*
* start up a listening backend that can respond to
* multiple front-ends. (Note: all the front-end
* connections are still connected to a single-threaded
* backend. Requests are FCFS. Everything is in one
* transaction
*/
multiplexedBackend = true;
serverPortnum = atoi(optarg);
/* Multiplexed backends are no longer supported. */
break;
case 'M':
exit(PostmasterMain(argc, argv));
@@ -1162,6 +1116,10 @@ PostgresMain(int argc, char *argv[])
}
break;
case 'v':
FrontendProtocol = (ProtocolVersion)atoi(optarg);
break;
case 'x':
#if 0 /* planner/xfunc.h */
@@ -1267,7 +1225,6 @@ PostgresMain(int argc, char *argv[])
printf("\tsortmem = %d\n", SortMem);
printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
printf("\tDatabaseName = [%s]\n", DBName);
puts("\t----------------\n");
}
@@ -1285,53 +1242,8 @@ PostgresMain(int argc, char *argv[])
Portfd = open(NULL_DEV, O_RDWR, 0666);
}
pq_init(Portfd);
}
if (multiplexedBackend)
{
if (serverPortnum == 0 ||
StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
{
fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
exit(1);
}
/*
{
char buf[100];
sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
puts(buf);
}
*/
FD_ZERO(&rmask);
FD_ZERO(&basemask);
FD_SET(serverSock, &basemask);
frontendList = DLNewList();
/* add the original FrontEnd to the list */
if (IsUnderPostmaster == true)
{
FrontEnd *fe = malloc(sizeof(FrontEnd));
FD_SET(Portfd, &basemask);
maxFd = Max(serverSock, Portfd) + 1;
fe->fn_connected = true;
fe->fn_Pfin = Pfin;
fe->fn_Pfout = Pfout;
fe->fn_done = false;
(fe->fn_port).sock = Portfd;
DLAddHead(frontendList, DLNewElem(fe));
numFE++;
}
else
{
numFE = 1;
maxFd = serverSock + 1;
}
}
if (IsUnderPostmaster || multiplexedBackend)
whereToSendOutput = Remote;
}
else
whereToSendOutput = Debug;
@@ -1381,7 +1293,7 @@ PostgresMain(int argc, char *argv[])
if (IsUnderPostmaster == false)
{
puts("\nPOSTGRES backend interactive interface");
puts("$Revision: 1.62 $ $Date: 1998/01/25 05:14:18 $");
puts("$Revision: 1.63 $ $Date: 1998/01/26 01:41:35 $");
}
/* ----------------
@@ -1395,106 +1307,13 @@ PostgresMain(int argc, char *argv[])
for (;;)
{
if (multiplexedBackend)
{
if (numFE == 0)
break;
memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
nSelected = select(maxFd, &rmask, 0, 0, 0);
if (nSelected < 0)
{
if (errno == EINTR)
continue;
fprintf(stderr, "postgres: multiplexed backend select failed\n");
exitpg(1);
}
if (FD_ISSET(serverSock, &rmask))
{
/* new connection pending on our well-known port's socket */
newFE = (FrontEnd *) malloc(sizeof(FrontEnd));
MemSet(newFE, 0, sizeof(FrontEnd));
newFE->fn_connected = false;
newFE->fn_done = false;
newPort = &(newFE->fn_port);
if (StreamConnection(serverSock, newPort) != STATUS_OK)
{
StreamClose(newPort->sock);
newFd = -1;
}
else
{
DLAddHead(frontendList, DLNewElem(newFE));
numFE++;
newFd = newPort->sock;
if (newFd >= maxFd)
maxFd = newFd + 1;
FD_SET(newFd, &rmask);
FD_SET(newFd, &basemask);
--nSelected;
FD_CLR(serverSock, &rmask);
}
continue;
} /* if FD_ISSET(serverSock) */
/*
* if we get here, it means that the serverSocket was not the
* one selected. Instead, one of the front ends was selected.
* find which one
*/
curr = DLGetHead(frontendList);
while (curr)
{
FrontEnd *fe = (FrontEnd *) DLE_VAL(curr);
Port *port = &(fe->fn_port);
/* this is lifted from postmaster.c */
if (FD_ISSET(port->sock, &rmask))
{
if (fe->fn_connected == false)
{
/* we have a message from a new frontEnd */
status = PacketReceive(port, &port->buf, NON_BLOCKING);
if (status == STATUS_OK)
{
fe->fn_connected = true;
pq_init(port->sock);
fe->fn_Pfin = Pfin;
fe->fn_Pfout = Pfout;
}
else
fprintf(stderr, "Multiplexed backend: error in reading packets from %d\n", port->sock);
}
else
/* we have a query from an existing, active FrontEnd */
{
Pfin = fe->fn_Pfin;
Pfout = fe->fn_Pfout;
currentFE = fe;
}
if (fe->fn_done)
{
Dlelem *c = curr;
curr = DLGetSucc(curr);
DLRemove(c);
}
break;
}
else
curr = DLGetSucc(curr);
}
}
/* ----------------
* (1) read a command.
* ----------------
*/
MemSet(parser_input, 0, MAX_PARSE_BUFFER);
firstchar = ReadCommand(parser_input, multiplexedBackend);
firstchar = ReadCommand(parser_input);
/* process the command */
switch (firstchar)
{
@@ -1564,12 +1383,6 @@ PostgresMain(int argc, char *argv[])
*/
case 'X':
IsEmptyQuery = true;
if (multiplexedBackend)
{
FD_CLR(currentFE->fn_port.sock, &basemask);
currentFE->fn_done = true;
numFE--;
}
pq_close();
break;
@@ -1596,7 +1409,7 @@ PostgresMain(int argc, char *argv[])
}
else
{
if (IsUnderPostmaster || multiplexedBackend)
if (IsUnderPostmaster)
NullCommand(Remote);
}

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.18 1998/01/25 05:14:42 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.19 1998/01/26 01:41:42 scrappy Exp $
*
* NOTES
* Globals used all over the place should be declared here and not
@@ -32,9 +32,10 @@
#include "storage/sinvaladt.h"
#include "storage/lmgr.h"
#include "utils/elog.h"
#include "libpq/pqcomm.h"
#include "catalog/catname.h"
ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST;
int Portfd = -1;
int Noversion = 0;
int Quiet = 1;