From 6af92701d126488b3e8ca4e65c6cda60cc91b328 Mon Sep 17 00:00:00 2001 From: Calvin Buckley Date: Fri, 17 Jul 2026 13:41:38 -0300 Subject: [PATCH] odbc: Quote spaces in UID/PWD appended to connection string Drivers have no standard parsing, and may react weirdly to spaces in a connection string. When we append the UID/PWD parameters for the user and pass parameters of `odbc_(p)connect` or the PDO constructor, add spaces to the list of characters that require quoting. This fixes issues related to significant whitespace possibly not being parsed in a username or password, or having whitespace mangle parsing of a connection string. Note that there is no security impact because in order to do something interesting, you must be able to control the ';=' characters, and we already quote in those cases. --- ext/odbc/tests/odbc_utils.phpt | 14 +++++++++++++- main/php_odbc_utils.c | 7 ++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ext/odbc/tests/odbc_utils.phpt b/ext/odbc/tests/odbc_utils.phpt index 05d23e78aaed..613749cf0d86 100644 --- a/ext/odbc/tests/odbc_utils.phpt +++ b/ext/odbc/tests/odbc_utils.phpt @@ -17,11 +17,14 @@ $with_end_curly2 = "{foo}bar}"; // 2. See $with_end_curly2; should_quote doesn't care about if the string is already quoted. $with_end_curly3 = "{foo}}bar}"; // 1. No, it's not quoted. -// 2. It doesn't need to be quoted because of no s +// 2. It doesn't need to be quoted because of no special characters. $with_no_end_curly1 = "foobar"; // 1. Yes, it is quoted and any characters are properly escaped. // 2. See $with_end_curly2. $with_no_end_curly2 = "{foobar}"; +// 1. No, it's not quoted. +// 2. Yes, spaces should be quoted, as drivers can interpret them differently. +$with_spaces = " foobar "; echo "# Is quoted?\n"; echo "With end curly brace 1: "; @@ -34,6 +37,8 @@ echo "Without end curly brace 1: "; var_dump(odbc_connection_string_is_quoted($with_no_end_curly1)); echo "Without end curly brace 2: "; var_dump(odbc_connection_string_is_quoted($with_no_end_curly2)); +echo "With spaces: "; +var_dump(odbc_connection_string_is_quoted($with_spaces)); echo "# Should quote?\n"; echo "With end curly brace 1: "; @@ -46,6 +51,8 @@ echo "Without end curly brace 1: "; var_dump(odbc_connection_string_should_quote($with_no_end_curly1)); echo "Without end curly brace 2: "; var_dump(odbc_connection_string_should_quote($with_no_end_curly2)); +echo "With spaces: "; +var_dump(odbc_connection_string_should_quote($with_spaces)); echo "# Quote?\n"; echo "With end curly brace 1: "; @@ -58,6 +65,8 @@ echo "Without end curly brace 1: "; var_dump(odbc_connection_string_quote($with_no_end_curly1)); echo "Without end curly brace 2: "; var_dump(odbc_connection_string_quote($with_no_end_curly2)); +echo "With spaces: "; +var_dump(odbc_connection_string_quote($with_spaces)); ?> --EXPECTF-- @@ -67,15 +76,18 @@ With end curly brace 2: bool(false) With end curly brace 3: bool(true) Without end curly brace 1: bool(false) Without end curly brace 2: bool(true) +With spaces: bool(false) # Should quote? With end curly brace 1: bool(true) With end curly brace 2: bool(true) With end curly brace 3: bool(true) Without end curly brace 1: bool(false) Without end curly brace 2: bool(true) +With spaces: bool(true) # Quote? With end curly brace 1: string(10) "{foo}}bar}" With end curly brace 2: string(13) "{{foo}}bar}}}" With end curly brace 3: string(15) "{{foo}}}}bar}}}" Without end curly brace 1: string(8) "{foobar}" Without end curly brace 2: string(11) "{{foobar}}}" +With spaces: string(12) "{ foobar }" diff --git a/main/php_odbc_utils.c b/main/php_odbc_utils.c index 5cba835f81e3..162a1eb31df2 100644 --- a/main/php_odbc_utils.c +++ b/main/php_odbc_utils.c @@ -64,12 +64,17 @@ PHPAPI bool php_odbc_connstr_is_quoted(const char *str) * attribute values that contain the characters []{}(),;?*=!@ not enclosed * with braces should be avoided." * + * We also add spaces too, as driver connection string parameter parsing isn't + * standardized and can be quite sloppy; it can lead to significant whitespace + * not being parsed or confusing parsing of different sections. Note that this + * lacks security impact as we already quote the ';=' characters when parsing. + * * Note that it assumes that the string is *not* already quoted. You should * check beforehand. */ PHPAPI bool php_odbc_connstr_should_quote(const char *str) { - return strpbrk(str, "[]{}(),;?*=!@") != NULL; + return strpbrk(str, "[]{}(),;?*=!@ ") != NULL; } /**