summaryrefslogtreecommitdiff
path: root/src/backend/libpq
diff options
context:
space:
mode:
authorMarc G. Fournier1998-01-26 01:42:53 +0000
committerMarc G. Fournier1998-01-26 01:42:53 +0000
commitd5bbe2aca55bc833e38c768d7f82c129b8b70c83 (patch)
tree47f4e1ecb3277869bb276e5433df335d920d1baf /src/backend/libpq
parent91d983aa1140e3ae109684ff7c916583ed059e0e (diff)
From: Phil Thompson <phil@river-bank.demon.co.uk>
I've completed the patch to fix the protocol and authentication issues I was discussing a couple of weeks ago. The particular changes are: - the protocol has a version number - network byte order is used throughout - the pg_hba.conf file is used to specify what method is used to authenticate a frontend (either password, ident, trust, reject, krb4 or krb5) - support for multiplexed backends is removed - appropriate changes to man pages - the -a switch to many programs to specify an authentication service no longer has any effect - the libpq.so version number has changed to 1.1 The new backend still supports the old protocol so old interfaces won't break.
Diffstat (limited to 'src/backend/libpq')
-rw-r--r--src/backend/libpq/auth.c668
-rw-r--r--src/backend/libpq/be-dumpdata.c4
-rw-r--r--src/backend/libpq/be-pqexec.c4
-rw-r--r--src/backend/libpq/crypt.c17
-rw-r--r--src/backend/libpq/hba.c477
-rw-r--r--src/backend/libpq/password.c69
-rw-r--r--src/backend/libpq/pg_hba.conf.sample60
-rw-r--r--src/backend/libpq/pqcomm.c78
-rw-r--r--src/backend/libpq/pqcomprim.c160
-rw-r--r--src/backend/libpq/pqpacket.c356
10 files changed, 825 insertions, 1068 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 8aa3efca9b..7464303728 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.20 1997/12/09 03:10:31 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.21 1998/01/26 01:41:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,39 +16,6 @@
*
* backend (postmaster) routines:
* be_recvauth receive authentication information
- * be_setauthsvc do/do not permit an authentication service
- * be_getauthsvc is an authentication service permitted?
- *
- * NOTES
- * To add a new authentication system:
- * 0. If you can't do your authentication over an existing socket,
- * you lose -- get ready to hack around this framework instead of
- * using it. Otherwise, you can assume you have an initialized
- * and empty connection to work with. (Please don't leave leftover
- * gunk in the connection after the authentication transactions, or
- * the POSTGRES routines that follow will be very unhappy.)
- * 1. Write a set of routines that:
- * let a client figure out what user/principal name to use
- * send authentication information (client side)
- * receive authentication information (server side)
- * You can include both routines in this file, using #ifdef FRONTEND
- * to separate them.
- * 2. Edit libpq/pqcomm.h and assign a MsgType for your protocol.
- * 3. Edit the static "struct authsvc" array and the generic
- * {be,fe}_{get,set}auth{name,svc} routines in this file to reflect
- * the new service. You may have to change the arguments of these
- * routines; they basically just reflect what Kerberos v4 needs.
- * 4. Hack on src/{,bin}/Makefile.global and src/{backend,libpq}/Makefile
- * to add library and CFLAGS hooks -- basically, grep the Makefile
- * hierarchy for KRBVERS to see where you need to add things.
- *
- * Send mail to post_hackers@postgres.Berkeley.EDU if you have to make
- * any changes to arguments, etc. Context diffs would be nice, too.
- *
- * Someday, this cruft will go away and magically be replaced by a
- * nice interface based on the GSS API or something. For now, though,
- * there's no (stable) UNIX security API to work with...
- *
*/
#include <stdio.h>
#include <string.h>
@@ -68,66 +35,21 @@
#include <libpq/auth.h>
#include <libpq/libpq.h>
-#include <libpq/libpq-be.h>
#include <libpq/hba.h>
#include <libpq/password.h>
#include <libpq/crypt.h>
-static int be_getauthsvc(MsgType msgtype);
-
-/*----------------------------------------------------------------
- * common definitions for generic fe/be routines
- *----------------------------------------------------------------
- */
-struct authsvc
-{
- char name[16]; /* service nickname (for command line) */
- MsgType msgtype; /* startup packet header type */
- int allowed; /* initially allowed (before command line
- * option parsing)? */
-};
+static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler)());
+static void handle_done_auth(Port *port);
+static void handle_krb4_auth(Port *port);
+static void handle_krb5_auth(Port *port);
+static void handle_password_auth(Port *port);
+static void readPasswordPacket(char *arg, PacketLen len, char *pkt);
+static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt);
+static int old_be_recvauth(Port *port);
+static int map_old_to_new(Port *port, UserAuth old, int status);
-/*
- * Command-line parsing routines use this structure to map nicknames
- * onto service types (and the startup packets to use with them).
- *
- * Programs receiving an authentication request use this structure to
- * decide which authentication service types are currently permitted.
- * By default, all authentication systems compiled into the system are
- * allowed. Unauthenticated connections are disallowed unless there
- * isn't any authentication system.
- */
-
-#if defined(HBA)
-static int useHostBasedAuth = 1;
-
-#else
-static int useHostBasedAuth = 0;
-
-#endif
-
-#if defined(KRB4) || defined(KRB5) || defined(HBA)
-#define UNAUTH_ALLOWED 0
-#else
-#define UNAUTH_ALLOWED 1
-#endif
-
-static struct authsvc authsvcs[] = {
- {"unauth", STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED},
- {"hba", STARTUP_HBA_MSG, 1},
- {"krb4", STARTUP_KRB4_MSG, 1},
- {"krb5", STARTUP_KRB5_MSG, 1},
-#if defined(KRB5)
- {"kerberos", STARTUP_KRB5_MSG, 1},
-#else
- {"kerberos", STARTUP_KRB4_MSG, 1},
-#endif
- {"password", STARTUP_PASSWORD_MSG, 1},
- {"crypt", STARTUP_CRYPT_MSG, 1}
-};
-
-static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#ifdef KRB4
/* This has to be ifdef'd out because krb.h does exist. This needs
@@ -140,10 +62,6 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
#include <krb.h>
-#ifdef FRONTEND
-/* moves to src/libpq/fe-auth.c */
-#else /* !FRONTEND */
-
/*
* pg_krb4_recvauth -- server routine to receive authentication information
* from the client
@@ -154,10 +72,7 @@ static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
* unauthenticated connections.)
*/
static int
-pg_krb4_recvauth(int sock,
- struct sockaddr_in * laddr,
- struct sockaddr_in * raddr,
- char *username)
+pg_krb4_recvauth(Port *)
{
long krbopts = 0; /* one-way authentication */
KTEXT_ST clttkt;
@@ -170,12 +85,12 @@ pg_krb4_recvauth(int sock,
strcpy(instance, "*"); /* don't care, but arg gets expanded
* anyway */
status = krb_recvauth(krbopts,
- sock,
+ port->sock,
&clttkt,
PG_KRB_SRVNAM,
instance,
- raddr,
- laddr,
+ &port->raddr.in,
+ &port->laddr.in,
&auth_data,
PG_KRB_SRVTAB,
key_sched,
@@ -198,12 +113,11 @@ pg_krb4_recvauth(int sock,
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
- if (username && *username &&
- strncmp(username, auth_data.pname, NAMEDATALEN))
+ if (strncmp(port->user, auth_data.pname, SM_USER))
{
sprintf(PQerrormsg,
"pg_krb4_recvauth: name \"%s\" != \"%s\"\n",
- username,
+ port->username,
auth_data.pname);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
@@ -212,14 +126,9 @@ pg_krb4_recvauth(int sock,
return (STATUS_OK);
}
-#endif /* !FRONTEND */
-
#else
static int
-pg_krb4_recvauth(int sock,
- struct sockaddr_in * laddr,
- struct sockaddr_in * raddr,
- char *username)
+pg_krb4_recvauth(Port *port)
{
sprintf(PQerrormsg,
"pg_krb4_recvauth: Kerberos not implemented on this "
@@ -267,10 +176,6 @@ pg_an_to_ln(char *aname)
return (aname);
}
-#ifdef FRONTEND
-/* moves to src/libpq/fe-auth.c */
-#else /* !FRONTEND */
-
/*
* pg_krb5_recvauth -- server routine to receive authentication information
* from the client
@@ -294,10 +199,7 @@ pg_an_to_ln(char *aname)
* but kdb5_edit allows you to select which principals to dump. Yay!)
*/
static int
-pg_krb5_recvauth(int sock,
- struct sockaddr_in * laddr,
- struct sockaddr_in * raddr,
- char *username)
+pg_krb5_recvauth(Port *port)
{
char servbuf[MAXHOSTNAMELEN + 1 +
sizeof(PG_KRB_SRVNAM)];
@@ -334,9 +236,9 @@ pg_krb5_recvauth(int sock,
* krb5_sendauth needs this to verify the address in the client
* authenticator.
*/
- sender_addr.addrtype = raddr->sin_family;
- sender_addr.length = sizeof(raddr->sin_addr);
- sender_addr.contents = (krb5_octet *) & (raddr->sin_addr);
+ sender_addr.addrtype = port->raddr.in.sin_family;
+ sender_addr.length = sizeof(port->raddr.in.sin_addr);
+ sender_addr.contents = (krb5_octet *) & (port->raddr.in.sin_addr);
if (strcmp(PG_KRB_SRVTAB, ""))
{
@@ -344,7 +246,7 @@ pg_krb5_recvauth(int sock,
keyprocarg = PG_KRB_SRVTAB;
}
- if (code = krb5_recvauth((krb5_pointer) & sock,
+ if (code = krb5_recvauth((krb5_pointer) & port->sock,
PG_KRB5_VERSION,
server,
&sender_addr,
@@ -390,11 +292,11 @@ pg_krb5_recvauth(int sock,
return (STATUS_ERROR);
}
kusername = pg_an_to_ln(kusername);
- if (username && strncmp(username, kusername, NAMEDATALEN))
+ if (strncmp(username, kusername, SM_USER))
{
sprintf(PQerrormsg,
"pg_krb5_recvauth: name \"%s\" != \"%s\"\n",
- username, kusername);
+ port->username, kusername);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
pfree(kusername);
@@ -404,15 +306,9 @@ pg_krb5_recvauth(int sock,
return (STATUS_OK);
}
-#endif /* !FRONTEND */
-
-
#else
static int
-pg_krb5_recvauth(int sock,
- struct sockaddr_in * laddr,
- struct sockaddr_in * raddr,
- char *username)
+pg_krb5_recvauth(Port *port)
{
sprintf(PQerrormsg,
"pg_krb5_recvauth: Kerberos not implemented on this "
@@ -425,246 +321,360 @@ pg_krb5_recvauth(int sock,
#endif /* KRB5 */
-static int
-pg_password_recvauth(Port *port, char *database, char *DataDir)
+
+/*
+ * Handle a v0 password packet.
+ */
+
+static void pg_passwordv0_recvauth(char *arg, PacketLen len, char *pkt)
{
- PacketBuf buf;
- char *user,
- *password;
+ Port *port;
+ PasswordPacketV0 *pp;
+ char *user, *password, *cp, *start;
- if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
+ port = (Port *)arg;
+ pp = (PasswordPacketV0 *)pkt;
+
+ /*
+ * The packet is supposed to comprise the user name and the password
+ * as C strings. Be careful the check that this is the case.
+ */
+
+ user = password = NULL;
+
+ len -= sizeof (pp->unused);
+
+ cp = start = pp->data;
+
+ while (len > 0)
+ if (*cp++ == '\0')
+ {
+ if (user == NULL)
+ user = start;
+ else
+ {
+ password = start;
+ break;
+ }
+
+ start = cp;
+ }
+
+ if (user == NULL || password == NULL)
{
sprintf(PQerrormsg,
- "pg_password_recvauth: failed to receive authentication packet.\n");
+ "pg_password_recvauth: badly formed password packet.\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
+
+ auth_failed(port);
}
+ else if (map_old_to_new(port, uaPassword,
+ verify_password(port->auth_arg, user, password)) != STATUS_OK)
+ auth_failed(port);
+}
- user = buf.data;
- password = buf.data + strlen(user) + 1;
- return verify_password(user, password, port, database, DataDir);
-}
+/*
+ * Tell the user the authentication failed, but not why.
+ */
-static int
-crypt_recvauth(Port *port)
+void auth_failed(Port *port)
{
- PacketBuf buf;
- char *user,
- *password;
-
- if (PacketReceive(port, &buf, BLOCKING) != STATUS_OK)
- {
- sprintf(PQerrormsg,
- "crypt_recvauth: failed to receive authentication packet.\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
-
- user = buf.data;
- password = buf.data + strlen(user) + 1;
-
- return crypt_verify(port, user, password);
+ PacketSendError(&port->pktInfo, "User authentication failed");
}
+
/*
* be_recvauth -- server demux routine for incoming authentication information
*/
-int
-be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo *sp)
+void be_recvauth(Port *port)
{
- MsgType msgtype;
+ AuthRequest areq;
+ void (*auth_handler)();
/*
- * A message type of STARTUP_MSG (which once upon a time was the only
- * startup message type) means user wants us to choose. "unauth" is
- * what used to be the only choice, but installation may choose "hba"
- * instead.
+ * Get the authentication method to use for this frontend/database
+ * combination.
*/
- if (msgtype_arg == STARTUP_MSG)
+
+ if (hba_getauthmethod(&port->raddr, port->database, port->auth_arg,
+ &port->auth_method) != STATUS_OK)
{
- if (useHostBasedAuth)
- msgtype = STARTUP_HBA_MSG;
- else
- msgtype = STARTUP_UNAUTH_MSG;
+ PacketSendError(&port->pktInfo, "Error getting authentication method");
+ return;
}
- else
- msgtype = msgtype_arg;
+ /* Handle old style authentication. */
- if (!username)
+ if (PG_PROTOCOL_MAJOR(port->proto) == 0)
{
- sprintf(PQerrormsg,
- "be_recvauth: no user name passed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- if (!port)
- {
- sprintf(PQerrormsg,
- "be_recvauth: no port structure passed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
+ if (old_be_recvauth(port) != STATUS_OK)
+ auth_failed(port);
+
+ return;
}
- switch (msgtype)
+ /* Handle new style authentication. */
+
+ switch (port->auth_method)
{
- case STARTUP_KRB4_MSG:
- if (!be_getauthsvc(msgtype))
- {
- sprintf(PQerrormsg,
- "be_recvauth: krb4 authentication disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- if (pg_krb4_recvauth(port->sock, (struct sockaddr_in *) &port->laddr,
- (struct sockaddr_in *) &port->raddr,
- username) != STATUS_OK)
- {
- sprintf(PQerrormsg,
- "be_recvauth: krb4 authentication failed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- break;
- case STARTUP_KRB5_MSG:
- if (!be_getauthsvc(msgtype))
- {
- sprintf(PQerrormsg,
- "be_recvauth: krb5 authentication disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- if (pg_krb5_recvauth(port->sock, (struct sockaddr_in *) &port->laddr,
- (struct sockaddr_in *) &port->raddr,
- username) != STATUS_OK)
- {
- sprintf(PQerrormsg,
- "be_recvauth: krb5 authentication failed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- break;
- case STARTUP_UNAUTH_MSG:
- if (!be_getauthsvc(msgtype))
- {
- sprintf(PQerrormsg,
- "be_recvauth: "
- "unauthenticated connections disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- break;
- case STARTUP_HBA_MSG:
- if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK)
- {
- sprintf(PQerrormsg,
- "be_recvauth: host-based authentication failed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- break;
- case STARTUP_PASSWORD_MSG:
- if (!be_getauthsvc(msgtype))
- {
- sprintf(PQerrormsg,
- "be_recvauth: "
- "plaintext password authentication disallowed\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- if (pg_password_recvauth(port, sp->database, DataDir) != STATUS_OK)
- {
-
- /*
- * pg_password_recvauth or lower-level routines have
- * already set
- */
- /* the error message */
- return (STATUS_ERROR);
- }
- break;
- case STARTUP_CRYPT_MSG:
- if (crypt_recvauth(port) != STATUS_OK)
- return STATUS_ERROR;
- break;
- default:
- sprintf(PQerrormsg,
- "be_recvauth: unrecognized message type: %d\n",
- msgtype);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return (STATUS_ERROR);
- }
- return (STATUS_OK);
+ case uaReject:
+ auth_failed(port);
+ return;
+
+ case uaKrb4:
+ areq = AUTH_REQ_KRB4;
+ auth_handler = handle_krb4_auth;
+ break;
+
+ case uaKrb5:
+ areq = AUTH_REQ_KRB5;
+ auth_handler = handle_krb5_auth;
+ break;
+
+ case uaTrust:
+ areq = AUTH_REQ_OK;
+ auth_handler = handle_done_auth;
+ break;
+
+ case uaIdent:
+ if (authident(&port->raddr.in, &port->laddr.in, port->user,
+ port->auth_arg) != STATUS_OK)
+ {
+ auth_failed(port);
+ return;
+ }
+
+ areq = AUTH_REQ_OK;
+ auth_handler = handle_done_auth;
+ break;
+
+ case uaPassword:
+ areq = AUTH_REQ_PASSWORD;
+ auth_handler = handle_password_auth;
+ break;
+
+ case uaCrypt:
+ areq = AUTH_REQ_CRYPT;
+ auth_handler = handle_password_auth;
+ break;
+ }
+
+ /* Tell the frontend what we want next. */
+
+ sendAuthRequest(port, areq, auth_handler);
}
+
/*
- * be_setauthsvc -- enable/disable the authentication services currently
- * selected for use by the backend
- * be_getauthsvc -- returns whether a particular authentication system
- * (indicated by its message type) is permitted by the
- * current selections
- *
- * be_setauthsvc encodes the command-line syntax that
- * -a "<service-name>"
- * enables a service, whereas
- * -a "no<service-name>"
- * disables it.
+ * Send an authentication request packet to the frontend.
*/
-void
-be_setauthsvc(char *name)
+
+static void sendAuthRequest(Port *port, AuthRequest areq, void (*handler)())
{
- int i,
- j;
- int turnon = 1;
+ char *dp, *sp;
+ int i;
+ uint32 net_areq;
- if (!name)
- return;
- if (!strncmp("no", name, 2))
+ /* Convert to a byte stream. */
+
+ net_areq = htonl(areq);
+
+ dp = port->pktInfo.pkt.ar.data;
+ sp = (char *)&net_areq;
+
+ *dp++ = 'R';
+
+ for (i = 1; i <= 4; ++i)
+ *dp++ = *sp++;
+
+ /* Add the salt for encrypted passwords. */
+
+ if (areq == AUTH_REQ_CRYPT)
{
- turnon = 0;
- name += 2;
+ *dp++ = port->salt[0];
+ *dp++ = port->salt[1];
+ i += 2;
}
- if (name[0] == '\0')
- return;
- for (i = 0; i < n_authsvcs; ++i)
- if (!strcmp(name, authsvcs[i].name))
- {
- for (j = 0; j < n_authsvcs; ++j)
- if (authsvcs[j].msgtype == authsvcs[i].msgtype)
- authsvcs[j].allowed = turnon;
- break;
- }
- if (i == n_authsvcs)
+
+ PacketSendSetup(&port -> pktInfo, i, handler, (char *)port);
+}
+
+
+/*
+ * Called when we have told the front end that it is authorised.
+ */
+
+static void handle_done_auth(Port *port)
+{
+ /*
+ * Don't generate any more traffic. This will cause the backend to
+ * start.
+ */
+
+ return;
+}
+
+
+/*
+ * Called when we have told the front end that it should use Kerberos V4
+ * authentication.
+ */
+
+static void handle_krb4_auth(Port *port)
+{
+ if (pg_krb4_recvauth(port) != STATUS_OK)
+ auth_failed(port);
+ else
+ sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
+}
+
+
+/*
+ * Called when we have told the front end that it should use Kerberos V5
+ * authentication.
+ */
+
+static void handle_krb5_auth(Port *port)
+{
+ if (pg_krb5_recvauth(port) != STATUS_OK)
+ auth_failed(port);
+ else
+ sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
+}
+
+
+/*
+ * Called when we have told the front end that it should use password
+ * authentication.
+ */
+
+static void handle_password_auth(Port *port)
+{
+ /* Set up the read of the password packet. */
+
+ PacketReceiveSetup(&port->pktInfo, readPasswordPacket, (char *)port);
+}
+
+
+/*
+ * Called when we have received the password packet.
+ */
+
+static void readPasswordPacket(char *arg, PacketLen len, char *pkt)
+{
+ char password[sizeof (PasswordPacket) + 1];
+ Port *port;
+
+ port = (Port *)arg;
+
+ /* Silently truncate a password that is too big. */
+
+ if (len > sizeof (PasswordPacket))
+ len = sizeof (PasswordPacket);
+
+ StrNCpy(password, ((PasswordPacket *)pkt)->passwd, len);
+
+ /*
+ * Use the local flat password file if clear passwords are used and the
+ * file is specified. Otherwise use the password in the pg_user table,
+ * encrypted or not.
+ */
+
+ if (port->auth_method == uaPassword && port->auth_arg[0] != '\0')
{
- sprintf(PQerrormsg,
- "be_setauthsvc: invalid name %s, ignoring...\n",
- name);
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
+ if (verify_password(port->auth_arg, port->user, password) != STATUS_OK)
+ auth_failed(port);
}
- return;
+ else if (crypt_verify(port, port->user, password) != STATUS_OK)
+ auth_failed(port);
+ else
+ sendAuthRequest(port, AUTH_REQ_OK, handle_done_auth);
}
-static int
-be_getauthsvc(MsgType msgtype)
+
+/*
+ * Server demux routine for incoming authentication information for protocol
+ * version 0.
+ */
+static int old_be_recvauth(Port *port)
{
- int i;
+ int status;
+ MsgType msgtype = (MsgType)port->proto;
+
+ /* Handle the authentication that's offered. */
+
+ switch (msgtype)
+ {
+ case STARTUP_KRB4_MSG:
+ status = map_old_to_new(port,uaKrb4,pg_krb4_recvauth(port));
+ break;
+
+ case STARTUP_KRB5_MSG:
+ status = map_old_to_new(port,uaKrb5,pg_krb5_recvauth(port));
+ break;
+
+ case STARTUP_MSG:
+ status = map_old_to_new(port,uaTrust,STATUS_OK);
+ break;
+
+ case STARTUP_PASSWORD_MSG:
+ PacketReceiveSetup(&port->pktInfo, pg_passwordv0_recvauth,
+ (char *)port);
- for (i = 0; i < n_authsvcs; ++i)
- if (msgtype == authsvcs[i].msgtype)
- return (authsvcs[i].allowed);
- return (0);
+ return STATUS_OK;
+
+ default:
+ fprintf(stderr, "Invalid startup message type: %u\n", msgtype);
+
+ return STATUS_OK;
+ }
+
+ return status;
+}
+
+
+/*
+ * The old style authentication has been done. Modify the result of this (eg.
+ * allow the connection anyway, disallow it anyway, or use the result)
+ * depending on what authentication we really want to use.
+ */
+
+static int map_old_to_new(Port *port, UserAuth old, int status)
+{
+ switch (port->auth_method)
+ {
+ case uaCrypt:
+ case uaReject:
+ status = STATUS_ERROR;
+ break;
+
+ case uaKrb4:
+ if (old != uaKrb4)
+ status = STATUS_ERROR;
+ break;
+
+ case uaKrb5:
+ if (old != uaKrb5)
+ status = STATUS_ERROR;
+ break;
+
+ case uaTrust:
+ status = STATUS_OK;
+ break;
+
+ case uaIdent:
+ status = authident(&port->raddr.in, &port->laddr.in,
+ port->user, port->auth_arg);
+ break;
+
+ case uaPassword:
+ if (old != uaPassword)
+ status = STATUS_ERROR;
+
+ break;
+ }
+
+ return status;
}
diff --git a/src/backend/libpq/be-dumpdata.c b/src/backend/libpq/be-dumpdata.c
index f34be7cdab..7a20e26e54 100644
--- a/src/backend/libpq/be-dumpdata.c
+++ b/src/backend/libpq/be-dumpdata.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.9 1997/09/12 04:07:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-dumpdata.c,v 1.10 1998/01/26 01:41:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,7 @@
#include <postgres.h>
#include <lib/dllist.h>
-#include <libpq/libpq-be.h>
+#include <libpq/libpq.h>
#include <access/heapam.h>
#include <access/htup.h>
#include <storage/buf.h>
diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c
index 69d8675a46..a63ff43161 100644
--- a/src/backend/libpq/be-pqexec.c
+++ b/src/backend/libpq/be-pqexec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.13 1998/01/07 21:03:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.14 1998/01/26 01:41:06 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,7 +27,7 @@
#include <tcop/fastpath.h>
#include <tcop/tcopprot.h>
#include <lib/dllist.h>
-#include <libpq/libpq-be.h>
+#include <libpq/libpq.h>
#include <fmgr.h>
#include <utils/exc.h>
#include <utils/builtins.h>
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 6e6555503a..7a72275bc4 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -17,9 +17,6 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
-#ifdef HAVE_CRYPT_H
-#include <crypt.h>
-#endif
#include "postgres.h"
#include "miscadmin.h"
@@ -27,6 +24,10 @@
#include "storage/fd.h"
#include "libpq/crypt.h"
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
char** pwd_cache = NULL;
int pwd_cache_count = 0;
@@ -219,6 +220,7 @@ int crypt_getloginfo(const char* user, char** passwd, char** valuntil) {
/*-------------------------------------------------------------------------*/
+#ifdef 0
MsgType crypt_salt(const char* user) {
char* passwd;
@@ -237,6 +239,7 @@ MsgType crypt_salt(const char* user) {
if (valuntil) free((void*)valuntil);
return STARTUP_SALT_MSG;
}
+#endif
/*-------------------------------------------------------------------------*/
@@ -258,7 +261,13 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) {
return STATUS_ERROR;
}
- crypt_pwd = crypt(passwd, port->salt);
+ /*
+ * Compare with the encrypted or plain password depending on the
+ * authentication method being used for this connection.
+ */
+
+ crypt_pwd = (port->auth_method == uaCrypt ? crypt(passwd, port->salt) : passwd);
+
if (!strcmp(pgpass, crypt_pwd)) {
/* check here to be sure we are not past valuntil
*/
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 3390f38f9a..048add7771 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.25 1997/12/09 03:10:38 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.26 1998/01/26 01:41:08 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -97,84 +97,56 @@ read_through_eol(FILE *file)
static void
-read_hba_entry2(FILE *file, enum Userauth * userauth_p, char usermap_name[],
- bool *error_p, bool *matches_p, bool find_password_entries)
+read_hba_entry2(FILE *file, UserAuth * userauth_p, char auth_arg[],
+ bool *error_p)
{
/*--------------------------------------------------------------------------
Read from file FILE the rest of a host record, after the mask field,
- and return the interpretation of it as *userauth_p, usermap_name, and
+ and return the interpretation of it as *userauth_p, auth_arg, and
*error_p.
---------------------------------------------------------------------------*/
char buf[MAX_TOKEN];
- bool userauth_valid;
-
/* Get authentication type token. */
next_token(file, buf, sizeof(buf));
- userauth_valid = false;
- if (buf[0] == '\0')
- {
- *error_p = true;
- }
+
+ if (strcmp(buf, "trust") == 0)
+ *userauth_p = uaTrust;
+ else if (strcmp(buf, "ident") == 0)
+ *userauth_p = uaIdent;
+ else if (strcmp(buf, "password") == 0)
+ *userauth_p = uaPassword;
+ else if (strcmp(buf, "krb4") == 0)
+ *userauth_p = uaKrb4;
+ else if (strcmp(buf, "krb5") == 0)
+ *userauth_p = uaKrb5;
+ else if (strcmp(buf, "reject") == 0)
+ *userauth_p = uaReject;
+ else if (strcmp(buf, "crypt") == 0)
+ *userauth_p = uaCrypt;
else
{
- userauth_valid = true;
- if (strcmp(buf, "trust") == 0)
- {
- *userauth_p = Trust;
- }
- else if (strcmp(buf, "ident") == 0)
- {
- *userauth_p = Ident;
- }
- else if (strcmp(buf, "password") == 0)
- {
- *userauth_p = Password;
- }
- else
- {
- userauth_valid = false;
- }
+ *error_p = true;
- if ((find_password_entries && strcmp(buf, "password") == 0) ||
- (!find_password_entries && strcmp(buf, "password") != 0))
- {
- *matches_p = true;
- }
- else
- {
- *matches_p = false;
- }
+ if (buf[0] != '\0')
+ read_through_eol(file);
}
- if (!userauth_valid || !*matches_p || *error_p)
- {
- if (!userauth_valid)
- {
- *error_p = true;
- }
- read_through_eol(file);
- }
- else
+ if (!*error_p)
{
- /* Get the map name token, if any */
+ /* Get the authentication argument token, if any */
next_token(file, buf, sizeof(buf));
if (buf[0] == '\0')
- {
- *error_p = false;
- usermap_name[0] = '\0';
- }
+ auth_arg[0] = '\0';
else
{
- strncpy(usermap_name, buf, USERMAP_NAME_SIZE);
+ StrNCpy(auth_arg, buf, MAX_AUTH_ARG - 1);
next_token(file, buf, sizeof(buf));
if (buf[0] != '\0')
{
*error_p = true;
read_through_eol(file);
}
- else
- *error_p = false;
}
}
}
@@ -182,139 +154,150 @@ read_hba_entry2(FILE *file, enum Userauth * userauth_p, char usermap_name[],
static void
-process_hba_record(FILE *file,
- const struct in_addr ip_addr, const char database[],
+process_hba_record(FILE *file, SockAddr *raddr, const char database[],
bool *matches_p, bool *error_p,
- enum Userauth * userauth_p, char usermap_name[],
- bool find_password_entries)
+ UserAuth * userauth_p, char auth_arg[])
{
/*---------------------------------------------------------------------------
Process the non-comment record in the config file that is next on the file.
- See if it applies to a connection to a host with IP address "ip_addr"
+ See if it applies to a connection to a host with IP address "*raddr"
to a database named "database[]". If so, return *matches_p true
- and *userauth_p and usermap_name[] as the values from the entry.
- If not, return matches_p false. If the record has a syntax error,
+ and *userauth_p and auth_arg[] as the values from the entry.
+ If not, leave *matches_p as it was. If the record has a syntax error,
return *error_p true, after issuing a message to stderr. If no error,
leave *error_p as it was.
---------------------------------------------------------------------------*/
- char buf[MAX_TOKEN]; /* A token from the record */
+ char db[MAX_TOKEN], buf[MAX_TOKEN];
+
+ /* Read the record type field. */
- /* Read the record type field */
next_token(file, buf, sizeof(buf));
+
if (buf[0] == '\0')
- *matches_p = false;
- else
+ return;
+
+ /* Check the record type. */
+
+ if (strcmp(buf, "local") == 0)
+ {
+ /* Get the database. */
+
+ next_token(file, db, sizeof(db));
+
+ if (db[0] == '\0')
+ goto syntax;
+
+ /* Read the rest of the line. */
+
+ read_hba_entry2(file, userauth_p, auth_arg, error_p);
+
+ /*
+ * For now, disallow methods that need AF_INET sockets to work.
+ */
+
+ if (!*error_p &&
+ (*userauth_p == uaIdent ||
+ *userauth_p == uaKrb4 ||
+ *userauth_p == uaKrb5))
+ *error_p = true;
+
+ if (*error_p)
+ goto syntax;
+
+ /*
+ * If this record isn't for our database, or this is the wrong
+ * sort of connection, ignore it.
+ */
+
+ if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0) ||
+ raddr->sa.sa_family != AF_UNIX)
+ return;
+ }
+ else if (strcmp(buf, "host") == 0)
{
- /* if this isn't a "host" record, it can't match. */
- if (strcmp(buf, "host") != 0)
+ struct in_addr file_ip_addr, mask;
+
+ /* Get the database. */
+
+ next_token(file, db, sizeof(db));
+
+ if (db[0] == '\0')
+ goto syntax;
+
+ /* Read the IP address field. */
+
+ next_token(file, buf, sizeof(buf));
+
+ if (buf[0] == '\0')
+ goto syntax;
+
+ /* Remember the IP address field and go get mask field. */
+
+ if (!inet_aton(buf, &file_ip_addr))
{
- *matches_p = false;
read_through_eol(file);
+ goto syntax;
}
- else
+
+ /* Read the mask field. */
+
+ next_token(file, buf, sizeof(buf));
+
+ if (buf[0] == '\0')
+ goto syntax;
+
+ if (!inet_aton(buf, &mask))
{
- /* It's a "host" record. Read the database name field. */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0')
- *matches_p = false;
- else
- {
- /* If this record isn't for our database, ignore it. */
- if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0)
- {
- *matches_p = false;
- read_through_eol(file);
- }
- else
- {
- /* Read the IP address field */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0')
- *matches_p = false;
- else
- {
- int valid; /* Field is valid dotted
- * decimal */
-
- /*
- * Remember the IP address field and go get mask
- * field
- */
- struct in_addr file_ip_addr; /* IP address field
- * value */
-
- valid = inet_aton(buf, &file_ip_addr);
- if (!valid)
- {
- *matches_p = false;
- read_through_eol(file);
- }
- else
- {
- /* Read the mask field */
- next_token(file, buf, sizeof(buf));
- if (buf[0] == '\0')
- *matches_p = false;
- else
- {
- struct in_addr mask;
-
- /*
- * Got mask. Now see if this record is
- * for our host.
- */
- valid = inet_aton(buf, &mask);
- if (!valid)
- {
- *matches_p = false;
- read_through_eol(file);
- }
- else
- {
- if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr)
- != 0x0000)
- {
- *matches_p = false;
- read_through_eol(file);
- }
- else
- {
-
- /*
- * This is the record we're
- * looking for. Read the rest of
- * the info from it.
- */
- read_hba_entry2(file, userauth_p, usermap_name,
- error_p, matches_p, find_password_entries);
- if (*error_p)
- {
- sprintf(PQerrormsg,
- "process_hba_record: invalid syntax in "
- "hba config file "
- "for host record for IP address %s\n",
- inet_ntoa(file_ip_addr));
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- }
- }
- }
- }
- }
- }
- }
- }
+ read_through_eol(file);
+ goto syntax;
}
+
+ /*
+ * This is the record we're looking for. Read the rest of the
+ * info from it.
+ */
+
+ read_hba_entry2(file, userauth_p, auth_arg, error_p);
+
+ if (*error_p)
+ goto syntax;
+
+ /*
+ * If this record isn't for our database, or this is the wrong
+ * sort of connection, ignore it.
+ */
+
+ if ((strcmp(db, database) != 0 && strcmp(db, "all") != 0) ||
+ raddr->sa.sa_family != AF_INET ||
+ ((file_ip_addr.s_addr ^ raddr->in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
+ return;
}
+ else
+ {
+ read_through_eol(file);
+ goto syntax;
+ }
+
+ *matches_p = true;
+
+ return;
+
+syntax:
+ sprintf(PQerrormsg,
+ "process_hba_record: invalid syntax in pg_hba.conf file\n");
+
+ fputs(PQerrormsg, stderr);
+ pqdebug("%s", PQerrormsg);
+
+ *error_p = true;
}
static void
-process_open_config_file(FILE *file,
- const struct in_addr ip_addr, const char database[],
- bool *host_ok_p, enum Userauth * userauth_p,
- char usermap_name[], bool find_password_entries)
+process_open_config_file(FILE *file, SockAddr *raddr, const char database[],
+ bool *host_ok_p, UserAuth * userauth_p,
+ char auth_arg[])
{
/*---------------------------------------------------------------------------
This function does the same thing as find_hba_entry, only with
@@ -348,36 +331,26 @@ process_open_config_file(FILE *file,
read_through_eol(file);
else
{
- process_hba_record(file, ip_addr, database,
- &found_entry, &error, userauth_p, usermap_name,
- find_password_entries);
+ process_hba_record(file, raddr, database,
+ &found_entry, &error, userauth_p, auth_arg);
}
}
}
- if (found_entry)
- {
- if (error)
- *host_ok_p = false;
- else
- *host_ok_p = true;
- }
- else
- *host_ok_p = false;
+
+ if (found_entry && !error)
+ *host_ok_p = true;
}
-void
-find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
- const char database[],
- bool *host_ok_p, enum Userauth * userauth_p,
- char usermap_name[], bool find_password_entries)
+static void
+find_hba_entry(SockAddr *raddr, const char database[], bool *host_ok_p,
+ UserAuth * userauth_p, char auth_arg[])
{
/*--------------------------------------------------------------------------
Read the config file and find an entry that allows connection from
- host "ip_addr" to database "database". If not found, return
- *host_ok_p == false. If found, return *userauth_p and *usermap_name
- representing the contents of that entry.
+ host "*raddr" to database "database". If found, return *host_ok_p == true
+ and *userauth_p and *auth_arg representing the contents of that entry.
When a record has invalid syntax, we either ignore it or reject the
connection (depending on where it's invalid). No message or anything.
@@ -436,8 +409,6 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
{
/* The open of the config file failed. */
- *host_ok_p = false;
-
sprintf(PQerrormsg,
"find_hba_entry: Host-based authentication config file "
"does not exist or permissions are not setup correctly! "
@@ -448,8 +419,8 @@ find_hba_entry(const char DataDir[], const struct in_addr ip_addr,
}
else
{
- process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p,
- usermap_name, find_password_entries);
+ process_open_config_file(file, raddr, database, host_ok_p, userauth_p,
+ auth_arg);
FreeFile(file);
}
pfree(conf_file);
@@ -754,8 +725,7 @@ verify_against_open_usermap(FILE *file,
static void
-verify_against_usermap(const char DataDir[],
- const char pguser[],
+verify_against_usermap(const char pguser[],
const char ident_username[],
const char usermap_name[],
bool *checks_out_p)
@@ -834,20 +804,20 @@ verify_against_usermap(const char DataDir[],
-static void
-authident(const char DataDir[],
- const Port port, const char postgres_username[],
- const char usermap_name[],
- bool *authentic_p)
+int
+authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr,
+ const char postgres_username[],
+ const char auth_arg[])
{
/*---------------------------------------------------------------------------
Talk to the ident server on the remote host and find out who owns the
connection described by "port". Then look in the usermap file under
- the usermap usermap_name[] and see if that user is equivalent to
+ the usermap auth_arg[] and see if that user is equivalent to
Postgres user user[].
- Return *authentic_p true iff yes.
+ Return STATUS_OK if yes.
---------------------------------------------------------------------------*/
+ bool checks_out;
bool ident_failed;
/* We were unable to get ident to give us a username */
@@ -855,120 +825,35 @@ authident(const char DataDir[],
/* The username returned by ident */
- ident(port.raddr.in.sin_addr, port.laddr.in.sin_addr,
- port.raddr.in.sin_port, port.laddr.in.sin_port,
+ ident(raddr->sin_addr, laddr->sin_addr,
+ raddr->sin_port, laddr->sin_port,
&ident_failed, ident_username);
if (ident_failed)
- *authentic_p = false;
- else
- {
- bool checks_out;
+ return STATUS_ERROR;
- verify_against_usermap(DataDir,
- postgres_username, ident_username, usermap_name,
+ verify_against_usermap(postgres_username, ident_username, auth_arg,
&checks_out);
- if (checks_out)
- *authentic_p = true;
- else
- *authentic_p = false;
- }
+
+ return (checks_out ? STATUS_OK : STATUS_ERROR);
}
extern int
-hba_recvauth(const Port *port, const char database[], const char user[],
- const char DataDir[])
+hba_getauthmethod(SockAddr *raddr, char *database, char *auth_arg,
+ UserAuth *auth_method)
{
/*---------------------------------------------------------------------------
- Determine if the TCP connection described by "port" is with someone
- allowed to act as user "user" and access database "database". Return
- STATUS_OK if yes; STATUS_ERROR if not.
+ Determine what authentication method should be used when accessing database
+ "database" from frontend "raddr". Return the method, an optional argument,
+ and STATUS_OK.
----------------------------------------------------------------------------*/
bool host_ok;
- /*
- * There's an entry for this database and remote host in the pg_hba
- * file
- */
- char usermap_name[USERMAP_NAME_SIZE + 1];
-
- /*
- * The name of the map pg_hba specifies for this connection (or
- * special value "SAMEUSER")
- */
- enum Userauth userauth;
-
- /*
- * The type of user authentication pg_hba specifies for this
- * connection
- */
- int retvalue;
-
- /* UNIX socket always OK, for now */
- if (port->raddr.in.sin_family == AF_UNIX)
- return STATUS_OK;
- /* Our eventual return value */
-
-
- find_hba_entry(DataDir, port->raddr.in.sin_addr, database,
- &host_ok, &userauth, usermap_name,
- false /* don't find password entries of type
- 'password' */ );
+ host_ok = false;
- if (!host_ok)
- retvalue = STATUS_ERROR;
- else
- {
- switch (userauth)
- {
- case Trust:
- retvalue = STATUS_OK;
- break;
- case Ident:
- {
-
- /*
- * Here's where we need to call up ident and
- * authenticate the user
- */
-
- bool authentic; /* He is who he says he
- * is. */
-
- authident(DataDir, *port, user, usermap_name, &authentic);
-
- if (authentic)
- retvalue = STATUS_OK;
- else
- retvalue = STATUS_ERROR;
- }
- break;
+ find_hba_entry(raddr, database, &host_ok, auth_method, auth_arg);
- default:
- retvalue = STATUS_ERROR;
- Assert(false);
- }
- }
- return (retvalue);
+ return (host_ok ? STATUS_OK : STATUS_ERROR);
}
-
-
-/*----------------------------------------------------------------
- * This version of hba was written by Bryan Henderson
- * in September 1996 for Release 6.0. It changed the format of the
- * hba file and added ident function.
- *
- * Here are some notes about the original host based authentication
- * the preceded this one.
- *
- * based on the securelib package originally written by William
- * LeFebvre, EECS Department, Northwestern University
- * (phil@eecs.nwu.edu) - orginal configuration file code handling
- * by Sam Horrocks (sam@ics.uci.edu)
- *
- * modified and adapted for use with Postgres95 by Paul Fisher
- * (pnfisher@unity.ncsu.edu)
- *
- -----------------------------------------------------------------*/
diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c
index 8f26597f6a..c77b065e33 100644
--- a/src/backend/libpq/password.c
+++ b/src/backend/libpq/password.c
@@ -1,6 +1,6 @@
#include <postgres.h>
+#include <miscadmin.h>
#include <libpq/password.h>
-#include <libpq/hba.h>
#include <libpq/libpq.h>
#include <storage/fd.h>
#include <string.h>
@@ -10,56 +10,15 @@
#endif
int
-verify_password(char *user, char *password, Port *port,
- char *database, char *DataDir)
+verify_password(char *auth_arg, char *user, char *password)
{
- bool host_ok;
- enum Userauth userauth;
- char pw_file_name[PWFILE_NAME_SIZE + 1];
+ char *pw_file_fullname;
+ FILE *pw_file;
- char *pw_file_fullname;
- FILE *pw_file;
-
- char pw_file_line[255];
- char *p,
- *test_user,
- *test_pw;
-
- find_hba_entry(DataDir, port->raddr.in.sin_addr, database,
- &host_ok, &userauth, pw_file_name, true);
-
- if (!host_ok)
- {
- sprintf(PQerrormsg,
- "verify_password: couldn't find entry for connecting host\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
-
- if (userauth != Password)
- {
- sprintf(PQerrormsg,
- "verify_password: couldn't find entry of type 'password' "
- "for this host\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
-
- if (!pw_file_name || pw_file_name[0] == '\0')
- {
- sprintf(PQerrormsg,
- "verify_password: no password file specified\n");
- fputs(PQerrormsg, stderr);
- pqdebug("%s", PQerrormsg);
- return STATUS_ERROR;
- }
-
- pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(pw_file_name) + 2);
+ pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(auth_arg) + 2);
strcpy(pw_file_fullname, DataDir);
strcat(pw_file_fullname, "/");
- strcat(pw_file_fullname, pw_file_name);
+ strcat(pw_file_fullname, auth_arg);
pw_file = AllocateFile(pw_file_fullname, "r");
if (!pw_file)
@@ -69,12 +28,17 @@ verify_password(char *user, char *password, Port *port,
pw_file_fullname);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
+
+ pfree(pw_file_fullname);
+
return STATUS_ERROR;
}
while (!feof(pw_file))
{
- fgets(pw_file_line, 255, pw_file);
+ char pw_file_line[255], *p, *test_user, *test_pw;
+
+ fgets(pw_file_line, sizeof (pw_file_line), pw_file);
p = pw_file_line;
test_user = strtok(p, ":");
@@ -97,6 +61,9 @@ verify_password(char *user, char *password, Port *port,
if (strcmp(crypt(password, test_pw), test_pw) == 0)
{
/* it matched. */
+
+ pfree(pw_file_fullname);
+
return STATUS_OK;
}
@@ -105,6 +72,9 @@ verify_password(char *user, char *password, Port *port,
user);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
+
+ pfree(pw_file_fullname);
+
return STATUS_ERROR;
}
}
@@ -114,5 +84,8 @@ verify_password(char *user, char *password, Port *port,
user);
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
+
+ pfree(pw_file_fullname);
+
return STATUS_ERROR;
}
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index bb0d34f401..c746c752e4 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -4,6 +4,7 @@
#
# This file controls what hosts are allowed to connect to what databases
# and specifies some options on how users on a particular host are identified.
+# It is read each time a host tries to make a connection to a database.
#
# Each line (terminated by a newline character) is a record. A record cannot
# be continued across two lines.
@@ -29,13 +30,14 @@
# Record type "host"
# ------------------
#
-# This record identifies a set of hosts that are permitted to connect to
-# databases. No hosts are permitted to connect except as specified by a
-# "host" record.
+# This record identifies a set of network hosts that are permitted to connect
+# to databases. No network hosts are permitted to connect except as specified
+# by a "host" record. See the record type "local" to specify permitted
+# connections using UNIX sockets.
#
# Format:
#
-# host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [MAP]
+# host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [AUTH_ARGUMENT]
#
# DBNAME is the name of a Postgres database, or "all" to indicate all
# databases.
@@ -49,33 +51,54 @@
# under the Postgres username he supplies in his connection parameters.
#
# ident: Authentication is done by the ident server on the remote
-# host, via the ident (RFC 1413) protocol.
+# host, via the ident (RFC 1413) protocol. AUTH_ARGUMENT, if
+# specified, is a map name to be found in the pg_ident.conf file.
+# That table maps from ident usernames to Postgres usernames. The
+# special map name "sameuser" indicates an implied map (not found
+# in pg_ident.conf) that maps every ident username to the identical
+# Postgres username.
#
# trust: No authentication is done. Trust that the user has the
# authority to user whatever username he says he does.
# Before Postgres Version 6, all authentication was this way.
#
-# MAP is the name of a map that matches an authenticated principal with
-# a Postgres username. If USERNAME is "trust", this value is ignored and
-# may be absent.
+# reject: Reject the connection.
#
-# In the case of USERAUTH=ident, this is a map name to be found in the
-# pg_ident.conf file. That table maps from ident usernames to Postgres
-# usernames. The special map name "sameuser" indicates an implied map
-# (not found in pg_ident.conf) that maps every ident username to the identical
-# Postgres username.
+# password: Authentication is done by matching a password supplied in clear
+# by the host. If AUTH_ARGUMENT is specified then the password is
+# compared with the user's entry in that file (in the $PGDATA
+# directory). See pg_passwd(1). If it is omitted then the
+# password is compared with the user's entry in the pg_user table.
+#
+# crypt: Authentication is done by matching an encrypted password supplied
+# by the host with that held for the user in the pg_user table.
+#
+# krb4: Kerberos V4 authentication is used.
+#
+# krb5: Kerberos V5 authentication is used.
+# Record type "local"
+# ------------------
#
+# This record identifies the authentication to use when connecting to a
+# particular database via a local UNIX socket.
+#
+# Format:
+#
+# local DBNAME USERAUTH [AUTH_ARGUMENT]
+#
+# The format is the same as that of the "host" record type except that the
+# IP_ADDRESS and ADDRESS_MASK are omitted and the "ident", "krb4" and "krb5"
+# values of USERAUTH are no allowed.
+
# For backwards compatibility, PostgreSQL also accepts pre-Version 6 records,
# which look like:
#
# all 127.0.0.1 0.0.0.0
-#
-#
# TYPE DATABASE IP_ADDRESS MASK USERAUTH MAP
-host all 127.0.0.1 255.255.255.255 trust
+#host all 127.0.0.1 255.255.255.255 trust
# The above allows any user on the local system to connect to any database
# under any username.
@@ -86,10 +109,11 @@ host all 127.0.0.1 255.255.255.255 trust
# connect to database template1 as the same username that ident on that host
# identifies him as (typically his Unix username).
+#host all 192.168.0.1 255.255.255.255 reject
#host all 0.0.0.0 0.0.0.0 trust
-# The above would allow anyone anywhere to connect to any database under
-# any username.
+# The above would allow anyone anywhere except from 192.168.0.1 to connect to
+# any database under any username.
#host all 192.168.0.0 255.255.255.0 ident omicron
#
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 8014ae14f8..2b4e25f873 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.34 1998/01/25 05:13:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/pqcomm.c,v 1.35 1998/01/26 01:41:11 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -269,28 +270,6 @@ int
pq_getnchar(char *s, int off, int maxlen)
{
return pqGetNBytes(s + off, maxlen, Pfin);
-
-#if 0
- int c = '\0';
-
- if (Pfin == (FILE *) NULL)
- {
-/* elog(DEBUG, "Input descriptor is null"); */
- return (EOF);
- }
-
- s += off;
- while (maxlen-- && (c = pq_getc(Pfin)) != EOF)
- *s++ = c;
-
- /* -----------------
- * If EOF reached let caller know
- * -----------------
- */
- if (c == EOF)
- return (EOF);
- return (!EOF);
-#endif
}
/* --------------------------------
@@ -591,11 +570,7 @@ do_unlink()
int
StreamServerPort(char *hostName, short portName, int *fdP)
{
- union
- {
- struct sockaddr_in in;
- struct sockaddr_un un;
- } saddr;
+ SockAddr saddr;
int fd,
err,
family;
@@ -624,20 +599,19 @@ StreamServerPort(char *hostName, short portName, int *fdP)
return (STATUS_ERROR);
}
bzero(&saddr, sizeof(saddr));
+ saddr.sa.sa_family = family;
if (family == AF_UNIX)
{
- saddr.un.sun_family = family;
len = UNIXSOCK_PATH(saddr.un, portName);
strcpy(sock_path, saddr.un.sun_path);
}
else
{
- saddr.in.sin_family = family;
saddr.in.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.in.sin_port = htons(portName);
- len = sizeof saddr.in;
+ len = sizeof (struct sockaddr_in);
}
- err = bind(fd, (struct sockaddr *) & saddr, len);
+ err = bind(fd, &saddr.sa, len);
if (err < 0)
{
sprintf(PQerrormsg,
@@ -685,7 +659,7 @@ StreamConnection(int server_fd, Port *port)
{
int len,
addrlen;
- int family = port->raddr.in.sin_family;
+ int family = port->raddr.sa.sa_family;
/* accept connection (and fill in the client (remote) address) */
len = family == AF_INET ?
@@ -726,8 +700,6 @@ StreamConnection(int server_fd, Port *port)
}
}
- port->mask = 1 << port->sock;
-
/* reset to non-blocking */
fcntl(port->sock, F_SETFL, 1);
@@ -788,7 +760,7 @@ StreamOpen(char *hostName, short portName, Port *port)
len = UNIXSOCK_PATH(port->raddr.un, portName);
}
/* connect to the server */
- if ((port->sock = socket(port->raddr.in.sin_family, SOCK_STREAM, 0)) < 0)
+ if ((port->sock = socket(port->raddr.sa.sa_family, SOCK_STREAM, 0)) < 0)
{
sprintf(PQerrormsg,
"FATAL: StreamOpen: socket() failed: errno=%d\n",
@@ -797,7 +769,7 @@ StreamOpen(char *hostName, short portName, Port *port)
pqdebug("%s", PQerrormsg);
return (STATUS_ERROR);
}
- err = connect(port->sock, (struct sockaddr *) & port->raddr, len);
+ err = connect(port->sock, &port->raddr.sa, len);
if (err < 0)
{
sprintf(PQerrormsg,
@@ -809,8 +781,7 @@ StreamOpen(char *hostName, short portName, Port *port)
}
/* fill in the client address */
- if (getsockname(port->sock, (struct sockaddr *) & port->laddr,
- &len) < 0)
+ if (getsockname(port->sock, &port->laddr.sa, &len) < 0)
{
sprintf(PQerrormsg,
"FATAL: StreamOpen: getsockname() failed: errno=%d\n",
@@ -822,32 +793,3 @@ StreamOpen(char *hostName, short portName, Port *port)
return (STATUS_OK);
}
-
-static char *authentication_type_name[] = {
- 0, 0, 0, 0, 0, 0, 0,
- "the default authentication type",
- 0, 0,
- "Kerberos v4",
- "Kerberos v5",
- "host-based authentication",
- "unauthenication",
- "plaintext password authentication"
-};
-
-char *
-name_of_authentication_type(int type)
-{
- char *result = 0;
-
- if (type >= 1 && type <= LAST_AUTHENTICATION_TYPE)
- {
- result = authentication_type_name[type];
- }
-
- if (result == 0)
- {
- result = "<unknown authentication type>";
- }
-
- return result;
-}
diff --git a/src/backend/libpq/pqcomprim.c b/src/backend/libpq/pqcomprim.c
index 53742190f3..0dd46d9205 100644
--- a/src/backend/libpq/pqcomprim.c
+++ b/src/backend/libpq/pqcomprim.c
@@ -1,122 +1,150 @@
#include <stdlib.h>
#include <stdio.h>
+#include <netinet/in.h>
#include "postgres.h"
#include "libpq/pqcomm.h"
-#ifdef HAVE_ENDIAN_H
-#include <endian.h>
-#endif
-
-/* --------------------------------------------------------------------- */
-/* These definitions for ntoh/hton are the other way around from the
- * default system definitions, so we roll our own here.
+/*
+ * The backend supports the old little endian byte order and the current
+ * network byte order.
*/
+#ifndef FRONTEND
+
+#include "libpq/libpq-be.h"
+
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#endif
+
#ifndef BYTE_ORDER
#error BYTE_ORDER must be defined as LITTLE_ENDIAN, BIG_ENDIAN or PDP_ENDIAN
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
-#define ntoh_s(n) n
-#define ntoh_l(n) n
-#define hton_s(n) n
-#define hton_l(n) n
-#else /* BYTE_ORDER != LITTLE_ENDIAN */
+
+#define ntoh_s(n) n
+#define ntoh_l(n) n
+#define hton_s(n) n
+#define hton_l(n) n
+
+#else
#if BYTE_ORDER == BIG_ENDIAN
-#define ntoh_s(n) (u_short)(((u_char *)&n)[1] << 8 \
- | ((u_char *)&n)[0])
-#define ntoh_l(n) (uint32) (((u_char *)&n)[3] << 24 \
- | ((u_char *)&n)[2] << 16 \
- | ((u_char *)&n)[1] << 8 \
- | ((u_char *)&n)[0])
-#define hton_s(n) (ntoh_s(n))
-#define hton_l(n) (ntoh_l(n))
+
+#define ntoh_s(n) (uint16)(((u_char *)&n)[1] << 8 \
+ | ((u_char *)&n)[0])
+#define ntoh_l(n) (uint32)(((u_char *)&n)[3] << 24 \
+ | ((u_char *)&n)[2] << 16 \
+ | ((u_char *)&n)[1] << 8 \
+ | ((u_char *)&n)[0])
+#define hton_s(n) (ntoh_s(n))
+#define hton_l(n) (ntoh_l(n))
+
#else
-/* BYTE_ORDER != BIG_ENDIAN */
#if BYTE_ORDER == PDP_ENDIAN
+
#error PDP_ENDIAN macros not written yet
+
#else
-/* BYTE_ORDER != anything known */
+
#error BYTE_ORDER not defined as anything understood
-#endif /* BYTE_ORDER == PDP_ENDIAN */
-#endif /* BYTE_ORDER == BIG_ENDIAN */
-#endif /* BYTE_ORDER == LITTLE_ENDIAN */
+
+#endif
+#endif
+#endif
+
+#endif
+
/* --------------------------------------------------------------------- */
int
pqPutShort(int integer, FILE *f)
{
- int retval = 0;
- u_short n,
- s;
+ uint16 n;
+
+#ifdef FRONTEND
+ n = htons((uint16)integer);
+#else
+ n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_s(integer) : htons((uint16)integer));
+#endif
- s = integer;
- n = hton_s(s);
- if (fwrite(&n, sizeof(u_short), 1, f) != 1)
- retval = EOF;
+ if (fwrite(&n, 2, 1, f) != 1)
+ return EOF;
- return retval;
+ return 0;
}
/* --------------------------------------------------------------------- */
int
pqPutLong(int integer, FILE *f)
{
- int retval = 0;
- uint32 n;
+ uint32 n;
- n = hton_l(integer);
- if (fwrite(&n, sizeof(uint32), 1, f) != 1)
- retval = EOF;
+#ifdef FRONTEND
+ n = htonl((uint32)integer);
+#else
+ n = ((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? hton_l(integer) : htonl((uint32)integer));
+#endif
- return retval;
+ if (fwrite(&n, 4, 1, f) != 1)
+ return EOF;
+
+ return 0;
}
/* --------------------------------------------------------------------- */
int
pqGetShort(int *result, FILE *f)
{
- int retval = 0;
- u_short n;
+ uint16 n;
- if (fread(&n, sizeof(u_short), 1, f) != 1)
- retval = EOF;
+ if (fread(&n, 2, 1, f) != 1)
+ return EOF;
+
+#ifdef FRONTEND
+ *result = (int)ntohs(n);
+#else
+ *result = (int)((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_s(n) : ntohs(n));
+#endif
- *result = ntoh_s(n);
- return retval;
+ return 0;
}
/* --------------------------------------------------------------------- */
int
pqGetLong(int *result, FILE *f)
{
- int retval = 0;
- uint32 n;
+ uint32 n;
- if (fread(&n, sizeof(uint32), 1, f) != 1)
- retval = EOF;
+ if (fread(&n, 4, 1, f) != 1)
+ return EOF;
- *result = ntoh_l(n);
- return retval;
+#ifdef FRONTEND
+ *result = (int)ntohl(n);
+#else
+ *result = (int)((PG_PROTOCOL_MAJOR(FrontendProtocol) == 0) ? ntoh_l(n) : ntohl(n));
+#endif
+
+ return 0;
}
/* --------------------------------------------------------------------- */
-/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s.
+/* pqGetNBytes: Read a chunk of exactly len bytes in buffer s (which must be 1
+ byte longer) and terminate it with a '\0'.
Return 0 if ok.
*/
int
pqGetNBytes(char *s, size_t len, FILE *f)
{
- int cnt;
+ int cnt;
if (f == NULL)
return EOF;
cnt = fread(s, 1, len, f);
s[cnt] = '\0';
- /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
return (cnt == len) ? 0 : EOF;
}
@@ -126,7 +154,7 @@ int
pqPutNBytes(const char *s, size_t len, FILE *f)
{
if (f == NULL)
- return 0;
+ return EOF;
if (fwrite(s, 1, len, f) != len)
return EOF;
@@ -138,15 +166,27 @@ pqPutNBytes(const char *s, size_t len, FILE *f)
int
pqGetString(char *s, size_t len, FILE *f)
{
- int c;
+ int c;
if (f == NULL)
return EOF;
- while (len-- && (c = getc(f)) != EOF && c)
- *s++ = c;
+ /*
+ * Keep on reading until we get the terminating '\0' and discard those
+ * bytes we don't have room for.
+ */
+
+ while ((c = getc(f)) != EOF && c != '\0')
+ if (len > 1)
+ {
+ *s++ = c;
+ len--;
+ }
+
*s = '\0';
- /* mjl: actually needs up to len+1 bytes, is this okay? XXX */
+
+ if (c == EOF)
+ return EOF;
return 0;
}
@@ -183,5 +223,3 @@ pqPutByte(int c, FILE *f)
return (putc(c, f) == c) ? 0 : EOF;
}
-
-/* --------------------------------------------------------------------- */
diff --git a/src/backend/libpq/pqpacket.c b/src/backend/libpq/pqpacket.c
index b62eb3ee36..0a00a97ec6 100644
--- a/src/backend/libpq/pqpacket.c
+++ b/src/backend/libpq/pqpacket.c
@@ -8,36 +8,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.12 1997/12/09 03:10:51 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/Attic/pqpacket.c,v 1.13 1998/01/26 01:41:12 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
-/* NOTES
- * This is the module that understands the lowest-level part
- * of the communication protocol. All of the trickiness in
- * this module is for making sure that non-blocking I/O in
- * the Postmaster works correctly. Check the notes in PacketRecv
- * on non-blocking I/O.
- *
- * Data Structures:
- * Port has two important functions. (1) It records the
- * sock/addr used in communication. (2) It holds partially
- * read in messages. This is especially important when
- * we haven't seen enough to construct a complete packet
- * header.
- *
- * PacketBuf -- None of the clients of this module should know
- * what goes into a packet hdr (although they know how big
- * it is). This routine is in charge of host to net order
- * conversion for headers. Data conversion is someone elses
- * responsibility.
- *
- * IMPORTANT: these routines are called by backends, clients, and
- * the Postmaster.
- *
- */
+
#include <stdio.h>
#include <unistd.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
@@ -50,260 +28,158 @@
#include <storage/ipc.h>
#include <libpq/libpq.h>
+
/*
- * PacketReceive -- receive a packet on a port.
- *
- * RETURNS: connection id of the packet sender, if one
- * is available.
- *
+ * Set up a packet read for the postmaster event loop.
*/
-int
-PacketReceive(Port *port, /* receive port */
- PacketBuf *buf, /* MAX_PACKET_SIZE-worth of buffer space */
- bool nonBlocking) /* NON_BLOCKING or BLOCKING i/o */
+
+void PacketReceiveSetup(Packet *pkt, void (*iodone)(), char *arg)
{
- PacketLen max_size = sizeof(PacketBuf);
- PacketLen cc; /* character count -- bytes recvd */
- PacketLen packetLen; /* remaining packet chars to read */
- Addr tmp; /* curr recv buf pointer */
- int hdrLen;
- int flag;
- int decr;
+ pkt->nrtodo = sizeof (pkt->len);
+ pkt->ptr = (char *)&pkt->len;
+ pkt->iodone = iodone;
+ pkt->arg = arg;
+ pkt->state = ReadingPacketLength;
+}
- hdrLen = sizeof(buf->len);
- if (nonBlocking == NON_BLOCKING)
- {
- flag = MSG_PEEK;
- decr = 0;
- }
- else
- {
- flag = 0;
- decr = hdrLen;
- }
+/*
+ * Read a packet fragment. Return STATUS_OK if the connection should stay
+ * open.
+ */
- /*
- * Assume port->nBytes is zero unless we were interrupted during
- * non-blocking I/O. This first recv() is to get the hdr information
- * so we know how many bytes to read. Life would be very complicated
- * if we read too much data (buffering).
- */
- tmp = ((Addr) buf) + port->nBytes;
+int PacketReceiveFragment(Packet *pkt, int sock)
+{
+ int got;
- if (port->nBytes >= hdrLen)
+ if ((got = read(sock,pkt->ptr,pkt->nrtodo)) > 0)
{
- packetLen = ntohl(buf->len) - port->nBytes;
- }
- else
- {
- /* peeking into the incoming message */
- cc = recv(port->sock, (char *) &(buf->len), hdrLen, flag);
- if (cc < hdrLen)
+ pkt->nrtodo -= got;
+ pkt->ptr += got;
+
+ /* See if we have got what we need for the packet length. */
+
+ if (pkt->nrtodo == 0 && pkt->state == ReadingPacketLength)
{
- /* if cc is negative, the system call failed */
- if (cc < 0)
- {
- return (STATUS_ERROR);
- }
+ pkt->len = ntohl(pkt->len);
- /*
- * cc == 0 means the connection was broken at the other end.
- */
- else if (!cc)
+ if (pkt->len < sizeof (pkt->len) ||
+ pkt->len > sizeof (pkt->len) + sizeof (pkt->pkt))
{
- return (STATUS_INVALID);
+ PacketSendError(pkt,"Invalid packet length");
+ return STATUS_OK;
}
- else
- {
- /*
- * Worst case. We didn't even read in enough data to get
- * the header length. since we are using a data stream,
- * this happens only if the client is mallicious.
- *
- * Don't save the number of bytes we've read so far. Since we
- * only peeked at the incoming message, the kernel is
- * going to keep it for us.
- */
- return (STATUS_NOT_DONE);
- }
+ /* Set up for the rest of the packet. */
+
+ pkt->nrtodo = pkt->len - sizeof (pkt->len);
+ pkt->ptr = (char *)&pkt->pkt;
+ pkt->state = ReadingPacket;
}
- else
- {
- /*
- * This is an attempt to shield the Postmaster from mallicious
- * attacks by placing tighter restrictions on the reported
- * packet length.
- *
- * Check for negative packet length
- */
- if ((buf->len) <= 0)
- {
- return (STATUS_INVALID);
- }
+ /* See if we have got what we need for the packet. */
- /*
- * Check for oversize packet
- */
- if ((ntohl(buf->len)) > max_size)
- {
- return (STATUS_INVALID);
- }
+ if (pkt->nrtodo == 0 && pkt->state == ReadingPacket)
+ {
+ pkt->state = Idle;
- /*
- * great. got the header. now get the true length (including
- * header size).
- */
- packetLen = ntohl(buf->len);
+ /* Special case to close the connection. */
- /*
- * if someone is sending us junk, close the connection
- */
- if (packetLen > max_size)
- {
- port->nBytes = packetLen;
- return (STATUS_BAD_PACKET);
- }
- packetLen -= decr;
- tmp += decr - port->nBytes;
+ if (pkt->iodone == NULL)
+ return STATUS_ERROR;
+
+ (*pkt->iodone)(pkt->arg, pkt->len - sizeof (pkt->len),
+ (char *)&pkt->pkt);
}
+
+ return STATUS_OK;
}
- /*
- * Now that we know how big it is, read the packet. We read the
- * entire packet, since the last call was just a peek.
- */
- while (packetLen)
- {
- cc = read(port->sock, tmp, packetLen);
- if (cc < 0)
- return (STATUS_ERROR);
+ if (got == 0)
+ return STATUS_ERROR;
- /*
- * cc == 0 means the connection was broken at the other end.
- */
- else if (!cc)
- return (STATUS_INVALID);
+ if (errno == EINTR)
+ return STATUS_OK;
-/*
- fprintf(stderr,"expected packet of %d bytes, got %d bytes\n",
- packetLen, cc);
-*/
- tmp += cc;
- packetLen -= cc;
-
- /* if non-blocking, we're done. */
- if (nonBlocking && packetLen)
- {
- port->nBytes += cc;
- return (STATUS_NOT_DONE);
- }
- }
+ fprintf(stderr, "read() system call failed\n");
- port->nBytes = 0;
- return (STATUS_OK);
+ return STATUS_ERROR;
}
+
/*
- * PacketSend -- send a single-packet message.
- *
- * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
- * SIDE_EFFECTS: may block.
- * NOTES: Non-blocking writes would significantly complicate
- * buffer management. For now, we're not going to do it.
- *
+ * Set up a packet write for the postmaster event loop.
*/
-int
-PacketSend(Port *port,
- PacketBuf *buf,
- PacketLen len,
- bool nonBlocking)
+
+void PacketSendSetup(Packet *pkt, int nbytes, void (*iodone)(), char *arg)
{
- PacketLen doneLen;
+ pkt->nrtodo = nbytes;
+ pkt->ptr = (char *)&pkt->pkt;
+ pkt->iodone = iodone;
+ pkt->arg = arg;
+ pkt->state = WritingPacket;
+}
+
+
+/*
+ * Write a packet fragment. Return STATUS_OK if the connection should stay
+ * open.
+ */
- Assert(!nonBlocking);
- Assert(buf);
+int PacketSendFragment(Packet *pkt, int sock)
+{
+ int done;
- doneLen = write(port->sock, buf, len);
- if (doneLen < len)
+ if ((done = write(sock,pkt->ptr,pkt->nrtodo)) > 0)
{
- sprintf(PQerrormsg,
- "FATAL: PacketSend: couldn't send complete packet: errno=%d\n",
- errno);
- fputs(PQerrormsg, stderr);
- return (STATUS_ERROR);
+ pkt->nrtodo -= done;
+ pkt->ptr += done;
+
+ /* See if we have written the whole packet. */
+
+ if (pkt->nrtodo == 0)
+ {
+ pkt->state = Idle;
+
+ /* Special case to close the connection. */
+
+ if (pkt->iodone == NULL)
+ return STATUS_ERROR;
+
+ (*pkt->iodone)(pkt->arg);
+ }
+
+ return STATUS_OK;
}
- return (STATUS_OK);
-}
+ if (done == 0)
+ return STATUS_ERROR;
-/*
- * StartupInfo2PacketBuf -
- * convert the fields of the StartupInfo to a PacketBuf
- *
- */
-/* moved to src/libpq/fe-connect.c */
-/*
-PacketBuf*
-StartupInfo2PacketBuf(StartupInfo* s)
-{
- PacketBuf* res;
- char* tmp;
-
- res = (PacketBuf*)palloc(sizeof(PacketBuf));
- res->len = htonl(sizeof(PacketBuf));
- res->data[0] = '\0';
-
- tmp= res->data;
-
- strncpy(tmp, s->database, sizeof(s->database));
- tmp += sizeof(s->database);
- strncpy(tmp, s->user, sizeof(s->user));
- tmp += sizeof(s->user);
- strncpy(tmp, s->options, sizeof(s->options));
- tmp += sizeof(s->options);
- strncpy(tmp, s->execFile, sizeof(s->execFile));
- tmp += sizeof(s->execFile);
- strncpy(tmp, s->tty, sizeof(s->execFile));
-
- return res;
+ if (errno == EINTR)
+ return STATUS_OK;
+
+ fprintf(stderr, "write() system call failed\n");
+
+ return STATUS_ERROR;
}
-*/
+
/*
- * PacketBuf2StartupInfo -
- * convert the fields of the StartupInfo to a PacketBuf
- *
+ * Send an error message from the postmaster to the frontend.
*/
-/* moved to postmaster.c
-StartupInfo*
-PacketBuf2StartupInfo(PacketBuf* p)
+
+void PacketSendError(Packet *pkt, char *errormsg)
{
- StartupInfo* res;
- char* tmp;
-
- res = (StartupInfo*)palloc(sizeof(StartupInfo));
-
- res->database[0]='\0';
- res->user[0]='\0';
- res->options[0]='\0';
- res->execFile[0]='\0';
- res->tty[0]='\0';
-
- tmp= p->data;
- strncpy(res->database,tmp,sizeof(res->database));
- tmp += sizeof(res->database);
- strncpy(res->user,tmp, sizeof(res->user));
- tmp += sizeof(res->user);
- strncpy(res->options,tmp, sizeof(res->options));
- tmp += sizeof(res->options);
- strncpy(res->execFile,tmp, sizeof(res->execFile));
- tmp += sizeof(res->execFile);
- strncpy(res->tty,tmp, sizeof(res->tty));
-
- return res;
+ fprintf(stderr, "%s\n", errormsg);
+
+ pkt->pkt.em.data[0] = 'E';
+ StrNCpy(&pkt->pkt.em.data[1], errormsg, sizeof (pkt->pkt.em.data) - 2);
+
+ /*
+ * The NULL i/o callback will cause the connection to be broken when
+ * the error message has been sent.
+ */
+
+ PacketSendSetup(pkt, strlen(pkt->pkt.em.data) + 1, NULL, NULL);
}
-*/