Skip to content

Commit e6bb90c

Browse files
committed
Fix #62479: Some chars not parsed in passwords
This fixes an issue where backslashes and spaces aren't correctly parsed for passwords.
1 parent 3eb2b1a commit e6bb90c

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? 201?, PHP 5.3.29
44

5+
- PDO_pgsql:
6+
. Fixed bug #62479 (PDO-psql cannot connect if password contains spaces)
7+
58
12 Dec 2013, PHP 5.3.28
69

710
- Openssl:

ext/pdo_pgsql/pgsql_driver.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
10291029
pdo_pgsql_db_handle *H;
10301030
int ret = 0;
10311031
char *conn_str, *p, *e;
1032+
char *tmp_pass;
10321033
long connect_timeout = 30;
10331034

10341035
H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
@@ -1050,18 +1051,44 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
10501051
connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
10511052
}
10521053

1054+
if (dbh->password) {
1055+
if (dbh->password[0] != '\'' && dbh->password[strlen(dbh->password) - 1] != '\'') {
1056+
char *pwd = dbh->password;
1057+
int pos = 1;
1058+
1059+
tmp_pass = safe_emalloc(2, strlen(dbh->password), 3);
1060+
tmp_pass[0] = '\'';
1061+
1062+
while (*pwd != '\0') {
1063+
if (*pwd == '\\' || *pwd == '\'') {
1064+
tmp_pass[pos++] = '\\';
1065+
}
1066+
1067+
tmp_pass[pos++] = *pwd++;
1068+
}
1069+
1070+
tmp_pass[pos++] = '\'';
1071+
tmp_pass[pos] = '\0';
1072+
} else {
1073+
tmp_pass = dbh->password;
1074+
}
1075+
}
1076+
10531077
/* support both full connection string & connection string + login and/or password */
10541078
if (dbh->username && dbh->password) {
1055-
spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, dbh->password, connect_timeout);
1079+
spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, tmp_pass, connect_timeout);
10561080
} else if (dbh->username) {
10571081
spprintf(&conn_str, 0, "%s user=%s connect_timeout=%ld", dbh->data_source, dbh->username, connect_timeout);
10581082
} else if (dbh->password) {
1059-
spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, dbh->password, connect_timeout);
1083+
spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, tmp_pass, connect_timeout);
10601084
} else {
10611085
spprintf(&conn_str, 0, "%s connect_timeout=%ld", (char *) dbh->data_source, connect_timeout);
10621086
}
10631087

10641088
H->server = PQconnectdb(conn_str);
1089+
if (dbh->password && tmp_pass != dbh->password) {
1090+
efree(tmp_pass);
1091+
}
10651092

10661093
efree(conn_str);
10671094

ext/pdo_pgsql/tests/bug62479.phpt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
--TEST--
2+
PDO PgSQL Bug #62479 (PDO-psql cannot connect if password contains spaces)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
6+
require dirname(__FILE__) . '/config.inc';
7+
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
8+
PDOTest::skip();
9+
if (!isset($conf['ENV']['PDOTEST_DSN'])) die('no dsn found in env');
10+
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
11+
$rand = rand(5, 5);
12+
13+
// Assume that if we can't create a user, this test needs to be skipped
14+
$testQuery = "CREATE USER pdo_$rand WITH PASSWORD 'testpass'";
15+
$db->query($testQuery);
16+
$testQuery = "DROP USER pdo_$rand";
17+
$db->query($testQuery);
18+
?>
19+
--FILE--
20+
<?php
21+
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
22+
$pdo = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
23+
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
24+
$rand = rand(5, 400);
25+
$user = "pdo_$rand";
26+
$template = "CREATE USER $user WITH PASSWORD '%s'";
27+
$dropUser = "DROP USER $user";
28+
$testQuery = 'SELECT 1 as verification';
29+
30+
// Create temp user with space in password
31+
$sql = sprintf($template, 'my password');
32+
$pdo->query($sql);
33+
$testConn = new PDO($_ENV['PDOTEST_DSN'], $user, "my password");
34+
$result = $testConn->query($testQuery)->fetch();
35+
$check = $result[0];
36+
var_dump($check);
37+
38+
// Remove the user
39+
$pdo->query($dropUser);
40+
41+
// Create a user with a space and single quote
42+
$sql = sprintf($template, "my pass''word");
43+
$pdo->query($sql);
44+
45+
$testConn = new PDO($_ENV['PDOTEST_DSN'], $user, "my pass'word");
46+
$result = $testConn->query($testQuery)->fetch();
47+
$check = $result[0];
48+
var_dump($check);
49+
50+
// Remove the user
51+
$pdo->query($dropUser);
52+
?>
53+
--EXPECT--
54+
int(1)
55+
int(1)
56+

0 commit comments

Comments
 (0)