diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 7be74c58a78b0a069787b54994e57a36768daf79..d036a22f6e5bf45d839956a6e8d6abbc5b968b46 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.90 2002/09/04 20:31:18 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.91 2002/09/04 23:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -563,12 +563,11 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re
 	{
 		sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD);
 		if (pq_eof() == EOF || pq_getint(&len, 4) == EOF)
-		{
 			return PAM_CONV_ERR;	/* client didn't want to send password */
-		}
 
 		initStringInfo(&buf);
-		pq_getstr(&buf);
+		if (pq_getstr_bounded(&buf, 1000) == EOF)
+			return PAM_CONV_ERR;	/* EOF while reading password */
 
 		/* Do not echo failed password to logs, for security. */
 		elog(DEBUG5, "received PAM packet");
@@ -707,7 +706,7 @@ recv_and_check_password_packet(Port *port)
 		return STATUS_EOF;		/* client didn't want to send password */
 
 	initStringInfo(&buf);
-	if (pq_getstr(&buf) == EOF) /* receive password */
+	if (pq_getstr_bounded(&buf, 1000) == EOF) /* receive password */
 	{
 		pfree(buf.data);
 		return STATUS_EOF;
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index d7dca96528c7fb876f1b8381f5a05064ef385dc2..6baf568eea53a7b2619b33eb769ccd997b58d582 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -1,6 +1,6 @@
 /*-------------------------------------------------------------------------
  *
- * be-connect.c
+ * be-secure.c
  *	  functions related to setting up a secure connection to the frontend.
  *	  Secure connections are expected to provide confidentiality,
  *	  message integrity and endpoint authentication.
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.13 2002/09/04 20:31:19 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/be-secure.c,v 1.14 2002/09/04 23:31:34 tgl Exp $
  *
  *	  Since the server static private key ($DataDir/server.key)
  *	  will normally be stored unencrypted so that the database
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index c0d832bd3da2a824e142fc6997c641f979f86978..62e8bd44cd5e931f34799bfd9de2667f9f8b7708 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -29,7 +29,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: pqcomm.c,v 1.140 2002/09/04 20:31:19 momjian Exp $
+ *	$Id: pqcomm.c,v 1.141 2002/09/04 23:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -555,16 +555,24 @@ pq_getbytes(char *s, size_t len)
  *		The return value is placed in an expansible StringInfo.
  *		Note that space allocation comes from the current memory context!
  *
+ *		If maxlen is not zero, it is an upper limit on the length of the
+ *		string we are willing to accept.  We abort the connection (by
+ *		returning EOF) if client tries to send more than that.  Note that
+ *		since we test maxlen in the outer per-bufferload loop, the limit
+ *		is fuzzy: we might accept up to PQ_BUFFER_SIZE more bytes than
+ *		specified.  This is fine for the intended purpose, which is just
+ *		to prevent DoS attacks from not-yet-authenticated clients.
+ *
  *		NOTE: this routine does not do any character set conversion,
  *		even though it is presumably useful only for text, because
  *		no code in this module should depend on the encoding.
- *		See pq_getstr in pqformat.c for that.
+ *		See pq_getstr_bounded in pqformat.c for that.
  *
  *		returns 0 if OK, EOF if trouble
  * --------------------------------
  */
 int
-pq_getstring(StringInfo s)
+pq_getstring(StringInfo s, int maxlen)
 {
 	int			i;
 
@@ -572,7 +580,7 @@ pq_getstring(StringInfo s)
 	s->len = 0;
 	s->data[0] = '\0';
 
-	/* Read until we get the terminating '\0' */
+	/* Read until we get the terminating '\0' or overrun maxlen */
 	for (;;)
 	{
 		while (PqRecvPointer >= PqRecvLength)
@@ -594,10 +602,13 @@ pq_getstring(StringInfo s)
 		}
 
 		/* If we're here we haven't got the \0 in the buffer yet. */
-
 		appendBinaryStringInfo(s, PqRecvBuffer + PqRecvPointer,
 							   PqRecvLength - PqRecvPointer);
 		PqRecvPointer = PqRecvLength;
+
+		/* If maxlen is specified, check for overlength input. */
+		if (maxlen > 0 && s->len > maxlen)
+			return EOF;
 	}
 }
 
