File c3p0-java-e14cbd.patch of Package c3p0.43042

From e14cbd8166e423e2e9a9d6f08b2add3433492d6e Mon Sep 17 00:00:00 2001
From: Steve Waldman <swaldman@mchange.com>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: Reimplement userOverridesAsString without relying on unnecessarily
 dangerous Java Serialization.

--- c3p0-0.9.5.5.src/src/java/com/mchange/v2/c3p0/cfg/C3P0Config.java.orig
+++ c3p0-0.9.5.5.src/src/java/com/mchange/v2/c3p0/cfg/C3P0Config.java
@@ -46,6 +46,7 @@
 import java.lang.reflect.Method;
 import com.mchange.v1.lang.BooleanUtils;
 import com.mchange.v2.c3p0.C3P0Registry;
+import com.mchange.v2.csv.MalformedCsvException;
 
 //all internal maps should be HashMaps (the implementation presumes HashMaps)
 
@@ -474,7 +475,7 @@
 	return (out.isEmpty() ? null : out );
     }
 
-    public static String getUserOverridesAsString(String configName) throws IOException
+    public static String getUserOverridesAsString(String configName) throws IOException, MalformedCsvException
     {
 	Map userOverrides = getUserOverrides( configName );
 	if (userOverrides == null)
 
--- c3p0-0.9.5.5.src/src/java/com/mchange/v2/c3p0/impl/C3P0ImplUtils.java.orig
+++ c3p0-0.9.5.5.src/src/java/com/mchange/v2/c3p0/impl/C3P0ImplUtils.java
@@ -36,13 +36,14 @@
 package com.mchange.v2.c3p0.impl;
 
 import java.beans.*;
+import java.io.*;
 import java.util.*;
 import java.lang.reflect.*;
 
 import com.mchange.v2.c3p0.*;
 import com.mchange.v2.c3p0.cfg.*;
 
-import java.io.IOException;
+import com.mchange.v2.csv.*;
 import java.sql.Connection;
 import java.sql.SQLException;
 import com.mchange.lang.ByteUtils;
@@ -299,6 +300,12 @@
 
     private final static String HASM_HEADER = "HexAsciiSerializedMap";
 
+    /*
+    // Java Serialization-based userOverridesAsString format creates an unnecessary attack surface for
+    // placing malicious objects in the serialized format and provoking deserialization.
+    //
+    // We'll transition to a simpler, less dangerous format.
+
     public static String createUserOverridesAsString( Map userOverrides ) throws IOException
     {
 	StringBuffer sb = new StringBuffer();
@@ -320,6 +327,111 @@
 	else
 	    return Collections.EMPTY_MAP;
     }
+    */
+
+    // Quote a single CSV item: wrap in double-quotes and escape interior double-quotes as ""
+    private static String quoteCsvItem( String s )
+    {
+	if (s == null) return "\"\"";
+	return "\"" + s.replace("\"", "\"\"") + "\"";
+    }
+
+    // Generate a CSV line from an array of items, all quoted, without a line terminator
+    private static String generateCsvLine( String[] items )
+    {
+	StringBuilder sb = new StringBuilder();
+	for (int i = 0; i < items.length; ++i)
+	    {
+		if (i > 0) sb.append(',');
+		sb.append( quoteCsvItem( items[i] ) );
+	    }
+	return sb.toString();
+    }
+
+    // we serialize user overrides to "ragged CSV".
+    // CSV lines containing only a single element are interpreted as the user for whom we are overriding config
+    // lines following containing two elements are the config param overrides for that user.
+    public static String createUserOverridesAsString( Map userOverrides ) throws IOException, MalformedCsvException
+    {
+	Writer w = new StringWriter();
+	for (Object o : userOverrides.keySet())
+	    {
+		// we don't check the type. We're treating this as basically an assertion, in our old-school, loosely typed Java
+		// we'll let the user see a ClassCastException if something has been messed with
+		String user = (String) o;
+		w.append( quoteCsvItem( user ) );
+		w.append("\r\n");
+		Map userProps = (Map) userOverrides.get(user);
+		String[] propNamePropValAsString = new String[2];
+		for (Object pn : userProps.keySet())
+		    {
+			propNamePropValAsString[0] = (String) pn;
+			propNamePropValAsString[1] = (String) userProps.get(pn);
+			w.append( generateCsvLine( propNamePropValAsString ) );
+			w.append("\r\n");
+		    }
+	    }
+	return w.toString();
+    }
+
+    private static Map parseSingleUserMap(String userOverridesAsString, BufferedReader br, String[] nextUserHolder) throws IOException, MalformedCsvException
+    {
+	Map out = new HashMap();
+	nextUserHolder[0] = null;
+	String line = FastCsvUtils.csvReadLine(br);
+	if (line == null)
+	    {
+		nextUserHolder[0] = null;
+		return Collections.EMPTY_MAP;
+	    }
+	else
+	    {
+		do
+		    {
+			String[] items = FastCsvUtils.splitRecord( line );
+			switch ( items.length )
+			    {
+			    case 2: // this is an expected property override line
+				out.put(items[0],items[1]);
+				break;
+			    case 1: // this is the next user name
+				nextUserHolder[0] = items[0];
+				break;
+			    default:
+				throw new IOException("Unexpected CSV line in userOverridesAsString ('" + line + "'). All line should have 1 or 2 items:\r\n" + userOverridesAsString);
+			    }
+		    }
+		while (nextUserHolder[0] == null && (line = FastCsvUtils.csvReadLine(br)) != null); // either EOL or discovery of next user terminates
+		return Collections.unmodifiableMap(out);
+	    }
+    }
+
+    public static Map parseUserOverridesAsString( String userOverridesAsString ) throws IOException, MalformedCsvException
+    {
+	if ( userOverridesAsString == null )
+	    return Collections.EMPTY_MAP;
+	String[] nextUserHolder = new String[1];
+	BufferedReader br = new BufferedReader(new StringReader(userOverridesAsString));
+	String line = FastCsvUtils.csvReadLine(br);
+	if ( line == null )
+	    return Collections.EMPTY_MAP;
+	else
+	    {
+		Map out = new HashMap();
+		String[] items = FastCsvUtils.splitRecord(line);
+		if (items.length != 1)
+		    throw new IOException("Cannot parse userOverridesAsString, one element line naming the user should come before other data:\r\n" + userOverridesAsString);
+		String username = items[0];
+		do
+		    {
+			Map overrides = parseSingleUserMap(userOverridesAsString, br, nextUserHolder);
+			out.put(username, overrides);
+			username = nextUserHolder[0];
+		    }
+		while (username != null);
+		return Collections.unmodifiableMap(out);
+	    }
+    }
 
     /**
      *  never intended to be called. we just want a compiler error if somehow we are building/code-generating 
openSUSE Build Service is sponsored by