*
*
* 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;
/*
* 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);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
+ pfree(buf);
auth_failed(port);
}
else
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;
}
static void
auth_failed(Port *port)
{
- char buffer[512];
const char *authmethod = "Unknown auth method:";
switch (port->auth_method)
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
*/
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);
}
*/
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;
}
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);
{
switch (port->auth_method)
{
- case uaCrypt:
- case uaReject:
+ case uaCrypt:
+ case uaReject:
status = STATUS_ERROR;
break;
*
*
* 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
*
*/
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;
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);
* garbage collecting the backend processes.
*/
BackendList = DLNewList();
- PortList = DLNewList();
/*
* Record postmaster options. We delay this till now to avoid
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...
fd_set readmask,
writemask;
int nSockets;
- Dlelem *curr;
struct timeval now,
later;
struct timezone tz;
}
}
-#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.
*/
*/
#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 */
}
}
/*
- * 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)
{
{
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
}
}
#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 */
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
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;
{
if (DebugLvl)
postmaster_error("processCancelRequest: CheckPointPID in cancel request for process %d", backendPID);
- return STATUS_ERROR;
+ return;
}
/* See if we have a matching backend */
{
/* 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);
}
/*
return NULL;
}
+
/*
* ConnCreate -- create a local connection data structure
*/
}
else
{
- DLAddHead(PortList, DLNewElem(port));
RandomSalt(port->salt);
port->pktInfo.state = Idle;
}
return port;
}
+
/*
* ConnFree -- free a local connection data structure
*/
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);
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;
- }
}
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
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();
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);
* 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));
return STATUS_OK;
}
+
/*
* split_opts -- split a string of options and append it to an argv array
*
char optbuf[ARGV_SIZE];
char ttybuf[ARGV_SIZE];
int i;
+ int status;
struct timeval now;
struct timezone tz;
* 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
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
on_exit_reset();
/* Close the postmaster's sockets */
- ClosePostmasterPorts(NULL);
+ ClosePostmasterPorts();
/* Set up command-line arguments for subprocess */
av[ac++] = "postgres";
fprintf(stderr, "%s: ", progname);
va_start(ap, fmt);
- fprintf(stderr, gettext(fmt), ap);
+ vfprintf(stderr, gettext(fmt), ap);
va_end(ap);
fprintf(stderr, "\n");
}