Commit 9b4bfbdc authored by Peter Eisentraut's avatar Peter Eisentraut

Handle reading of startup packet and authentication exchange after forking

a new postmaster child process.  This should eliminate problems with
authentication blocking (e.g., ident, SSL init) and also reduce problems
with the accept queue filling up under heavy load.

The option to send elog output to a different file per backend (postgres -o)
has been disabled for now because the initialization would have to happen
in a different order and it's not clear we want to keep this anyway.
parent 588463a4
......@@ -8,48 +8,34 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.52 2001/03/22 03:59:30 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.53 2001/06/20 18:07:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
*
* backend (postmaster) routines:
* be_recvauth receive authentication information
*/
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifndef MAXHOSTNAMELEN
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
#include <pwd.h>
#include <ctype.h>
#include "postgres.h"
#include <sys/types.h> /* needed by in.h on Ultrix */
#include <netinet/in.h>
#include <arpa/inet.h>
#include "postgres.h"
#include "libpq/auth.h"
#include "libpq/crypt.h"
#include "libpq/hba.h"
#include "libpq/libpq.h"
#include "libpq/password.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
static void sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler);
static int handle_done_auth(void *arg, PacketLen len, void *pkt);
static int handle_krb4_auth(void *arg, PacketLen len, void *pkt);
static int handle_krb5_auth(void *arg, PacketLen len, void *pkt);
static int handle_password_auth(void *arg, PacketLen len, void *pkt);
static int readPasswordPacket(void *arg, PacketLen len, void *pkt);
static int pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt);
static void sendAuthRequest(Port *port, AuthRequest areq);
static int checkPassword(Port *port, char *user, char *password);
static int old_be_recvauth(Port *port);
static int map_old_to_new(Port *port, UserAuth old, int status);
static void auth_failed(Port *port);
static int recv_and_check_password_packet(Port *port);
static int recv_and_check_passwordv0(Port *port);
char *pg_krb_server_keyfile;
......@@ -325,25 +311,28 @@ pg_krb5_recvauth(Port *port)
/*
* Handle a v0 password packet.
*/
static int
pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
recv_and_check_passwordv0(Port *port)
{
Port *port;
int32 len;
char *buf;
PasswordPacketV0 *pp;
char *user,
*password,
*cp,
*start;
port = (Port *) arg;
pp = (PasswordPacketV0 *) pkt;
pq_getint(&len, 4);
len -= 4;
buf = palloc(len);
pq_getbytes(buf, len);
pp = (PasswordPacketV0 *) buf;
/*
* 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);
......@@ -371,6 +360,7 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
pfree(buf);
auth_failed(port);
}
else
......@@ -385,15 +375,15 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
status = checkPassword(port, user, password);
pfree(buf);
port->auth_method = saved;
/* Adjust the result if necessary. */
if (map_old_to_new(port, uaPassword, status) != STATUS_OK)
auth_failed(port);
}
return STATUS_OK; /* don't close the connection yet */
return STATUS_OK;
}
......@@ -413,7 +403,6 @@ pg_passwordv0_recvauth(void *arg, PacketLen len, void *pkt)
static void
auth_failed(Port *port)
{
char buffer[512];
const char *authmethod = "Unknown auth method:";
switch (port->auth_method)
......@@ -441,19 +430,20 @@ auth_failed(Port *port)
break;
}
sprintf(buffer, "%s authentication failed for user '%s'",
authmethod, port->user);
PacketSendError(&port->pktInfo, buffer);
elog(FATAL, "%s authentication failed for user \"%s\"",
authmethod, port->user);
}
/*
* be_recvauth -- server demux routine for incoming authentication information
* Client authentication starts here. If there is an error, this
* function does not return and the backend process is terminated.
*/
void
be_recvauth(Port *port)
ClientAuthentication(Port *port)
{
int status = STATUS_ERROR;
/*
* Get the authentication method to use for this frontend/database
......@@ -463,97 +453,77 @@ be_recvauth(Port *port)
*/
if (hba_getauthmethod(port) != STATUS_OK)
PacketSendError(&port->pktInfo,
"Missing or erroneous pg_hba.conf file, see postmaster log for details");
elog(FATAL, "Missing or erroneous pg_hba.conf file, see postmaster log for details");
/* Handle old style authentication. */
else if (PG_PROTOCOL_MAJOR(port->proto) == 0)
{
/* Handle old style authentication. */
if (old_be_recvauth(port) != STATUS_OK)
auth_failed(port);
return;
}
else
{
/* Handle new style authentication. */
AuthRequest areq = AUTH_REQ_OK;
PacketDoneProc auth_handler = NULL;
switch (port->auth_method)
{
case uaReject:
/*
* This could have come from an explicit "reject" entry in
* pg_hba.conf, but more likely it means there was no
* matching entry. Take pity on the poor user and issue a
* helpful error message. NOTE: this is not a security
* breach, because all the info reported here is known at
* the frontend and must be assumed known to bad guys.
* We're merely helping out the less clueful good guys.
* NOTE 2: libpq-be.h defines the maximum error message
* length as 99 characters. It probably wouldn't hurt
* anything to increase it, but there might be some client
* out there that will fail. So, be terse.
*/
{
char buffer[512];
const char *hostinfo = "localhost";
if (port->raddr.sa.sa_family == AF_INET)
hostinfo = inet_ntoa(port->raddr.in.sin_addr);
sprintf(buffer,
"No pg_hba.conf entry for host %s, user %s, database %s",
hostinfo, port->user, port->database);
PacketSendError(&port->pktInfo, buffer);
return;
}
break;
case uaKrb4:
areq = AUTH_REQ_KRB4;
auth_handler = handle_krb4_auth;
break;
/* Handle new style authentication. */
case uaKrb5:
areq = AUTH_REQ_KRB5;
auth_handler = handle_krb5_auth;
break;
switch (port->auth_method)
{
case uaReject:
case uaTrust:
areq = AUTH_REQ_OK;
auth_handler = handle_done_auth;
break;
/*
* This could have come from an explicit "reject" entry in
* pg_hba.conf, but more likely it means there was no
* matching entry. Take pity on the poor user and issue a
* helpful error message. NOTE: this is not a security
* breach, because all the info reported here is known at
* the frontend and must be assumed known to bad guys.
* We're merely helping out the less clueful good guys.
*/
{
const char *hostinfo = "localhost";
if (port->raddr.sa.sa_family == AF_INET)
hostinfo = inet_ntoa(port->raddr.in.sin_addr);
elog(FATAL,
"No pg_hba.conf entry for host %s, user %s, database %s",
hostinfo, port->user, port->database);
return;
}
break;
case uaIdent:
if (authident(&port->raddr.in, &port->laddr.in,
port->user, port->auth_arg) == STATUS_OK)
{
areq = AUTH_REQ_OK;
auth_handler = handle_done_auth;
}
case uaKrb4:
sendAuthRequest(port, AUTH_REQ_KRB4);
status = pg_krb4_recvauth(port);
break;
break;
case uaKrb5:
sendAuthRequest(port, AUTH_REQ_KRB5);
status = pg_krb5_recvauth(port);
break;
case uaPassword:
areq = AUTH_REQ_PASSWORD;
auth_handler = handle_password_auth;
break;
case uaIdent:
status = authident(&port->raddr.in, &port->laddr.in,
port->user, port->auth_arg);
break;
case uaCrypt:
areq = AUTH_REQ_CRYPT;
auth_handler = handle_password_auth;
break;
}
case uaPassword:
sendAuthRequest(port, AUTH_REQ_PASSWORD);
status = recv_and_check_password_packet(port);
break;
/* Tell the frontend what we want next. */
case uaCrypt:
sendAuthRequest(port, AUTH_REQ_CRYPT);
status = recv_and_check_password_packet(port);
break;
if (auth_handler != NULL)
sendAuthRequest(port, areq, auth_handler);
else
auth_failed(port);
case uaTrust:
status = STATUS_OK;
break;
}
if (status == STATUS_OK)
sendAuthRequest(port, AUTH_REQ_OK);
else
auth_failed(port);
}
......@@ -562,134 +532,50 @@ be_recvauth(Port *port)
*/
static void
sendAuthRequest(Port *port, AuthRequest areq, PacketDoneProc handler)
sendAuthRequest(Port *port, AuthRequest areq)
{
char *dp,
*sp;
int i;
uint32 net_areq;
StringInfoData buf;
/* 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++;
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'R');
pq_sendint(&buf, (int32) areq, sizeof(int32));
/* Add the salt for encrypted passwords. */
if (areq == AUTH_REQ_CRYPT)
{
*dp++ = port->salt[0];
*dp++ = port->salt[1];
i += 2;
pq_sendint(&buf, port->salt[0], 1);
pq_sendint(&buf, port->salt[1], 1);
}
PacketSendSetup(&port->pktInfo, i, handler, (void *) port);
}
/*
* Called when we have told the front end that it is authorised.
*/
static int
handle_done_auth(void *arg, PacketLen len, void *pkt)
{
/*
* Don't generate any more traffic. This will cause the backend to
* start.
*/
return STATUS_OK;
}
/*
* Called when we have told the front end that it should use Kerberos V4
* authentication.
*/
static int
handle_krb4_auth(void *arg, PacketLen len, void *pkt)
{
Port *port = (Port *) arg;
if (pg_krb4_recvauth(port) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
return STATUS_OK;
}
/*
* Called when we have told the front end that it should use Kerberos V5
* authentication.
*/
static int
handle_krb5_auth(void *arg, PacketLen len, void *pkt)
{
Port *port = (Port *) arg;
if (pg_krb5_recvauth(port) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
return STATUS_OK;
pq_endmessage(&buf);
pq_flush();
}
/*
* Called when we have told the front end that it should use password
* authentication.
*/
static int
handle_password_auth(void *arg, PacketLen len, void *pkt)
{
Port *port = (Port *) arg;
/* Set up the read of the password packet. */
PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (void *) port);
return STATUS_OK;
}
/*
* Called when we have received the password packet.
*/
static int
readPasswordPacket(void *arg, PacketLen len, void *pkt)
recv_and_check_password_packet(Port *port)
{
char password[sizeof(PasswordPacket) + 1];
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);
if (checkPassword(port, port->user, password) != STATUS_OK)
auth_failed(port);
else
sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
return STATUS_OK; /* don't close the connection yet */
StringInfoData buf;
int32 len;
int result;
if (pq_getint(&len, 4) == EOF)
return STATUS_ERROR; /* client didn't want to send password */
initStringInfo(&buf);
pq_getstr(&buf);
if (DebugLvl)
fprintf(stderr, "received password packet with len=%d, pw=%s\n",
len, buf.data);
result = checkPassword(port, port->user, buf.data);
pfree(buf.data);
return result;
}
......@@ -734,10 +620,8 @@ old_be_recvauth(Port *port)
break;
case STARTUP_PASSWORD_MSG:
PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
(void *) port);
return STATUS_OK;
status = recv_and_check_passwordv0(port);
break;
default:
fprintf(stderr, "Invalid startup message type: %u\n", msgtype);
......@@ -760,8 +644,8 @@ map_old_to_new(Port *port, UserAuth old, int status)
{
switch (port->auth_method)
{
case uaCrypt:
case uaReject:
case uaCrypt:
case uaReject:
status = STATUS_ERROR;
break;
......
......@@ -28,7 +28,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.223 2001/06/19 23:40:10 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.224 2001/06/20 18:07:55 petere Exp $
*
* NOTES
*
......@@ -116,16 +116,13 @@ int UnBlockSig,
*/
typedef struct bkend
{
int pid; /* process id of backend */
pid_t pid; /* process id of backend */
long cancel_key; /* cancel key for cancels for this backend */
} Backend;
/* list of active backends. For garbage collection only now. */
static Dllist *BackendList;
/* list of ports associated with still open, but incomplete connections */
static Dllist *PortList;
/* The socket number we are listening for connections on */
int PostPortNumber;
char *UnixSocketDir;
......@@ -221,21 +218,20 @@ extern int optreset;
static void pmdaemonize(int argc, char *argv[]);
static Port *ConnCreate(int serverFd);
static void ConnFree(Port *port);
static void ClosePostmasterPorts(Port *myConn);
static void ClosePostmasterPorts(void);
static void reset_shared(unsigned short port);
static void SIGHUP_handler(SIGNAL_ARGS);
static void pmdie(SIGNAL_ARGS);
static void reaper(SIGNAL_ARGS);
static void schedule_checkpoint(SIGNAL_ARGS);
static void dumpstatus(SIGNAL_ARGS);
static void CleanupProc(int pid, int exitstatus);
static int DoBackend(Port *port);
static void ExitPostmaster(int status);
static void usage(const char *);
static int ServerLoop(void);
static int BackendStartup(Port *port);
static int readStartupPacket(void *arg, PacketLen len, void *pkt);
static int processCancelRequest(Port *port, PacketLen len, void *pkt);
static int ProcessStartupPacket(Port *port);
static void processCancelRequest(Port *port, void *pkt);
static int initMasks(fd_set *rmask, fd_set *wmask);
static char *canAcceptConnections(void);
static long PostmasterRandom(void);
......@@ -661,7 +657,6 @@ PostmasterMain(int argc, char *argv[])
* garbage collecting the backend processes.
*/
BackendList = DLNewList();
PortList = DLNewList();
/*
* Record postmaster options. We delay this till now to avoid
......@@ -690,7 +685,6 @@ PostmasterMain(int argc, char *argv[])
pqsignal(SIGCHLD, reaper); /* handle child termination */
pqsignal(SIGTTIN, SIG_IGN); /* ignored */
pqsignal(SIGTTOU, SIG_IGN); /* ignored */
pqsignal(SIGWINCH, dumpstatus); /* dump port status */
/*
* We're ready to rock and roll...
......@@ -794,7 +788,6 @@ ServerLoop(void)
fd_set readmask,
writemask;
int nSockets;
Dlelem *curr;
struct timeval now,
later;
struct timezone tz;
......@@ -841,27 +834,6 @@ ServerLoop(void)
}
}
#ifdef USE_SSL
/*
* If we are using SSL, there may be input data already read and
* pending in SSL's input buffers. If so, check for additional
* input from other clients, but don't delay before processing.
*/
for (curr = DLGetHead(PortList); curr; curr = DLGetSucc(curr))
{
Port *port = (Port *) DLE_VAL(curr);
if (port->ssl && SSL_pending(port->ssl))
{
timeout_tv.tv_sec = 0;
timeout_tv.tv_usec = 0;
timeout = &timeout_tv;
break;
}
}
#endif
/*
* Wait for something to happen.
*/
......@@ -915,126 +887,26 @@ ServerLoop(void)
*/
#ifdef HAVE_UNIX_SOCKETS
if (ServerSock_UNIX != INVALID_SOCK &&
FD_ISSET(ServerSock_UNIX, &rmask) &&
(port = ConnCreate(ServerSock_UNIX)) != NULL)
if (ServerSock_UNIX != INVALID_SOCK
&& FD_ISSET(ServerSock_UNIX, &rmask))
{
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(void *) port);
port = ConnCreate(ServerSock_UNIX);
if (port)
BackendStartup(port);
StreamClose(port->sock);
ConnFree(port);
}
#endif
if (ServerSock_INET != INVALID_SOCK &&
FD_ISSET(ServerSock_INET, &rmask) &&
(port = ConnCreate(ServerSock_INET)) != NULL)
if (ServerSock_INET != INVALID_SOCK
&& FD_ISSET(ServerSock_INET, &rmask))
{
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(void *) port);
port = ConnCreate(ServerSock_INET);
if (port)
BackendStartup(port);
StreamClose(port->sock);
ConnFree(port);
}
/*
* Scan active ports, processing any available input. While we
* are at it, build up new masks for next select().
*/
nSockets = initMasks(&readmask, &writemask);
curr = DLGetHead(PortList);
while (curr)
{
Port *port = (Port *) DLE_VAL(curr);
int status = STATUS_OK;
Dlelem *next;
if (FD_ISSET(port->sock, &rmask)
#ifdef USE_SSL
|| (port->ssl && SSL_pending(port->ssl))
#endif
)
{
if (DebugLvl > 1)
postmaster_error("ServerLoop: handling reading %d", port->sock);
if (PacketReceiveFragment(port) != STATUS_OK)
status = STATUS_ERROR;
}
if (FD_ISSET(port->sock, &wmask))
{
if (DebugLvl > 1)
postmaster_error("ServerLoop: handling writing %d", port->sock);
if (PacketSendFragment(port) != 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)
{
/*
* Can we accept a connection now?
*
* Even though readStartupPacket() already checked, we have
* to check again in case conditions changed while
* negotiating authentication.
*/
char *rejectMsg = canAcceptConnections();
if (rejectMsg != NULL)
PacketSendError(&port->pktInfo, rejectMsg);
else
{
/*
* If the backend start fails then keep the connection
* open to report it. Otherwise, pretend there is an
* error to close our descriptor for the connection,
* which will now be managed by the backend.
*/
if (BackendStartup(port) != STATUS_OK)
PacketSendError(&port->pktInfo,
"Backend startup failed");
else
status = STATUS_ERROR;
}
}
/* Close the connection if required. */
if (status != STATUS_OK)
{
StreamClose(port->sock);
DLRemove(curr);
ConnFree(port);
DLFreeElem(curr);
}
else
{
/* 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;
} /* loop over active ports */
}
}
......@@ -1074,28 +946,42 @@ initMasks(fd_set *rmask, fd_set *wmask)
/*
* Called when the startup packet has been read.
* Read the startup packet and do something according to it.
*
* Returns STATUS_OK or STATUS_ERROR, or might call elog(FATAL) and
* not return at all.
*/
static int
readStartupPacket(void *arg, PacketLen len, void *pkt)
ProcessStartupPacket(Port *port)
{
Port *port;
StartupPacket *si;
StartupPacket *packet;
char *rejectMsg;
int32 len;
void *buf;
port = (Port *) arg;
si = (StartupPacket *) pkt;
pq_getbytes((char *)&len, 4);
len = ntohl(len);
len -= 4;
if (len < sizeof(len) || len > sizeof(len) + sizeof(StartupPacket))
elog(FATAL, "invalid length of startup packet");
buf = palloc(len);
pq_getbytes(buf, len);
packet = buf;
/*
* The first field is either a protocol version number or a special
* request code.
*/
port->proto = ntohl(si->protoVersion);
port->proto = ntohl(packet->protoVersion);
if (port->proto == CANCEL_REQUEST_CODE)
return processCancelRequest(port, len, pkt);
{
processCancelRequest(port, packet);
return 127; /* XXX */
}
if (port->proto == NEGOTIATE_SSL_CODE)
{
......@@ -1114,7 +1000,7 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
{
postmaster_error("failed to send SSL negotiation response: %s",
strerror(errno));
return STATUS_ERROR;/* Close connection */
return STATUS_ERROR; /* close the connection */
}
#ifdef USE_SSL
......@@ -1130,11 +1016,10 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
}
}
#endif
/* ready for the normal startup packet */
PacketReceiveSetup(&port->pktInfo,
readStartupPacket,
(void *) port);
return STATUS_OK; /* Do not close connection */
/* regular startup packet should follow... */
/* FIXME: by continuing to send SSL negotiation packets, a
client could run us out of stack space */
return ProcessStartupPacket(port);
}
/* Could add additional special packet types here */
......@@ -1146,46 +1031,35 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
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 STATUS_OK; /* don't close the connection yet */
}
elog(FATAL, "unsupported frontend protocol");
/*
* Get the parameters from the startup packet as C strings. The
* packet destination was cleared first so a short packet has zeros
* silently added and a long packet is silently truncated.
*/
StrNCpy(port->database, si->database, sizeof(port->database));
StrNCpy(port->user, si->user, sizeof(port->user));
StrNCpy(port->options, si->options, sizeof(port->options));
StrNCpy(port->tty, si->tty, sizeof(port->tty));
StrNCpy(port->database, packet->database, sizeof(port->database));
StrNCpy(port->user, packet->user, sizeof(port->user));
StrNCpy(port->options, packet->options, sizeof(port->options));
StrNCpy(port->tty, packet->tty, sizeof(port->tty));
/* The database defaults to the user name. */
if (port->database[0] == '\0')
StrNCpy(port->database, si->user, sizeof(port->database));
StrNCpy(port->database, packet->user, sizeof(port->database));
/*
* Truncate given database and user names to length of a Postgres
* name.
* name. This avoids lookup failures when overlength names are
* given.
*/
/* This avoids lookup failures when overlength names are given. */
if ((int) sizeof(port->database) >= NAMEDATALEN)
port->database[NAMEDATALEN - 1] = '\0';
if ((int) sizeof(port->user) >= NAMEDATALEN)
port->user[NAMEDATALEN - 1] = '\0';
/* Check a user name was given. */
if (port->user[0] == '\0')
{
PacketSendError(&port->pktInfo,
"No Postgres username specified in startup packet.");
return STATUS_OK; /* don't close the connection yet */
}
elog(FATAL, "no PostgreSQL user name specified in startup packet");
/*
* If we're going to reject the connection due to database state, say
......@@ -1195,27 +1069,19 @@ readStartupPacket(void *arg, PacketLen len, void *pkt)
rejectMsg = canAcceptConnections();
if (rejectMsg != NULL)
{
PacketSendError(&port->pktInfo, rejectMsg);
return STATUS_OK; /* don't close the connection yet */
}
elog(FATAL, "%s", rejectMsg);
/* Start the authentication itself. */
be_recvauth(port);
return STATUS_OK; /* don't close the connection yet */
return STATUS_OK;
}
/*
* The client has sent a cancel request packet, not a normal
* start-a-new-backend packet. Perform the necessary processing.
* Note that in any case, we return STATUS_ERROR to close the
* connection immediately. Nothing is sent back to the client.
* start-a-new-connection packet. Perform the necessary processing.
* Nothing is sent back to the client.
*/
static int
processCancelRequest(Port *port, PacketLen len, void *pkt)
static void
processCancelRequest(Port *port, void *pkt)
{
CancelRequestPacket *canc = (CancelRequestPacket *) pkt;
int backendPID;
......@@ -1230,7 +1096,7 @@ processCancelRequest(Port *port, PacketLen len, void *pkt)
{
if (DebugLvl)
postmaster_error("processCancelRequest: CheckPointPID in cancel request for process %d", backendPID);
return STATUS_ERROR;
return;
}
/* See if we have a matching backend */
......@@ -1244,24 +1110,24 @@ processCancelRequest(Port *port, PacketLen len, void *pkt)
{
/* Found a match; signal that backend to cancel current op */
if (DebugLvl)
postmaster_error("processCancelRequest: sending SIGINT to process %d", bp->pid);
elog(DEBUG, "processing cancel request: sending SIGINT to process %d",
backendPID);
kill(bp->pid, SIGINT);
}
else
{
/* Right PID, wrong key: no way, Jose */
if (DebugLvl)
postmaster_error("processCancelRequest: bad key in cancel request for process %d", bp->pid);
elog(DEBUG, "bad key in cancel request for process %d",
backendPID);
}
return STATUS_ERROR;
return;
}
}
/* No matching backend */
if (DebugLvl)
postmaster_error("processCancelRequest: bad PID in cancel request for process %d", backendPID);
return STATUS_ERROR;
elog(DEBUG, "bad pid in cancel request for process %d", backendPID);
}
/*
......@@ -1295,6 +1161,7 @@ canAcceptConnections(void)
return NULL;
}
/*
* ConnCreate -- create a local connection data structure
*/
......@@ -1318,7 +1185,6 @@ ConnCreate(int serverFd)
}
else
{
DLAddHead(PortList, DLNewElem(port));
RandomSalt(port->salt);
port->pktInfo.state = Idle;
}
......@@ -1326,6 +1192,7 @@ ConnCreate(int serverFd)
return port;
}
/*
* ConnFree -- free a local connection data structure
*/
......@@ -1339,22 +1206,20 @@ ConnFree(Port *conn)
free(conn);
}
/*
* ClosePostmasterPorts -- close all the postmaster's open sockets
*
* This is called during child process startup to release file descriptors
* that are not needed by that child process. All descriptors other than
* the one for myConn (if it's not null) are closed.
* that are not needed by that child process.
*
* Note that closing the child's descriptor does not destroy the client
* connection prematurely, since the parent (postmaster) process still
* has the socket open.
*/
static void
ClosePostmasterPorts(Port *myConn)
ClosePostmasterPorts(void)
{
Dlelem *curr;
/* Close the listen sockets */
if (NetServer)
StreamClose(ServerSock_INET);
......@@ -1363,25 +1228,6 @@ ClosePostmasterPorts(Port *myConn)
StreamClose(ServerSock_UNIX);
ServerSock_UNIX = INVALID_SOCK;
#endif
/* Close any sockets for other clients, and release memory too */
curr = DLGetHead(PortList);
while (curr)
{
Port *port = (Port *) DLE_VAL(curr);
Dlelem *next = DLGetSucc(curr);
if (port != myConn)
{
StreamClose(port->sock);
DLRemove(curr);
ConnFree(port);
DLFreeElem(curr);
}
curr = next;
}
}
......@@ -1847,7 +1693,7 @@ static int
BackendStartup(Port *port)
{
Backend *bn; /* for backend cleanup */
int pid;
pid_t pid;
/*
* Compute the cancel key that will be assigned to this backend. The
......@@ -1872,42 +1718,45 @@ BackendStartup(Port *port)
beos_before_backend_startup();
#endif
if ((pid = fork()) == 0)
{ /* child */
/*
* Make room for backend data structure. Better before the fork()
* so we can handle failure cleanly.
*/
bn = (Backend *) malloc(sizeof(Backend));
if (!bn)
{
fprintf(stderr, gettext("%s: BackendStartup: malloc failed\n"),
progname);
return STATUS_ERROR;
}
pid = fork();
if (pid == 0) /* child */
{
int status;
free(bn);
#ifdef __BEOS__
/* Specific beos backend startup actions */
beos_backend_startup();
#endif
#ifdef CYR_RECODE
{
/* Save charset for this host while we still have client addr */
char ChTable[80];
static char cyrEnvironment[100];
GetCharSetByHost(ChTable, port->raddr.in.sin_addr.s_addr, DataDir);
if (*ChTable != '\0')
{
snprintf(cyrEnvironment, sizeof(cyrEnvironment),
"PG_RECODETABLE=%s", ChTable);
putenv(cyrEnvironment);
}
}
#endif
if (DoBackend(port))
status = DoBackend(port);
if (status != 0)
{
fprintf(stderr, gettext("%s child[%d]: BackendStartup: backend startup failed\n"),
progname, (int) getpid());
ExitPostmaster(1);
proc_exit(status);
}
else
ExitPostmaster(0);
proc_exit(0);
}
/* in parent */
/* in parent, error */
if (pid < 0)
{
free(bn);
#ifdef __BEOS__
/* Specific beos backend startup actions */
beos_backend_startup_failed();
......@@ -1917,8 +1766,9 @@ BackendStartup(Port *port)
return STATUS_ERROR;
}
if (DebugLvl)
fprintf(stderr, gettext("%s: BackendStartup: pid %d user %s db %s socket %d\n"),
/* in parent, normal */
if (DebugLvl >= 1)
fprintf(stderr, gettext("%s: BackendStartup: pid=%d user=%s db=%s socket=%d\n"),
progname, pid, port->user, port->database,
port->sock);
......@@ -1926,13 +1776,6 @@ BackendStartup(Port *port)
* Everything's been successful, it's safe to add this backend to our
* list of backends.
*/
if (!(bn = (Backend *) calloc(1, sizeof(Backend))))
{
fprintf(stderr, gettext("%s: BackendStartup: malloc failed\n"),
progname);
ExitPostmaster(1);
}
bn->pid = pid;
bn->cancel_key = MyCancelKey;
DLAddHead(BackendList, DLNewElem(bn));
......@@ -1940,6 +1783,7 @@ BackendStartup(Port *port)
return STATUS_OK;
}
/*
* split_opts -- split a string of options and append it to an argv array
*
......@@ -1990,6 +1834,7 @@ DoBackend(Port *port)
char optbuf[ARGV_SIZE];
char ttybuf[ARGV_SIZE];
int i;
int status;
struct timeval now;
struct timezone tz;
......@@ -2004,14 +1849,22 @@ DoBackend(Port *port)
* Signal handlers setting is moved to tcop/postgres...
*/
SetProcessingMode(InitProcessing);
/* Save port etc. for ps status */
MyProcPort = port;
/* Reset MyProcPid to new backend's pid */
MyProcPid = getpid();
whereToSendOutput = Remote;
status = ProcessStartupPacket(port);
if (status == 127)
return 0; /* cancel request processed */
/* Close the postmaster's other sockets */
ClosePostmasterPorts(port);
ClosePostmasterPorts();
/*
* Don't want backend to be able to see the postmaster random number
......@@ -2162,26 +2015,6 @@ schedule_checkpoint(SIGNAL_ARGS)
errno = save_errno;
}
static void
dumpstatus(SIGNAL_ARGS)
{
int save_errno = errno;
Dlelem *curr;
PG_SETMASK(&BlockSig);
fprintf(stderr, "%s: dumpstatus:\n", progname);
curr = DLGetHead(PortList);
while (curr)
{
Port *port = DLE_VAL(curr);
fprintf(stderr, "\tsock %d\n", port->sock);
curr = DLGetSucc(curr);
}
errno = save_errno;
}
/*
* CharRemap
......@@ -2336,7 +2169,7 @@ SSDataBase(int xlop)
on_exit_reset();
/* Close the postmaster's sockets */
ClosePostmasterPorts(NULL);
ClosePostmasterPorts();
/* Set up command-line arguments for subprocess */
av[ac++] = "postgres";
......@@ -2463,7 +2296,7 @@ postmaster_error(const char *fmt, ...)
fprintf(stderr, "%s: ", progname);
va_start(ap, fmt);
fprintf(stderr, gettext(fmt), ap);
vfprintf(stderr, gettext(fmt), ap);
va_end(ap);
fprintf(stderr, "\n");
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.222 2001/06/19 23:40:10 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.223 2001/06/20 18:07:55 petere Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
......@@ -45,6 +45,7 @@
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "libpq/auth.h"
#include "nodes/print.h"
#include "optimizer/cost.h"
#include "optimizer/planner.h"
......@@ -1142,11 +1143,13 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
*/
if (!IsUnderPostmaster)
{
SetProcessingMode(InitProcessing);
EnableExceptionHandling(true);
MemoryContextInit();
}
SetProcessingMode(InitProcessing);
if (IsUnderPostmaster)
ClientAuthentication(MyProcPort); /* might not return */
/*
* Set default values for command-line options.
......@@ -1567,13 +1570,11 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
* restart... */
}
pq_init(); /* initialize libpq at backend startup */
whereToSendOutput = Remote;
BaseInit();
}
else
{
/* interactive case: database name can be last arg on command line */
whereToSendOutput = Debug;
if (errs || argc - optind > 1)
{
fprintf(stderr, "%s: invalid command line arguments\nTry -? for help.\n", argv[0]);
......@@ -1709,7 +1710,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.222 $ $Date: 2001/06/19 23:40:10 $\n");
puts("$Revision: 1.223 $ $Date: 2001/06/20 18:07:55 $\n");
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.86 2001/06/08 21:16:48 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.87 2001/06/20 18:07:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -129,10 +129,6 @@ elog(int lev, const char *fmt,...)
/* size of the prefix needed for timestamp and pid, if enabled */
size_t timestamp_size;
/* ignore debug msgs if noplace to send */
if (lev == DEBUG && Debugfile < 0)
return;
/* Save error str before calling any function that might change errno */
errorstr = useful_strerror(errno);
......@@ -336,10 +332,9 @@ elog(int lev, const char *fmt,...)
/* syslog doesn't want a trailing newline, but other destinations do */
strcat(msg_buf, "\n");
/* Write to debug file, if open and enabled */
/* NOTE: debug file is typically pointed at stderr */
if (Debugfile >= 0 && Use_syslog <= 1)
write(Debugfile, msg_buf, strlen(msg_buf));
/* write to terminal */
if (Use_syslog <= 1 || whereToSendOutput == Debug)
write(2, msg_buf, strlen(msg_buf));
if (lev > DEBUG && whereToSendOutput == Remote)
{
......@@ -371,17 +366,6 @@ elog(int lev, const char *fmt,...)
MemoryContextSwitchTo(oldcxt);
}
if (lev > DEBUG && whereToSendOutput != Remote)
{
/*
* We are running as an interactive backend, so just send the
* message to stderr. But don't send a duplicate if Debugfile
* write, above, already sent to stderr.
*/
if (Debugfile != fileno(stderr))
fputs(msg_buf, stderr);
}
/* done with the message, release space */
if (fmt_buf != fmt_fixedbuf)
free(fmt_buf);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.71 2001/06/14 01:09:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.72 2001/06/20 18:07:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -28,6 +28,7 @@
#include "catalog/catname.h"
#include "catalog/pg_shadow.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
......@@ -279,6 +280,7 @@ SetCharSet()
int i;
unsigned char FromChar,
ToChar;
char ChTable[80];
for (i = 0; i < 128; i++)
{
......@@ -286,11 +288,17 @@ SetCharSet()
RecodeBackTable[i] = i + 128;
}
p = getenv("PG_RECODETABLE");
if (IsUnderPostmaster)
{
GetCharSetByHost(ChTable, MyProcPort->raddr.in.sin_addr.s_addr, DataDir);
p = ChTable;
}
else
p = getenv("PG_RECODETABLE");
if (p && *p != '\0')
{
map_file = (char *) malloc((strlen(DataDir) +
strlen(p) + 2) * sizeof(char));
map_file = malloc(strlen(DataDir) + strlen(p) + 2);
if (! map_file)
elog(FATAL, "out of memory");
sprintf(map_file, "%s/%s", DataDir, p);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: auth.h,v 1.16 2001/03/22 04:00:47 momjian Exp $
* $Id: auth.h,v 1.17 2001/06/20 18:07:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -21,7 +21,7 @@
*----------------------------------------------------------------
*/
void be_recvauth(Port *port);
void ClientAuthentication(Port *port);
#define PG_KRB4_VERSION "PGVER4.1" /* at most KRB_SENDAUTH_VLEN chars */
#define PG_KRB5_VERSION "PGVER5.1"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment