UserPassword.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Holds the PhpMyAdmin\UserPassword class
  5. *
  6. * @package PhpMyAdmin
  7. */
  8. declare(strict_types=1);
  9. namespace PhpMyAdmin;
  10. use PhpMyAdmin\Core;
  11. use PhpMyAdmin\Message;
  12. use PhpMyAdmin\Response;
  13. use PhpMyAdmin\Server\Privileges;
  14. use PhpMyAdmin\Url;
  15. use PhpMyAdmin\Util;
  16. /**
  17. * Functions for user_password.php
  18. *
  19. * @package PhpMyAdmin
  20. */
  21. class UserPassword
  22. {
  23. /**
  24. * @var Privileges
  25. */
  26. private $serverPrivileges;
  27. /**
  28. * UserPassword constructor.
  29. *
  30. * @param Privileges $serverPrivileges Privileges object
  31. */
  32. public function __construct(Privileges $serverPrivileges)
  33. {
  34. $this->serverPrivileges = $serverPrivileges;
  35. }
  36. /**
  37. * Send the message as an ajax request
  38. *
  39. * @param array $change_password_message Message to display
  40. * @param string $sql_query SQL query executed
  41. *
  42. * @return void
  43. */
  44. public function getChangePassMessage(array $change_password_message, $sql_query = '')
  45. {
  46. $response = Response::getInstance();
  47. if ($response->isAjax()) {
  48. /**
  49. * If in an Ajax request, we don't need to show the rest of the page
  50. */
  51. if ($change_password_message['error']) {
  52. $response->addJSON('message', $change_password_message['msg']);
  53. $response->setRequestStatus(false);
  54. } else {
  55. $sql_query = Util::getMessage(
  56. $change_password_message['msg'],
  57. $sql_query,
  58. 'success'
  59. );
  60. $response->addJSON('message', $sql_query);
  61. }
  62. exit;
  63. }
  64. }
  65. /**
  66. * Generate the message
  67. *
  68. * @return array error value and message
  69. */
  70. public function setChangePasswordMsg()
  71. {
  72. $error = false;
  73. $message = Message::success(__('The profile has been updated.'));
  74. if ($_POST['nopass'] != '1') {
  75. if (strlen($_POST['pma_pw']) === 0 || strlen($_POST['pma_pw2']) === 0) {
  76. $message = Message::error(__('The password is empty!'));
  77. $error = true;
  78. } elseif ($_POST['pma_pw'] !== $_POST['pma_pw2']) {
  79. $message = Message::error(
  80. __('The passwords aren\'t the same!')
  81. );
  82. $error = true;
  83. } elseif (strlen($_POST['pma_pw']) > 256) {
  84. $message = Message::error(__('Password is too long!'));
  85. $error = true;
  86. }
  87. }
  88. return [
  89. 'error' => $error,
  90. 'msg' => $message,
  91. ];
  92. }
  93. /**
  94. * Change the password
  95. *
  96. * @param string $password New password
  97. * @param string $message Message
  98. * @param array $change_password_message Message to show
  99. *
  100. * @return void
  101. */
  102. public function changePassword($password, $message, array $change_password_message)
  103. {
  104. global $auth_plugin;
  105. $hashing_function = $this->changePassHashingFunction();
  106. list($username, $hostname) = $GLOBALS['dbi']->getCurrentUserAndHost();
  107. $serverType = Util::getServerType();
  108. $serverVersion = $GLOBALS['dbi']->getVersion();
  109. if (isset($_POST['authentication_plugin'])
  110. && ! empty($_POST['authentication_plugin'])
  111. ) {
  112. $orig_auth_plugin = $_POST['authentication_plugin'];
  113. } else {
  114. $orig_auth_plugin = $this->serverPrivileges->getCurrentAuthenticationPlugin(
  115. 'change',
  116. $username,
  117. $hostname
  118. );
  119. }
  120. $sql_query = 'SET password = '
  121. . (($password == '') ? '\'\'' : $hashing_function . '(\'***\')');
  122. if ($serverType == 'MySQL'
  123. && $serverVersion >= 50706
  124. ) {
  125. $sql_query = 'ALTER USER \'' . $GLOBALS['dbi']->escapeString($username)
  126. . '\'@\'' . $GLOBALS['dbi']->escapeString($hostname)
  127. . '\' IDENTIFIED WITH ' . $orig_auth_plugin . ' BY '
  128. . (($password == '') ? '\'\'' : '\'***\'');
  129. } elseif (($serverType == 'MySQL'
  130. && $serverVersion >= 50507)
  131. || ($serverType == 'MariaDB'
  132. && $serverVersion >= 50200)
  133. ) {
  134. // For MySQL versions 5.5.7+ and MariaDB versions 5.2+,
  135. // explicitly set value of `old_passwords` so that
  136. // it does not give an error while using
  137. // the PASSWORD() function
  138. if ($orig_auth_plugin == 'sha256_password') {
  139. $value = 2;
  140. } else {
  141. $value = 0;
  142. }
  143. $GLOBALS['dbi']->tryQuery('SET `old_passwords` = ' . $value . ';');
  144. }
  145. $this->changePassUrlParamsAndSubmitQuery(
  146. $username,
  147. $hostname,
  148. $password,
  149. $sql_query,
  150. $hashing_function,
  151. $orig_auth_plugin
  152. );
  153. $auth_plugin->handlePasswordChange($password);
  154. $this->getChangePassMessage($change_password_message, $sql_query);
  155. $this->changePassDisplayPage($message, $sql_query);
  156. }
  157. /**
  158. * Generate the hashing function
  159. *
  160. * @return string
  161. */
  162. private function changePassHashingFunction()
  163. {
  164. if (Core::isValid(
  165. $_POST['authentication_plugin'],
  166. 'identical',
  167. 'mysql_old_password'
  168. )) {
  169. $hashing_function = 'OLD_PASSWORD';
  170. } else {
  171. $hashing_function = 'PASSWORD';
  172. }
  173. return $hashing_function;
  174. }
  175. /**
  176. * Changes password for a user
  177. *
  178. * @param string $username Username
  179. * @param string $hostname Hostname
  180. * @param string $password Password
  181. * @param string $sql_query SQL query
  182. * @param string $hashing_function Hashing function
  183. * @param string $orig_auth_plugin Original Authentication Plugin
  184. *
  185. * @return void
  186. */
  187. private function changePassUrlParamsAndSubmitQuery(
  188. $username,
  189. $hostname,
  190. $password,
  191. $sql_query,
  192. $hashing_function,
  193. $orig_auth_plugin
  194. ) {
  195. $err_url = 'user_password.php' . Url::getCommon();
  196. $serverType = Util::getServerType();
  197. $serverVersion = $GLOBALS['dbi']->getVersion();
  198. if ($serverType == 'MySQL' && $serverVersion >= 50706) {
  199. $local_query = 'ALTER USER \'' . $GLOBALS['dbi']->escapeString($username)
  200. . '\'@\'' . $GLOBALS['dbi']->escapeString($hostname) . '\''
  201. . ' IDENTIFIED with ' . $orig_auth_plugin . ' BY '
  202. . (($password == '')
  203. ? '\'\''
  204. : '\'' . $GLOBALS['dbi']->escapeString($password) . '\'');
  205. } elseif ($serverType == 'MariaDB'
  206. && $serverVersion >= 50200
  207. && $serverVersion < 100100
  208. && $orig_auth_plugin !== ''
  209. ) {
  210. if ($orig_auth_plugin == 'mysql_native_password') {
  211. // Set the hashing method used by PASSWORD()
  212. // to be 'mysql_native_password' type
  213. $GLOBALS['dbi']->tryQuery('SET old_passwords = 0;');
  214. } elseif ($orig_auth_plugin == 'sha256_password') {
  215. // Set the hashing method used by PASSWORD()
  216. // to be 'sha256_password' type
  217. $GLOBALS['dbi']->tryQuery('SET `old_passwords` = 2;');
  218. }
  219. $hashedPassword = $this->serverPrivileges->getHashedPassword($_POST['pma_pw']);
  220. $local_query = "UPDATE `mysql`.`user` SET"
  221. . " `authentication_string` = '" . $hashedPassword
  222. . "', `Password` = '', "
  223. . " `plugin` = '" . $orig_auth_plugin . "'"
  224. . " WHERE `User` = '" . $GLOBALS['dbi']->escapeString($username)
  225. . "' AND Host = '" . $GLOBALS['dbi']->escapeString($hostname) . "';";
  226. } else {
  227. $local_query = 'SET password = ' . (($password == '')
  228. ? '\'\''
  229. : $hashing_function . '(\''
  230. . $GLOBALS['dbi']->escapeString($password) . '\')');
  231. }
  232. if (! @$GLOBALS['dbi']->tryQuery($local_query)) {
  233. Util::mysqlDie(
  234. $GLOBALS['dbi']->getError(),
  235. $sql_query,
  236. false,
  237. $err_url
  238. );
  239. }
  240. // Flush privileges after successful password change
  241. $GLOBALS['dbi']->tryQuery("FLUSH PRIVILEGES;");
  242. }
  243. /**
  244. * Display the page
  245. *
  246. * @param string $message Message
  247. * @param string $sql_query SQL query
  248. *
  249. * @return void
  250. */
  251. private function changePassDisplayPage($message, $sql_query)
  252. {
  253. echo '<h1>' , __('Change password') , '</h1>' , "\n\n";
  254. echo Util::getMessage(
  255. $message,
  256. $sql_query,
  257. 'success'
  258. );
  259. echo '<a href="index.php' , Url::getCommon()
  260. , ' target="_parent">' , "\n"
  261. , '<strong>' , __('Back') , '</strong></a>';
  262. exit;
  263. }
  264. }