diff --git a/src/backend/libpq/pqformat.c b/src/backend/libpq/pqformat.c
index 278835f2093b79d9aafd117eb647d5aa41dcc0ff..5f5acb44435e587caabf4e7e9c109430cccd872b 100644
--- a/src/backend/libpq/pqformat.c
+++ b/src/backend/libpq/pqformat.c
@@ -16,7 +16,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: pqformat.c,v 1.24 2002/09/03 21:45:42 petere Exp $
+ *	$Id: pqformat.c,v 1.25 2002/09/04 23:31:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -38,10 +38,10 @@
  *		pq_puttextmessage - generate a character set-converted message in one step
  *
  * Message input:
- *		pq_getint		- get an integer from connection
- *		pq_getstr		- get a null terminated string from connection
- * pq_getstr performs character set conversion on the collected string.
- * Use the raw pqcomm.c routines pq_getstring or pq_getbytes
+ *		pq_getint			- get an integer from connection
+ *		pq_getstr_bounded	- get a null terminated string from connection
+ * pq_getstr_bounded performs character set conversion on the collected
+ * string.  Use the raw pqcomm.c routines pq_getstring or pq_getbytes
  * to fetch data without conversion.
  */
 
@@ -247,21 +247,23 @@ pq_getint(int *result, int b)
 }
 
 /* --------------------------------
- *		pq_getstr - get a null terminated string from connection
+ *		pq_getstr_bounded - get a null terminated string from connection
  *
  *		The return value is placed in an expansible StringInfo.
  *		Note that space allocation comes from the current memory context!
  *
+ *		The maxlen parameter is interpreted as per pq_getstring.
+ *
  *		returns 0 if OK, EOF if trouble
  * --------------------------------
  */
 int
-pq_getstr(StringInfo s)
+pq_getstr_bounded(StringInfo s, int maxlen)
 {
 	int			result;
 	char	   *p;
 
-	result = pq_getstring(s);
+	result = pq_getstring(s, maxlen);
 
 	p = (char *) pg_client_to_server((unsigned char *) s->data, s->len);
 	if (p != s->data)			/* actual conversion has been done? */
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 915b3222a07459b429d1865b57203e9c78281730..5e4db4d24300bedf793959271e83f71c5fcb0a44 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq.h,v 1.51 2002/06/20 20:29:49 momjian Exp $
+ * $Id: libpq.h,v 1.52 2002/09/04 23:31:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ extern int	StreamConnection(int server_fd, Port *port);
 extern void StreamClose(int sock);
 extern void pq_init(void);
 extern int	pq_getbytes(char *s, size_t len);
-extern int	pq_getstring(StringInfo s);
+extern int	pq_getstring(StringInfo s, int maxlen);
 extern int	pq_getbyte(void);
 extern int	pq_peekbyte(void);
 extern int	pq_putbytes(const char *s, size_t len);
diff --git a/src/include/libpq/pqformat.h b/src/include/libpq/pqformat.h
index b94cf7a151380900f5ce77605654a11c1587e642..829727c38f0dd756b966ceaad131881923845fdc 100644
--- a/src/include/libpq/pqformat.h
+++ b/src/include/libpq/pqformat.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqformat.h,v 1.12 2002/06/20 20:29:49 momjian Exp $
+ * $Id: pqformat.h,v 1.13 2002/09/04 23:31:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,8 @@ extern void pq_endmessage(StringInfo buf);
 extern int	pq_puttextmessage(char msgtype, const char *str);
 
 extern int	pq_getint(int *result, int b);
-extern int	pq_getstr(StringInfo s);
+extern int	pq_getstr_bounded(StringInfo s, int maxlen);
+
+#define pq_getstr(s)	pq_getstr_bounded(s, 0)
 
 #endif   /* PQFORMAT_H */