From 509906b2a5e6fc6075219fbf6bde9c9089121e79 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 12 Jun 2023 23:47:42 +0200 Subject: [PATCH 1/2] Fix GH-11438: mysqlnd fails to authenticate with sha256_password accounts using passwords longer than 19 characters https://dev.mysql.com/doc/dev/mysql-server/latest/page_caching_sha2_authentication_exchanges.html tells us that the nonce used in this authentication method is 20 bytes long. However, we might receive additional scramble data in php_mysqlnd_greet_read not used in this method. On my test setup, I received 21 bytes (20 bytes + '\0'). This resulted in the xor computation to incorrectly include the NUL byte. Every password of at least 20 characters therefore failed to authenticate using this method. Looking at mysql-server source code also seems to reveal that it always uses a fixed number of scramble bytes [1]. [1] https://github.com/mysql/mysql-server/blob/ea7087d885006918ad54458e7aad215b1650312c/sql/auth/sha2_password.cc#L1078-L1079 Closes GH-11445. Co-authored-by: Kamil Tekiela --- NEWS | 3 ++ ext/mysqli/tests/gh11438.phpt | 84 +++++++++++++++++++++++++++++++++++ ext/mysqlnd/mysqlnd_auth.c | 5 ++- 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 ext/mysqli/tests/gh11438.phpt diff --git a/NEWS b/NEWS index a63a367d1f5..15202e9ad73 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,9 @@ PHP NEWS - MySQLnd: . Fixed bug GH-11440 (authentication to a sha256_password account fails over SSL). (nielsdos) + . Fixed bug GH-11438 (mysqlnd fails to authenticate with sha256_password + accounts using passwords longer than 19 characters). + (nielsdos, Kamil Tekiela) - Opcache: . Fixed bug GH-11715 (opcache.interned_strings_buffer either has no effect or diff --git a/ext/mysqli/tests/gh11438.phpt b/ext/mysqli/tests/gh11438.phpt new file mode 100644 index 00000000000..49c715e72c0 --- /dev/null +++ b/ext/mysqli/tests/gh11438.phpt @@ -0,0 +1,84 @@ +--TEST-- +GH-11438 (mysqlnd fails to authenticate with sha256_password accounts using passwords longer than 19 characters) +--EXTENSIONS-- +mysqli +--SKIPIF-- +query("SHOW PLUGINS"))) { + die(sprintf("skip [%d] %s\n", $link->errno, $link->error)); +} + +$found = false; +while ($row = $res->fetch_assoc()) { + if (($row['Name'] == 'sha256_password') && ($row['Status'] == 'ACTIVE')) { + $found = true; + break; + } +} +if (!$found) + die("skip SHA-256 server plugin unavailable"); + +// Ignore errors because this variable exists only in MySQL 5.6 and 5.7 +$link->query("SET @@session.old_passwords=2"); + +$link->query('DROP USER shatest'); +$link->query("DROP USER shatest@localhost"); + +if (!$link->query('CREATE USER shatest@"%" IDENTIFIED WITH sha256_password') || + !$link->query('CREATE USER shatest@"localhost" IDENTIFIED WITH sha256_password')) { + die(sprintf("skip CREATE USER failed [%d] %s", $link->errno, $link->error)); +} + +// Password of length 52, more than twice the length of the scramble data to ensure scramble is repeated correctly +if (!$link->query('SET PASSWORD FOR shatest@"%" = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"') || + !$link->query('SET PASSWORD FOR shatest@"localhost" = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"')) { + die(sprintf("skip SET PASSWORD failed [%d] %s", $link->errno, $link->error)); +} + +echo "nocache"; +?> +--FILE-- +connect_errno) { + printf("[001] [%d] %s\n", $link->connect_errno, $link->connect_error); +} else { + if (!$res = $link->query("SELECT USER()")) + printf("[002] [%d] %s\n", $link->errno, $link->error); + + if (!$row = mysqli_fetch_assoc($res)) { + printf("[003] [%d] %s\n", $link->errno, $link->error); + } + + if (!is_string($row['USER()']) || !str_starts_with($row['USER()'], 'shatest')) { + printf("[004] Expecting 1 got %s/'%s'", gettype($row['USER()']), $row['USER()']); + } +} + +print "done!"; +?> +--CLEAN-- +query('DROP USER shatest'); +$link->query('DROP USER shatest@localhost'); +?> +--EXPECTF-- +done! diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c index 6956440abdc..ea9755c982e 100644 --- a/ext/mysqlnd/mysqlnd_auth.c +++ b/ext/mysqlnd/mysqlnd_auth.c @@ -927,7 +927,10 @@ mysqlnd_sha256_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self char *xor_str = do_alloca(passwd_len + 1, use_heap); memcpy(xor_str, passwd, passwd_len); xor_str[passwd_len] = '\0'; - mysqlnd_xor_string(xor_str, passwd_len, (char *) auth_plugin_data, auth_plugin_data_len); + /* https://dev.mysql.com/doc/dev/mysql-server/latest/page_caching_sha2_authentication_exchanges.html + * This tells us that the nonce is 20 (==SCRAMBLE_LENGTH) bytes long. + * In a 5.5+ server we might get additional scramble data in php_mysqlnd_greet_read, not used by this authentication method. */ + mysqlnd_xor_string(xor_str, passwd_len, (char *) auth_plugin_data, SCRAMBLE_LENGTH); ret = mysqlnd_sha256_public_encrypt(conn, server_public_key, passwd_len, auth_data_len, xor_str); free_alloca(xor_str, use_heap); } From 997a36750be6a82e727b1e10aa7fdddcdae70e76 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 2 Aug 2023 16:02:00 +0200 Subject: [PATCH 2/2] Fix GH-10964: Improve `man` page about the built-in server Closes GH-11857. --- NEWS | 2 ++ sapi/cli/php.1.in | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/NEWS b/NEWS index 15202e9ad73..ac2bd020f77 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,8 @@ PHP NEWS - CLI: . Fixed bug GH-11716 (cli server crashes on SIGINT when compiled with ZEND_RC_DEBUG=1). (nielsdos) + . Fixed bug GH-10964 (Improve man page about the built-in server). + (Alexandre Daubois) - DOM: . Fix DOMEntity field getter bugs. (nielsdos) diff --git a/sapi/cli/php.1.in b/sapi/cli/php.1.in index 98c8dc76f26..227e4f20edc 100644 --- a/sapi/cli/php.1.in +++ b/sapi/cli/php.1.in @@ -92,6 +92,15 @@ point to a local address and port PHP will listen to HTTP requests on that addre .B docroot passed by the \-t option. .LP +If a PHP file is provided to the command line when the +built-in web server is used, it will be used as the router script. This script +will be started at each HTTP request. The script output is returned to the +browser, unless the router script returns the +.B false +value. If so, the built-in server falls back to the default behaviour, returning +the requested resource as-is by looking up the files relative to the document +root specified by the \-t option, if provided. +.LP If none of \-r \-f \-B \-R \-F \-E or \-S is present but a single parameter is given then this parameter is taken as the filename to parse and execute (same as with \-f). If no parameter is present then the standard input is read and