UserPassword.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. <?php
  2. declare(strict_types=1);
  3. namespace PhpMyAdmin;
  4. use PhpMyAdmin\Html\Generator;
  5. use PhpMyAdmin\Server\Privileges;
  6. use function strlen;
  7. use function in_array;
  8. /**
  9. * Functions for user password
  10. */
  11. class UserPassword
  12. {
  13. /** @var Privileges */
  14. private $serverPrivileges;
  15. /**
  16. * @param Privileges $serverPrivileges Privileges object
  17. */
  18. public function __construct(Privileges $serverPrivileges)
  19. {
  20. $this->serverPrivileges = $serverPrivileges;
  21. }
  22. /**
  23. * Generate the message
  24. *
  25. * @return array error value and message
  26. */
  27. public function setChangePasswordMsg()
  28. {
  29. $error = false;
  30. $message = Message::success(__('The profile has been updated.'));
  31. if ($_POST['nopass'] != '1') {
  32. if (strlen($_POST['pma_pw']) === 0 || strlen($_POST['pma_pw2']) === 0) {
  33. $message = Message::error(__('The password is empty!'));
  34. $error = true;
  35. } elseif ($_POST['pma_pw'] !== $_POST['pma_pw2']) {
  36. $message = Message::error(
  37. __('The passwords aren\'t the same!')
  38. );
  39. $error = true;
  40. } elseif (strlen($_POST['pma_pw']) > 256) {
  41. $message = Message::error(__('Password is too long!'));
  42. $error = true;
  43. }
  44. }
  45. return [
  46. 'error' => $error,
  47. 'msg' => $message,
  48. ];
  49. }
  50. /**
  51. * Change the password
  52. *
  53. * @param string $password New password
  54. */
  55. public function changePassword($password): string
  56. {
  57. global $auth_plugin, $dbi;
  58. $hashing_function = $this->changePassHashingFunction();
  59. [$username, $hostname] = $dbi->getCurrentUserAndHost();
  60. $serverType = Util::getServerType();
  61. $serverVersion = $dbi->getVersion();
  62. if (isset($_POST['authentication_plugin'])
  63. && ! empty($_POST['authentication_plugin'])
  64. ) {
  65. $orig_auth_plugin = $_POST['authentication_plugin'];
  66. } else {
  67. $orig_auth_plugin = $this->serverPrivileges->getCurrentAuthenticationPlugin(
  68. 'change',
  69. $username,
  70. $hostname
  71. );
  72. }
  73. $sql_query = 'SET password = '
  74. . ($password == '' ? '\'\'' : $hashing_function . '(\'***\')');
  75. $isPerconaOrMySql = in_array($serverType, ['MySQL', 'Percona Server'], true);
  76. if ($isPerconaOrMySql && $serverVersion >= 50706
  77. ) {
  78. $sql_query = 'ALTER USER \'' . $dbi->escapeString($username)
  79. . '\'@\'' . $dbi->escapeString($hostname)
  80. . '\' IDENTIFIED WITH ' . $orig_auth_plugin . ' BY '
  81. . ($password == '' ? '\'\'' : '\'***\'');
  82. } elseif (
  83. ($isPerconaOrMySql && $serverVersion >= 50507)
  84. || ($serverType === 'MariaDB' && $serverVersion >= 50200)
  85. ) {
  86. // For MySQL and Percona versions 5.5.7+ and MariaDB versions 5.2+,
  87. // explicitly set value of `old_passwords` so that
  88. // it does not give an error while using
  89. // the PASSWORD() function
  90. if ($orig_auth_plugin === 'sha256_password') {
  91. $value = 2;
  92. } else {
  93. $value = 0;
  94. }
  95. $dbi->tryQuery('SET `old_passwords` = ' . $value . ';');
  96. }
  97. $this->changePassUrlParamsAndSubmitQuery(
  98. $username,
  99. $hostname,
  100. $password,
  101. $sql_query,
  102. $hashing_function,
  103. $orig_auth_plugin
  104. );
  105. $auth_plugin->handlePasswordChange($password);
  106. return $sql_query;
  107. }
  108. /**
  109. * Generate the hashing function
  110. *
  111. * @return string
  112. */
  113. private function changePassHashingFunction()
  114. {
  115. if (Core::isValid(
  116. $_POST['authentication_plugin'],
  117. 'identical',
  118. 'mysql_old_password'
  119. )) {
  120. $hashing_function = 'OLD_PASSWORD';
  121. } else {
  122. $hashing_function = 'PASSWORD';
  123. }
  124. return $hashing_function;
  125. }
  126. /**
  127. * Changes password for a user
  128. *
  129. * @param string $username Username
  130. * @param string $hostname Hostname
  131. * @param string $password Password
  132. * @param string $sql_query SQL query
  133. * @param string $hashing_function Hashing function
  134. * @param string $orig_auth_plugin Original Authentication Plugin
  135. *
  136. * @return void
  137. */
  138. private function changePassUrlParamsAndSubmitQuery(
  139. $username,
  140. $hostname,
  141. $password,
  142. $sql_query,
  143. $hashing_function,
  144. $orig_auth_plugin
  145. ) {
  146. global $dbi;
  147. $err_url = Url::getFromRoute('/user-password');
  148. $serverType = Util::getServerType();
  149. $serverVersion = $dbi->getVersion();
  150. if (
  151. in_array($serverType, ['MySQL', 'Percona Server'], true)
  152. && $serverVersion >= 50706
  153. ) {
  154. $local_query = 'ALTER USER \'' . $dbi->escapeString($username)
  155. . '\'@\'' . $dbi->escapeString($hostname) . '\''
  156. . ' IDENTIFIED with ' . $orig_auth_plugin . ' BY '
  157. . ($password == ''
  158. ? '\'\''
  159. : '\'' . $dbi->escapeString($password) . '\'');
  160. } elseif ($serverType === 'MariaDB'
  161. && $serverVersion >= 50200
  162. && $serverVersion < 100100
  163. && $orig_auth_plugin !== ''
  164. ) {
  165. if ($orig_auth_plugin === 'mysql_native_password') {
  166. // Set the hashing method used by PASSWORD()
  167. // to be 'mysql_native_password' type
  168. $dbi->tryQuery('SET old_passwords = 0;');
  169. } elseif ($orig_auth_plugin === 'sha256_password') {
  170. // Set the hashing method used by PASSWORD()
  171. // to be 'sha256_password' type
  172. $dbi->tryQuery('SET `old_passwords` = 2;');
  173. }
  174. $hashedPassword = $this->serverPrivileges->getHashedPassword($_POST['pma_pw']);
  175. $local_query = 'UPDATE `mysql`.`user` SET'
  176. . " `authentication_string` = '" . $hashedPassword
  177. . "', `Password` = '', "
  178. . " `plugin` = '" . $orig_auth_plugin . "'"
  179. . " WHERE `User` = '" . $dbi->escapeString($username)
  180. . "' AND Host = '" . $dbi->escapeString($hostname) . "';";
  181. } else {
  182. $local_query = 'SET password = ' . ($password == ''
  183. ? '\'\''
  184. : $hashing_function . '(\''
  185. . $dbi->escapeString($password) . '\')');
  186. }
  187. if (! @$dbi->tryQuery($local_query)) {
  188. Generator::mysqlDie(
  189. $dbi->getError(),
  190. $sql_query,
  191. false,
  192. $err_url
  193. );
  194. }
  195. // Flush privileges after successful password change
  196. $dbi->tryQuery('FLUSH PRIVILEGES;');
  197. }
  198. public function getFormForChangePassword(?string $username, ?string $hostname): string
  199. {
  200. return $this->serverPrivileges->getFormForChangePassword($username ?? '', $hostname ?? '', false);
  201. }
  202. }