/serverconfig/nopassword-setdbpass.php

https://bitbucket.org/steinb/nopassword · PHP · 112 lines · 66 code · 12 blank · 34 comment · 18 complexity · 911529e4602d7c570e71a0c2272a463b MD5 · raw file

  1. <?php
  2. /* generate passwords for php access to mysql database,
  3. * write php config file and sql code to set database passwords
  4. *
  5. * to be called by nopassword-setdbpass.sh
  6. */
  7. // filename of the configuration file containing the database passwords
  8. // WARNING: this code will try to replace this file!
  9. $dbpass_fname = dirname(__FILE__) . '/secrets/nopassword-dbpass.php';
  10. // config file to read required usernames from
  11. $config_fname = dirname(__FILE__) . '/../inc/nopassword-config.php';
  12. $config_authuser = array();
  13. include $config_fname;
  14. // expect to have loaded an array config_authuser
  15. if (!isset($config_authuser)) {
  16. die("Error: Could not read configuration from file $config_fname.");
  17. }
  18. unset($nopassword_dbpass);
  19. foreach($config_authuser as $username) {
  20. $nopassword_dbpass[$username] = generate_random_password();
  21. }
  22. file_put_contents($dbpass_fname, "<?php\nnamespace nopassword;\n\$nopassword_dbpass = " . var_export($nopassword_dbpass, true) . ";\n?>");
  23. unset($nopassword_dbpass);
  24. include $dbpass_fname;
  25. // set passwords (generate mysql code to do so)
  26. echo "USE $dbname;\n";
  27. // disable the general query log for this session, to prevent the new passwords to be written to a log
  28. echo "SET sql_log_off=1;\n";
  29. foreach($nopassword_dbpass as $username => $password) {
  30. // sanity check: the password should be a string not shorter than 20 characters
  31. // (that would be no more than 120 bits of entropy with a base64 password)
  32. if (strlen($password) < 20) {
  33. die("ACTION REQUIRED: The password for $username is too short to be secure. This is a FATAL ERROR: Passwords in PHP config file $cfgfname and mysql database are NOW INCONSISTENT.");
  34. }
  35. echo "SET PASSWORD FOR $username = PASSWORD('$password');\n";
  36. }
  37. unset($nopassword_dbpass);
  38. //
  39. // generate a random base64-encoded string,
  40. // defaulting to a length of 27 characters
  41. // (a maximum of 27*6 = 162 bits of entropy)
  42. //
  43. // MySQL uses 41 charcter hashes where the first character is constant,
  44. // limiting entropy to at most 40*4 = 160 bits. Hence longer passwords
  45. // would not add security.
  46. //
  47. // base64 is a good choice for the encoding of a high-entropy password,
  48. // as it uses a large charcter set with almost perfect compatibility with any choice of charsets and transmission protocols
  49. //
  50. // this code is adapted from the random hash salt generation in a compatibility shim for the php 5.5 password function,
  51. // found at https://github.com/ircmaxell/password_compat
  52. //
  53. // the code attempts to use high-quality random number generators if available (mcrypt, openssl, /dev/urandom),
  54. // but does not fail if none are available, instead falling back to php's mt_rand() function, a pseudo-random number generator
  55. //
  56. // WARNING: On very old versions of PHP (<4.2.0), mt_rand is not (automatically) seeded, causing this code to break.
  57. // Also, the code has not been tested on PHP <5.4.9.
  58. //
  59. function generate_random_password($pw_len = 27) {
  60. $buffer = '';
  61. $raw_length = (int) ($pw_len * 3 / 4 + 1);
  62. $buffer_valid = false;
  63. if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
  64. $buffer = mcrypt_create_iv($raw_length, MCRYPT_DEV_URANDOM);
  65. if ($buffer) {
  66. $buffer_valid = true;
  67. }
  68. }
  69. if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
  70. $buffer = openssl_random_pseudo_bytes($raw_length);
  71. if ($buffer) {
  72. $buffer_valid = true;
  73. }
  74. }
  75. if (!$buffer_valid && is_readable('/dev/urandom')) {
  76. $f = fopen('/dev/urandom', 'r');
  77. $read = strlen($buffer);
  78. while ($read < $raw_length) {
  79. $buffer .= fread($f, $raw_length - $read);
  80. $read = strlen($buffer);
  81. }
  82. fclose($f);
  83. if ($read >= $raw_length) {
  84. $buffer_valid = true;
  85. }
  86. }
  87. if (!$buffer_valid || strlen($buffer) < $raw_length) {
  88. $bl = strlen($buffer);
  89. for ($i = 0; $i < $raw_length; $i++) {
  90. if ($i < $bl) {
  91. $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
  92. } else {
  93. $buffer .= chr(mt_rand(0, 255));
  94. }
  95. }
  96. }
  97. $salt = str_replace('+', '.', base64_encode($buffer));
  98. return substr($salt, 0, $pw_len);
  99. }
  100. ?>