OSDN Git Service

Handle reading of startup packet and authentication exchange after forking
authorPeter Eisentraut <peter_e@gmx.net>
Wed, 20 Jun 2001 18:07:56 +0000 (18:07 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Wed, 20 Jun 2001 18:07:56 +0000 (18:07 +0000)
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.

src/backend/libpq/auth.c
src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/backend/utils/error/elog.c
src/backend/utils/init/miscinit.c
src/include/libpq/auth.h

index dcb702e..9d8ffa7 100644 (file)
@@ -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;
 
index f1a0bd0..d6cbaf3 100644 (file)
@@ -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");
 }
index 2692053..476c2f7 100644 (file)
@@ -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");
        }
 
        /*
index e2ffb7b..2a41d3b 100644 (file)
@@ -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);
index df46469..4f2b940 100644 (file)
@@ -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);
index 649823f..df973df 100644 (file)
@@ -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"