From 1834987fb6b705ec37abdb5a2804d79761f7fa56 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Fri, 7 Sep 2001 22:02:32 +0000
Subject: [PATCH] I've attached the fixed version of the patch below.  After
 the discussion on pgsql-hackers (especially the frightening memory dump in
 <12273.999562219@sss.pgh.pa.us>), we decided that it is best not to use
 identifiers from an untrusted source at all.  Therefore, all claims of the
 suitability of PQescapeString() for identifiers have been removed.

Florian Weimer
---
 doc/src/sgml/libpq.sgml         | 38 ++++++++++++++++++++-
 src/interfaces/libpq/fe-exec.c  | 58 ++++++++++++++++++++++++++++++++-
 src/interfaces/libpq/libpq-fe.h |  5 ++-
 3 files changed, 98 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 51f30802fc..56518805dd 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.68 2001/09/04 00:18:18 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.69 2001/09/07 22:02:32 momjian Exp $
 -->
 
  <chapter id="libpq">
@@ -827,6 +827,42 @@ as with a PGresult returned by libpq itself.
 </itemizedlist>
 </sect2>
 
+<sect2 id="libpq-exec-escape-string">
+  <title>Escaping strings for inclusion in SQL queries</title>
+<para>
+<function>PQescapeString</function>
+          Escapes a string for use within an SQL query.
+<synopsis>
+size_t PQescapeString (char *to, const char *from, size_t length);
+</synopsis>
+If you want to include strings which have been received
+from a source which is not trustworthy (for example, because they were
+transmitted across a network), you cannot directly include them in SQL
+queries for security reasons.  Instead, you have to quote special
+characters which are otherwise interpreted by the SQL parser.
+</para>
+<para>
+<function>PQescapeString</> performs this operation.  The
+<parameter>from</> points to the first character of the string which
+is to be escaped, and the <parameter>length</> parameter counts the
+number of characters in this string (a terminating NUL character is
+neither necessary nor counted).  <parameter>to</> shall point to a
+buffer which is able to hold at least one more character than twice
+the value of <parameter>length</>, otherwise the behavior is
+undefined.  A call to <function>PQescapeString</> writes an escaped
+version of the <parameter>from</> string to the <parameter>to</>
+buffer, replacing special characters so that they cannot cause any
+harm, and adding a terminating NUL character.  The single quotes which
+must surround PostgreSQL string literals are not part of the result
+string.
+</para>
+<para>
+<function>PQescapeString</> returns the number of characters written
+to <parameter>to</>, not including the terminating NUL character.
+Behavior is undefined when the <parameter>to</> and <parameter>from</>
+strings overlap.
+</para>
+
 <sect2 id="libpq-exec-select-info">
   <title>Retrieving SELECT Result Information</title>
 
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 4b67bdcf52..bdff56fe08 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.109 2001/09/06 02:54:56 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.110 2001/09/07 22:02:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,6 +56,62 @@ static int	getAnotherTuple(PGconn *conn, int binary);
 static int	getNotify(PGconn *conn);
 static int	getNotice(PGconn *conn);
 
+/* ---------------
+ * Escaping arbitrary strings to get valid SQL strings/identifiers.
+ *
+ * Replaces "\\" with "\\\\", "\0" with "\\0", and "'" with "''".
+ * length is the length of the buffer pointed to by
+ * from.  The buffer at to must be at least 2*length + 1 characters
+ * long.  A terminating NUL character is written.
+ * ---------------
+ */
+
+size_t
+PQescapeString (char *to, const char *from, size_t length)
+{
+	const char *source = from;
+	char *target = to;
+	unsigned int remaining = length;
+
+	while (remaining > 0) {
+		switch (*source) {
+		case '\0':
+			*target = '\\';
+			target++;
+			*target = '0';
+			/* target and remaining are updated below. */
+			break;
+			
+		case '\\':
+			*target = '\\';
+			target++;
+			*target = '\\';
+			/* target and remaining are updated below. */
+			break;
+
+		case '\'':
+			*target = '\'';
+			target++;
+			*target = '\'';
+			/* target and remaining are updated below. */
+			break;
+
+		default:
+			*target = *source;
+			/* target and remaining are updated below. */
+		}
+		source++;
+		target++;
+		remaining--;
+	}
+
+	/* Write the terminating NUL character. */
+	*target = '\0';
+	
+	return target - to;
+}
+
+
 
 /* ----------------
  * Space management for PGresult.
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 5faa576c08..d3b472f9cc 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.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: libpq-fe.h,v 1.73 2001/09/06 02:54:56 momjian Exp $
+ * $Id: libpq-fe.h,v 1.74 2001/09/07 22:02:32 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -251,6 +251,9 @@ extern		"C"
 
 /* === in fe-exec.c === */
 
+	/* Quoting strings before inclusion in queries. */
+	extern size_t PQescapeString (char *to, const char *from, size_t length);
+
 	/* Simple synchronous query */
 	extern PGresult *PQexec(PGconn *conn, const char *query);
 	extern PGnotify *PQnotifies(PGconn *conn);