summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--schema/aur-schema.sql2
-rw-r--r--upgrading/4.5.0.txt6
-rw-r--r--web/html/passreset.php5
-rw-r--r--web/lib/acctfuncs.inc.php144
-rw-r--r--web/lib/aur.inc.php57
5 files changed, 68 insertions, 146 deletions
diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql
index 99f90834..b75a257c 100644
--- a/schema/aur-schema.sql
+++ b/schema/aur-schema.sql
@@ -27,7 +27,7 @@ CREATE TABLE Users (
Username VARCHAR(32) NOT NULL,
Email VARCHAR(254) NOT NULL,
HideEmail TINYINT UNSIGNED NOT NULL DEFAULT 0,
- Passwd CHAR(32) NOT NULL,
+ Passwd VARCHAR(255) NOT NULL,
Salt CHAR(32) NOT NULL DEFAULT '',
ResetKey CHAR(32) NOT NULL DEFAULT '',
RealName VARCHAR(64) NOT NULL DEFAULT '',
diff --git a/upgrading/4.5.0.txt b/upgrading/4.5.0.txt
index fb0a2993..37b2b810 100644
--- a/upgrading/4.5.0.txt
+++ b/upgrading/4.5.0.txt
@@ -18,3 +18,9 @@ ALTER TABLE Users
----
ALTER TABLE Bans MODIFY IPAddress VARCHAR(45) NULL DEFAULT NULL;
----
+
+4. Resize the Passwd column of the Users table:
+
+---
+ALTER TABLE Users MODIFY Passwd VARCHAR(255) NOT NULL;
+---
diff --git a/web/html/passreset.php b/web/html/passreset.php
index cb2f6bcd..e89967d4 100644
--- a/web/html/passreset.php
+++ b/web/html/passreset.php
@@ -34,10 +34,7 @@ if (isset($_GET['resetkey'], $_POST['email'], $_POST['password'], $_POST['confir
}
if (empty($error)) {
- $salt = generate_salt();
- $hash = salted_hash($password, $salt);
-
- $error = password_reset($hash, $salt, $resetkey, $email);
+ $error = password_reset($password, $resetkey, $email);
}
} elseif (isset($_POST['email'])) {
$email = $_POST['email'];
diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php
index b3cf6122..d0a7ff94 100644
--- a/web/lib/acctfuncs.inc.php
+++ b/web/lib/acctfuncs.inc.php
@@ -272,13 +272,12 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C=""
if ($TYPE == "new") {
/* Create an unprivileged user. */
- $salt = generate_salt();
if (empty($P)) {
$send_resetkey = true;
$email = $E;
} else {
$send_resetkey = false;
- $P = salted_hash($P, $salt);
+ $P = password_hash($P, PASSWORD_DEFAULT);
}
$U = $dbh->quote($U);
$E = $dbh->quote($E);
@@ -291,9 +290,9 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C=""
$I = $dbh->quote($I);
$K = $dbh->quote(str_replace(" ", "", $K));
$q = "INSERT INTO Users (AccountTypeID, Suspended, ";
- $q.= "InactivityTS, Username, Email, Passwd, Salt, ";
+ $q.= "InactivityTS, Username, Email, Passwd , ";
$q.= "RealName, LangPreference, Timezone, Homepage, IRCNick, PGPKey) ";
- $q.= "VALUES (1, 0, 0, $U, $E, $P, $salt, $R, $L, $TZ ";
+ $q.= "VALUES (1, 0, 0, $U, $E, $P, $R, $L, $TZ ";
$q.= "$HP, $I, $K)";
$result = $dbh->exec($q);
if (!$result) {
@@ -350,9 +349,8 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C=""
$q.= ", HideEmail = 0";
}
if ($P) {
- $salt = generate_salt();
- $hash = salted_hash($P, $salt);
- $q .= ", Passwd = '$hash', Salt = '$salt'";
+ $hash = password_hash($P, PASSWORD_DEFAULT);
+ $q .= ", Passwd = " . $dbh->quote($hash);
}
$q.= ", RealName = " . $dbh->quote($R);
$q.= ", LangPreference = " . $dbh->quote($L);
@@ -528,19 +526,24 @@ function try_login() {
if (user_suspended($userID)) {
$login_error = __('Account suspended');
return array('SID' => '', 'error' => $login_error);
- } elseif (passwd_is_empty($userID)) {
- $login_error = __('Your password has been reset. ' .
- 'If you just created a new account, please ' .
- 'use the link from the confirmation email ' .
- 'to set an initial password. Otherwise, ' .
- 'please request a reset key on the %s' .
- 'Password Reset%s page.', '<a href="' .
- htmlspecialchars(get_uri('/passreset')) . '">',
- '</a>');
- return array('SID' => '', 'error' => $login_error);
- } elseif (!valid_passwd($userID, $_REQUEST['passwd'])) {
- $login_error = __("Bad username or password.");
- return array('SID' => '', 'error' => $login_error);
+ }
+
+ switch (check_passwd($userID, $_REQUEST['passwd'])) {
+ case -1:
+ $login_error = __('Your password has been reset. ' .
+ 'If you just created a new account, please ' .
+ 'use the link from the confirmation email ' .
+ 'to set an initial password. Otherwise, ' .
+ 'please request a reset key on the %s' .
+ 'Password Reset%s page.', '<a href="' .
+ htmlspecialchars(get_uri('/passreset')) . '">',
+ '</a>');
+ return array('SID' => '', 'error' => $login_error);
+ case 0:
+ $login_error = __("Bad username or password.");
+ return array('SID' => '', 'error' => $login_error);
+ case 1:
+ break;
}
$logged_in = 0;
@@ -736,18 +739,18 @@ function send_resetkey($email, $welcome=false) {
/**
* Change a user's password in the database if reset key and e-mail are correct
*
- * @param string $hash New MD5 hash of a user's password
- * @param string $salt New salt for the user's password
+ * @param string $password The new password
* @param string $resetkey Code e-mailed to a user to reset a password
* @param string $email E-mail address of the user resetting their password
*
* @return string|void Redirect page if successful, otherwise return error message
*/
-function password_reset($hash, $salt, $resetkey, $email) {
+function password_reset($password, $resetkey, $email) {
+ $hash = password_hash($password, PASSWORD_DEFAULT);
+
$dbh = DB::connect();
- $q = "UPDATE Users ";
- $q.= "SET Passwd = '$hash', ";
- $q.= "Salt = '$salt', ";
+ $q = "UPDATE Users SET ";
+ $q.= "Passwd = " . $dbh->quote($hash) . ", ";
$q.= "ResetKey = '' ";
$q.= "WHERE ResetKey != '' ";
$q.= "AND ResetKey = " . $dbh->quote($resetkey) . " ";
@@ -778,75 +781,48 @@ function good_passwd($passwd) {
/**
* Determine if the password is correct and salt it if it hasn't been already
*
- * @param string $userID The user ID to check the password against
+ * @param int $user_id The user ID to check the password against
* @param string $passwd The password the visitor sent
*
- * @return bool True if password was correct and properly salted, otherwise false
+ * @return int Positive if password is correct, negative if password is unset
*/
-function valid_passwd($userID, $passwd) {
+function check_passwd($user_id, $passwd) {
$dbh = DB::connect();
- if ($passwd == "") {
- return false;
- }
- /* Get salt for this user. */
- $salt = get_salt($userID);
- if ($salt) {
- $q = "SELECT ID FROM Users ";
- $q.= "WHERE ID = " . $userID . " ";
- $q.= "AND Passwd = " . $dbh->quote(salted_hash($passwd, $salt));
- $result = $dbh->query($q);
- if (!$result) {
- return false;
- }
-
- $row = $result->fetch(PDO::FETCH_NUM);
- return ($row[0] > 0);
- } else {
- /* Check password without using salt. */
- $q = "SELECT ID FROM Users ";
- $q.= "WHERE ID = " . $userID . " ";
- $q.= "AND Passwd = " . $dbh->quote(md5($passwd));
- $result = $dbh->query($q);
- if (!$result) {
- return false;
- }
-
- $row = $result->fetch(PDO::FETCH_NUM);
- if (!$row[0]) {
- return false;
- }
+ /* Get password hash and salt. */
+ $q = "SELECT Passwd, Salt FROM Users WHERE ID = " . intval($user_id);
+ $result = $dbh->query($q);
+ if (!$result) {
+ return 0;
+ }
+ $row = $result->fetch(PDO::FETCH_ASSOC);
+ if (!$row) {
+ return 0;
+ }
+ $hash = $row['Passwd'];
+ $salt = $row['Salt'];
+ if (!$hash) {
+ return -1;
+ }
- /* Password correct, but salt it first! */
- if (!save_salt($userID, $passwd)) {
- trigger_error("Unable to salt user's password;" .
- " ID " . $userID, E_USER_WARNING);
- return false;
+ /* Verify the password hash. */
+ if (!password_verify($passwd, $hash)) {
+ /* Invalid password, fall back to MD5. */
+ if (md5($salt . $passwd) != $hash) {
+ return 0;
}
-
- return true;
}
-}
-/**
- * Determine if a user's password is empty
- *
- * @param string $uid The user ID to check for an empty password
- *
- * @return bool True if the user's password is empty, otherwise false
- */
-function passwd_is_empty($uid) {
- $dbh = DB::connect();
-
- $q = "SELECT * FROM Users WHERE ID = " . $dbh->quote($uid) . " ";
- $q .= "AND Passwd = " . $dbh->quote('');
- $result = $dbh->query($q);
+ /* Password correct, migrate the hash if necessary. */
+ if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
+ $hash = password_hash($passwd, PASSWORD_DEFAULT);
- if ($result->fetchColumn()) {
- return true;
- } else {
- return false;
+ $q = "UPDATE Users SET Passwd = " . $dbh->quote($hash) . " ";
+ $q.= "WHERE ID = " . intval($user_id);
+ $dbh->query($q);
}
+
+ return 1;
}
/**
diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php
index 94a38499..d58df406 100644
--- a/web/lib/aur.inc.php
+++ b/web/lib/aur.inc.php
@@ -538,63 +538,6 @@ function mkurl($append) {
}
/**
- * Determine a user's salt from the database
- *
- * @param string $user_id The user ID of the user trying to log in
- *
- * @return string|void Return the salt for the requested user, otherwise void
- */
-function get_salt($user_id) {
- $dbh = DB::connect();
- $q = "SELECT Salt FROM Users WHERE ID = " . $user_id;
- $result = $dbh->query($q);
- if ($result) {
- $row = $result->fetch(PDO::FETCH_NUM);
- return $row[0];
- }
- return;
-}
-
-/**
- * Save a user's salted password in the database
- *
- * @param string $user_id The user ID of the user who is salting their password
- * @param string $passwd The password of the user logging in
- */
-function save_salt($user_id, $passwd) {
- $dbh = DB::connect();
- $salt = generate_salt();
- $hash = salted_hash($passwd, $salt);
- $q = "UPDATE Users SET Salt = " . $dbh->quote($salt) . ", ";
- $q.= "Passwd = " . $dbh->quote($hash) . " WHERE ID = " . $user_id;
- return $dbh->exec($q);
-}
-
-/**
- * Generate a string to be used for salting passwords
- *
- * @return string MD5 hash of concatenated random number and current time
- */
-function generate_salt() {
- return md5(uniqid(mt_rand(), true));
-}
-
-/**
- * Combine salt and password to form a hash
- *
- * @param string $passwd User plaintext password
- * @param string $salt MD5 hash to be used as user salt
- *
- * @return string The MD5 hash of the concatenated salt and user password
- */
-function salted_hash($passwd, $salt) {
- if (strlen($salt) != 32) {
- trigger_error('Salt does not look like an md5 hash', E_USER_WARNING);
- }
- return md5($salt . $passwd);
-}
-
-/**
* Get a package comment
*
* @param int $comment_id The ID of the comment