Skip to content

Commit 3646604

Browse files
grooverdannikic
authored andcommitted
Fix #78680: mysqlnd pam plugin missing terminating null
The PAM service requires the terminating null to be part of the communication. Tested with MariaDB-10.4(pam) and Percona Server 5.7.32(auth_pam_compat). Also changed MySQL Enterprise test to the server side plugin, authentication_pam as opposed to the client plugin mysql_clear_password. Add additional check for pamtest user and pam service file as all are required for the test. More importantly, test result should actually succeed. Thanks Geoff Montee for bug report. Closes GH-78680.
1 parent 44a80b6 commit 3646604

File tree

3 files changed

+55
-7
lines changed

3 files changed

+55
-7
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ PHP NEWS
55
- Core:
66
. Fixed #80706 (mail(): Headers after Bcc headers may be ignored). (cmb)
77

8+
- MySQLnd:
9+
. Fixed bug #78680 (mysqlnd's mysql_clear_password does not transmit
10+
null-terminated password). (Daniel Black)
11+
812
- MySQLi:
913
. Fixed bug #74779 (x() and y() truncating floats to integers). (cmb)
1014

ext/mysqli/tests/mysqli_auth_pam.phpt

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ if (!$res = $link->query("SHOW PLUGINS"))
1919

2020
$have_pam = false;
2121
while ($row = $res->fetch_assoc()) {
22-
if (isset($row['Name']) && ('mysql_clear_password' == $row['Name'])) {
23-
$have_pam = true;
22+
if (isset($row['Name']) && in_array($row['Name'], array('pam', 'authentication_pam', 'auth_pam_compat'))) {
23+
$have_pam = $row['Name'];
2424
break;
2525
}
2626
}
@@ -29,12 +29,54 @@ $res->close();
2929
if (!$have_pam)
3030
die("SKIP Server PAM plugin not installed");
3131

32+
if ($have_pam == 'pam') {
33+
/* MariaDB - needs system variable pam_use_cleartext_plugin=ON to be set */
34+
if (!$res = mysqli_query($link, 'SHOW GLOBAL VARIABLES LIKE "pam_use_cleartext_plugin"'))
35+
die(sprintf("SKIP MariaDB probe of GLOBAL VARIABLES failed [%d] %s\n",
36+
mysqli_errno($link), mysqli_error($link)));
37+
$pam_use_cleartext_plugin = mysqli_fetch_row($res);
38+
mysqli_free_result($res);
39+
if (!$pam_use_cleartext_plugin or $pam_use_cleartext_plugin[1]!='ON')
40+
die("SKIP Server setting pam_use_cleartext_plugin!=ON");
41+
42+
$pam_service = file_get_contents('/etc/pam.d/mysql');
43+
} elseif ($have_pam == 'authentication_pam') {
44+
/*
45+
required MySQL syntax:
46+
https://dev.mysql.com/doc/refman/8.0/en/pam-pluggable-authentication.html#pam-pluggable-authentication-usage
47+
*/
48+
$have_pam .= " AS 'mysql-unix'";
49+
$pam_service = file_get_contents('/etc/pam.d/mysql-unix');
50+
} else {
51+
$pam_service = file_get_contents('/etc/pam.d/mysql');
52+
}
53+
$auth = 0;
54+
$account = 0;
55+
foreach (explode("\n", $pam_service) as $line)
56+
{
57+
if (preg_match('/^auth/', $line)) {
58+
$auth = 1;
59+
} elseif (preg_match('/^account/', $line)) {
60+
$account = 1;
61+
}
62+
}
63+
if (!$auth) {
64+
die("SKIP pam service file missing 'auth' directive");
65+
}
66+
if (!$account) {
67+
die("SKIP pam service file missing 'account' directive");
68+
}
69+
70+
if (!posix_getpwnam('pamtest')) {
71+
die("SKIP no pamtest user");
72+
}
73+
/* Password of user 'pamtest' should be set to 'pamtest' */
3274

3375
mysqli_query($link, 'DROP USER pamtest');
3476
mysqli_query($link, 'DROP USER pamtest@localhost');
3577

36-
if (!mysqli_query($link, 'CREATE USER pamtest@"%" IDENTIFIED WITH mysql_clear_password') ||
37-
!mysqli_query($link, 'CREATE USER pamtest@"localhost" IDENTIFIED WITH mysql_clear_password')) {
78+
if (!mysqli_query($link, "CREATE USER pamtest@'%' IDENTIFIED WITH $have_pam") ||
79+
!mysqli_query($link, "CREATE USER pamtest@'localhost' IDENTIFIED WITH $have_pam")) {
3880
printf("skip Cannot create second DB user [%d] %s", mysqli_errno($link), mysqli_error($link));
3981
mysqli_close($link);
4082
die("skip CREATE USER failed");
@@ -88,6 +130,4 @@ max_execution_time=240
88130
mysqli_query($link, 'DROP USER pamtest@localhost');
89131
?>
90132
--EXPECTF--
91-
Warning: mysqli_real_connect(): (28000/1045): Access denied for user %s
92-
[001] Cannot connect to the server using host=%s
93133
done!

ext/mysqlnd/mysqlnd_auth.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,11 @@ mysqlnd_pam_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
652652
if (passwd && passwd_len) {
653653
ret = (zend_uchar*) zend_strndup(passwd, passwd_len);
654654
}
655-
*auth_data_len = passwd_len;
655+
/*
656+
Trailing null required. bug#78680
657+
https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_authentication_methods_clear_text_password.html
658+
*/
659+
*auth_data_len = passwd_len + 1;
656660

657661
return ret;
658662
}

0 commit comments

Comments
 (0)