diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index dcb702e95967604d0b78062c0b9fb04c385e644c..9d8ffa7db1c05f40828423e6a01b5cfe0e7ff90c 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -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; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index f1a0bd074479d7a7387419dea67799c5b6bb8fe0..d6cbaf34b59fc2c91972e2f76db82ec7a9d8f0dd 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -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"); } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 2692053a39df9118fa03451fff937a726cf27399..476c2f72c3ae5df777a7440f7d8f56527878e052 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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"); } /* diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index e2ffb7bc825abbce04b96993559755541fd6a6ea..2a41d3b57fdfb96bb537158836d0ad1d63caf88d 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -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); diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index df46469f0007eefed292958ba8ef8e8d6d66b86e..4f2b940b7eaa4f84626c3175371d5ecd2e25d11a 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -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); diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h index 649823f0e76804bd371af87859641628c92c663c..df973df555efc8fd21e069829294776debcf4e14 100644 --- a/src/include/libpq/auth.h +++ b/src/include/libpq/auth.h @@ -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"