From 0a73f69cb4842f46c1a080b3375b0f268ba1e5de Mon Sep 17 00:00:00 2001
From: Barry Lind <barry@xythos.com>
Date: Tue, 22 Jul 2003 05:17:09 +0000
Subject: [PATCH] Fix to prevent SQL injection attacks for code calling
 setObject(int,Object,int) where Object is a user supplied String and the type
 is a numeric type (i.e. INTEGER,LONG,etc). Also applied a patch from Kim Ho
 that fixes compile problems under jdk1.2

 Modified Files:
 	jdbc/org/postgresql/Driver.java.in
 	jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
---
 .../jdbc/org/postgresql/Driver.java.in        |  4 +-
 .../jdbc1/AbstractJdbc1Statement.java         | 64 ++++++++++++-------
 2 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/src/interfaces/jdbc/org/postgresql/Driver.java.in b/src/interfaces/jdbc/org/postgresql/Driver.java.in
index de064bb8cfb..16f0d99c06e 100644
--- a/src/interfaces/jdbc/org/postgresql/Driver.java.in
+++ b/src/interfaces/jdbc/org/postgresql/Driver.java.in
@@ -6,7 +6,7 @@
  * Copyright (c) 2003, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/Driver.java.in,v 1.32 2003/07/21 20:48:31 barry Exp $
+ *	  $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/Driver.java.in,v 1.33 2003/07/22 05:17:09 barry Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -503,6 +503,6 @@ public class Driver implements java.sql.Driver
 
 
 	//The build number should be incremented for every new build
-	private static int m_buildNumber = 206;
+	private static int m_buildNumber = 207;
 
 }
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
index 9a5b5203a15..c8af729b9aa 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
@@ -25,7 +25,7 @@ import java.sql.Timestamp;
 import java.sql.Types;
 import java.util.Vector;
 
-/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.27 2003/07/09 05:12:04 barry Exp $
+/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.28 2003/07/22 05:17:09 barry Exp $
  * This class defines methods of the jdbc1 specification.  This class is
  * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
  * methods.  The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
@@ -1035,22 +1035,37 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 			{
 				sbuf.setLength(0);
 				sbuf.ensureCapacity(x.length() + (int)(x.length() / 10));
-				int i;
-
 				sbuf.append('\'');
-				for (i = 0 ; i < x.length() ; ++i)
-				{
-					char c = x.charAt(i);
-					if (c == '\\' || c == '\'')
-						sbuf.append((char)'\\');
-					sbuf.append(c);
-				}
+				escapeString(x, sbuf);
 				sbuf.append('\'');
 				bind(parameterIndex, sbuf.toString(), type);
 			}
 		}
 	}
 
+    private String escapeString(String p_input) {
+        // use the shared buffer object. Should never clash but this makes
+        // us thread safe!
+        synchronized (sbuf)
+        {
+            sbuf.setLength(0);
+            sbuf.ensureCapacity(p_input.length());
+            escapeString(p_input, sbuf);
+            return sbuf.toString();
+        }
+    }
+
+    private void escapeString(String p_input, StringBuffer p_output) {
+        for (int i = 0 ; i < p_input.length() ; ++i)
+        {
+            char c = p_input.charAt(i);
+            if (c == '\\' || c == '\'')
+                p_output.append((char)'\\');
+            p_output.append(c);
+        }
+    }
+
+
 	/*
 	 * Set a parameter to a Java array of bytes.  The driver converts this
 	 * to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
@@ -1467,7 +1482,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 				if (x instanceof Boolean)
 					bind(parameterIndex,((Boolean)x).booleanValue() ? "1" :"0", PG_BOOLEAN);
 				else
-					bind(parameterIndex, x.toString(), PG_INTEGER);
+					bind(parameterIndex, escapeString(x.toString()), PG_INTEGER);
 				break;
 			case Types.TINYINT:
 			case Types.SMALLINT:
@@ -1480,7 +1495,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 				if (x instanceof Boolean)
 					bind(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0", PG_BOOLEAN);
 				else
-					bind(parameterIndex, x.toString(), PG_NUMERIC);
+					bind(parameterIndex, escapeString(x.toString()), PG_NUMERIC);
 				break;
 			case Types.CHAR:
 			case Types.VARCHAR:
@@ -1913,15 +1928,12 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 	}
 
 	/*
-	 * There are a lot of setXXX classes which all basically do
-	 * the same thing.	We need a method which actually does the
-	 * set for us.
-	 *
-	 * @param paramIndex the index into the inString
-	 * @param s a string to be stored
-	 * @exception SQLException if something goes wrong
+     * Note if s is a String it should be escaped by the caller to avoid SQL
+     * injection attacks.  It is not done here for efficency reasons as
+     * most calls to this method do not require escaping as the source
+     * of the string is known safe (i.e. Integer.toString())
 	 */
-	protected void bind(int paramIndex, Object s, String type) throws SQLException
+	private void bind(int paramIndex, Object s, String type) throws SQLException
 	{
 		if (paramIndex < 1 || paramIndex > m_binds.length)
 			throw new PSQLException("postgresql.prep.range");
@@ -2072,7 +2084,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 		if (timezoneLocation>7 && timezoneLocation+3 == s.length())
 		{
 			timezone = Integer.parseInt(s.substring(timezoneLocation+1,s.length()));
-			localoffset = java.util.Calendar.getInstance().getTimeZone().getOffset(millis);
+			localoffset = java.util.Calendar.getInstance().getTimeZone().getRawOffset();
+			if (java.util.Calendar.getInstance().getTimeZone().inDaylightTime(new java.sql.Date(millis)))
+				localoffset += 60*60*1000;
 			if (s.charAt(timezoneLocation)=='+')
 				timezone*=-1;
 		}
@@ -2101,7 +2115,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 		if (timezoneLocation != -1 && timezoneLocation+3 == s.length())
 		{
 			timezone = Integer.parseInt(s.substring(timezoneLocation+1,s.length()));
-			localoffset = java.util.Calendar.getInstance().getTimeZone().getOffset(millis);
+			localoffset = java.util.Calendar.getInstance().getTimeZone().getRawOffset();
+			if (java.util.Calendar.getInstance().getTimeZone().inDaylightTime(new java.sql.Date(millis)))
+				localoffset += 60*60*1000;
 			if (s.charAt(timezoneLocation)=='+')
 				timezone*=-1;
 		}
@@ -2146,7 +2162,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
 		if (timezoneLocation>8 && timezoneLocation+3 == s.length())
 		{
 			timezone = Integer.parseInt(s.substring(timezoneLocation+1,s.length()));
-			localoffset = java.util.Calendar.getInstance().getTimeZone().getOffset(millis);
+			localoffset = java.util.Calendar.getInstance().getTimeZone().getRawOffset();
+			if (java.util.Calendar.getInstance().getTimeZone().inDaylightTime(new java.sql.Date(millis)))
+				localoffset += 60*60*1000;
 			if (s.charAt(timezoneLocation)=='+')
 				timezone*=-1;
 		}
-- 
GitLab