From 2f606b3d3db139b86633aecead33022c0f83022a Mon Sep 17 00:00:00 2001 From: Ulrich Block Date: Fri, 18 Oct 2013 18:38:09 +0200 Subject: [PATCH] #15: PHP 5.5 hash API --- THIRDPARTY | 8 +- external/api_users.php | 138 +++++++++--- web/login.php | 61 ++---- web/stuff/api_users.php | 15 +- web/stuff/functions.php | 20 +- web/stuff/global_userdata.php | 7 +- web/stuff/page_register.php | 8 +- web/stuff/user.php | 23 +- web/stuff/userpanel_substitutes.php | 13 +- web/stuff/voice_master.php | 8 +- web/stuff/voice_tsdns.php | 7 +- web/template/default/page_header.tpl | 4 +- web/third_party/password_compat/password.php | 219 +++++++++++++++++++ 13 files changed, 420 insertions(+), 111 deletions(-) create mode 100644 web/third_party/password_compat/password.php diff --git a/THIRDPARTY b/THIRDPARTY index c55f1ff8..64d673bf 100644 --- a/THIRDPARTY +++ b/THIRDPARTY @@ -25,4 +25,10 @@ https://github.com/aFarkas/html5shiv These icons are public domain, and as such are free for any use (attribution appreciated but not required). Note that these flags are named using the ISO3166-1 alpha-2 country codes where appropriate. A list of codes can be found at http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 If you find these icons useful, please donate via paypal to mjames@gmail.com (or click the donate button available at http://www.famfamfam.com/lab/icons/silk) -Contact: mjames@gmail.com \ No newline at end of file +Contact: mjames@gmail.com + +* password_compat +https://github.com/ircmaxell/password_compat/ +Copyright Anthony Ferrara +Released under the MIT license +http://opensource.org/licenses/MIT \ No newline at end of file diff --git a/external/api_users.php b/external/api_users.php index 3d7c5783..fccc8054 100644 --- a/external/api_users.php +++ b/external/api_users.php @@ -89,8 +89,9 @@ $pdo=new PDO("mysql:host=".$config['dbHost'].";dbname=".$config['dbName'],$config['dbUser'],$config['dbPwd'],array(PDO::MYSQL_ATTR_INIT_COMMAND=>"SET NAMES utf8")); $pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); - // JSON array - $json=array(); + // Define default values so we always have a proper return + $total = 0; + $json = array(); // User export if ($list == 'user') { @@ -148,20 +149,21 @@ } else if ($config['sourceType']=='teklab') { // Get amount of users that are new or received an update - // The Query needs to be altered to your database. This is just an example! $sql="SELECT COUNT(`id`) AS `amount` FROM `{$config['tblPrefix']}_members` WHERE `rank`=1"; $query=$pdo->prepare($sql); - $query->execute(array($lastID,$updateTime)); + $query->execute(); $total=$query->fetchColumn(); + // users $sql = "SELECT * FROM `{$config['tblPrefix']}_members` WHERE `rank`=1 LIMIT $start,$chunkSize"; $query=$pdo->prepare($sql); - $query->execute(array($lastID,$updateTime)); + $query->execute(); foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { - // Easy-Wi stores the salutation with numbers + + // Teklab has also 3 for company which Easy-WI currently does not maintain if ($row['title'] == 0) { $salutation = 1; } else if ($row['title']==1) { @@ -170,6 +172,7 @@ $salutation = null; } + // Easy-WI uses ISO code for storing countries if ($row['country'] == 1) { $country = 'de'; } else if ($row['country'] == 2) { @@ -182,8 +185,9 @@ $country = null; } + // Street and streetnumber are stored in the same column Easy-WI has individual columns $exploded = explode(" ", $row['street']); - if (count($exploded) > 2) { + if (count($exploded) > 1) { $streetNumber = $exploded[count($exploded) - 1]; unset($exploded[count($exploded) - 1]); $streetName = implode(' ', $exploded); @@ -191,8 +195,7 @@ $streetName = null; $streetNumber = null; } - - // the keys needs to be adjusted to your table layout and query! + $json[]=array( 'externalID' => $row['id'], 'salutation' => $salutation, @@ -215,29 +218,114 @@ ); } } - // Echo the JSON reply with - echo json_encode(array('total' => $total,'entries' => $json)); - } else if ($list == 'substitutes' and $config['sourceType']=='teklab') { - die; - - } else if ($list == 'dedicated' and $config['sourceType']=='teklab') { - die; + +/** + } else if ($list == 'gameroots') { + if ($config['sourceType']=='teklab') { + + // Get amount of users that are new or received an update + $sql="SELECT COUNT(`id`) AS `amount` FROM `{$config['tblPrefix']}_rootserver` + WHERE `active`=1 + AND `games`=1"; + $query=$pdo->prepare($sql); + $query->execute(); + $total=$query->fetchColumn(); + + // users + $sql = "SELECT * FROM `{$config['tblPrefix']}_rootserver` + WHERE `active`=1 + AND `games`=1 + LIMIT $start,$chunkSize"; + $query=$pdo->prepare($sql); + $query->execute(); + foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { + $json[]=array( + 'externalID' => $row['id'], + 'userID' => $row['memberid'], + 'description' => $row['name'], + 'serverIP' => $row['serverip'], + 'sshPort' => $row['sshport'], + 'ftpPort' => $row['ftpport'], + 'cpuCores' => $row['cpucores'], + 'maxRam' => $row['ram'] + ); + } - } else if ($list == 'gameserver' and $config['sourceType']=='teklab') { - die; + } + + } else if ($list == 'gameimages') { + if ($config['sourceType']=='teklab') { - } else if ($list == 'voice' and $config['sourceType']=='teklab') { - die; + } + + } else if ($list == 'gameserver') { + if ($config['sourceType']=='teklab') { - } else if ($list == 'node' and $config['sourceType']=='teklab') { - die; + } +/** + } else if ($list == 'addons') { + + if ($config['sourceType']=='teklab') { + + // Get amount of users that are new or received an update + $sql="SELECT COUNT(`id`) AS `amount` FROM `{$config['tblPrefix']}_games_addons`"; + $query=$pdo->prepare($sql); + $query->execute(); + $total=$query->fetchColumn(); + + // users + $sql = "SELECT * FROM `{$config['tblPrefix']}_games_addons` + LIMIT $start,$chunkSize"; + $query=$pdo->prepare($sql); + $query->execute(); + foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { + $json[]=array( + 'externalID' => $row['id'], + 'name' => $row['addonname'], + 'description' => $row['text'], + 'shortName' => $row['sname'] + ); + } - } else if ($list == 'virt' and $config['sourceType']=='teklab') { - die; + } +**/ + } else if ($list == 'voice') { + if ($config['sourceType']=='teklab') { + } + + // Substitutes at last so we can get access permissions as well + } else if ($list == 'substitutes') { + if ($config['sourceType']=='teklab') { + + // Get amount of users that are new or received an update + $sql="SELECT COUNT(`id`) AS `amount` FROM `{$config['tblPrefix']}_subusers`"; + $query=$pdo->prepare($sql); + $query->execute(); + $total=$query->fetchColumn(); + + // users + $sql = "SELECT * FROM `{$config['tblPrefix']}_subusers` + LIMIT $start,$chunkSize"; + $query=$pdo->prepare($sql); + $query->execute(); + foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { + $json[]=array( + 'externalID' => $row['id'], + 'belongsToExternalID' => $row['memberid'], + 'loginName' => $row['user'], + 'firstName' => null, + 'lastName' => null, + 'password' => $row['password'] + ); + } + } } - // Catch database error and display + // Echo the JSON reply with + echo json_encode(array('total' => $total,'entries' => $json)); + + // Catch database error and display } catch(PDOException $error) { echo json_encode(array('error' => $error->getMessage())); } diff --git a/web/login.php b/web/login.php index 0848b808..978c478c 100644 --- a/web/login.php +++ b/web/login.php @@ -50,6 +50,7 @@ include(EASYWIDIR . '/stuff/vorlage.php'); include(EASYWIDIR . '/stuff/class_validator.php'); +include(EASYWIDIR . '/third_party/password_compat/password.php'); include(EASYWIDIR . '/stuff/functions.php'); include(EASYWIDIR . '/stuff/settings.php'); include(EASYWIDIR . '/stuff/keyphrasefile.php'); @@ -150,19 +151,17 @@ } else if ($ui->password('password1', 255, 'post') and $ui->password('password2', 255, 'post') and $ui->w('token', 32, 'get')) { - if ($ui->password('password1', 255, 'post')==$ui->password('password2', 255, 'post')) { + if ($ui->password('password1', 255, 'post') == $ui->password('password2', 255, 'post')) { $query = $sql->prepare("SELECT `id`,`cname` FROM `userdata` WHERE `token`=? LIMIT 1"); $query->execute(array($ui->w('token',32, 'get'))); foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { $username = $row['cname']; - $salt = md5(mt_rand() . date('Y-m-d H:i:s:u')); - $password = createHash($username, $ui->password('password1', 255, 'post'), $salt, $aeskey); $text = $sprache->passwordreseted; - $query2 = $sql->prepare("UPDATE `userdata` SET `token`='',`security`=?,`salt`=? WHERE `id`=? LIMIT 1"); - $query2->execute(array($password, $salt, $row['id'])); + $query2 = $sql->prepare("UPDATE `userdata` SET `token`='',`security`=? WHERE `id`=? LIMIT 1"); + $query2->execute(array(password_hash($ui->password('password1', 255, 'post'), PASSWORD_DEFAULT), $row['id'])); } } else if ($ui->password('password1', 255, 'post') != $ui->password('password2', 255, 'post')) { @@ -223,36 +222,15 @@ $id = $row['id']; $active = $row['active']; $mail = $row['mail']; - $salt = $row['salt']; $externalID = $row['externalID']; - $security = $row['security']; $resellerid = $row['resellerid']; $accounttype = $row['accounttype']; - $userpassNew = createHash($username, $password, $salt, $aeskey); + $passwordCorrect = passwordCheck($password, $row['security'], $row['cname'], $row['salt'], $aeskey); - if (isset($security) and $security != $userpassNew) { - - $userpassOld = passwordhash($username, $password); - - // some systems do not care about security at all. - // In case we imported users from such insecure implementations we need to migrate to something safe - $md5Import = md5($password); - - if ($userpassOld == $security or $md5Import == $security) { - - $salt = md5(mt_rand() . date('Y-m-d H:i:s:u')); - $userpass = ($userpassOld == $security) ? $userpassOld : $security; - - $query = $sql->prepare("UPDATE `userdata` SET `security`=?,`salt`=? WHERE `id`=? LIMIT 1"); - $query->execute(array(createHash($username, $password, $salt, $aeskey), $salt, $id)); - - } else { - $userpass = $userpassNew; - } - - } else { - $userpass = $userpassNew; + if ($passwordCorrect !== true and $passwordCorrect !== false) { + $query = $sql->prepare("UPDATE `userdata` SET `security`=? WHERE `id`=? LIMIT 1"); + $query->execute(array($passwordCorrect, $id)); } } @@ -267,14 +245,18 @@ $id = $row['userID']; $username = $row['loginName']; $active = $row['active']; - $salt = $row['salt']; - $security = $row['passwordHashed']; $resellerid = $row['resellerID']; - $userpass = createHash($username, $password, $salt, $aeskey); + + $passwordCorrect = passwordCheck($password, $row['passwordHashed'], $row['loginName'], $row['salt'], $aeskey); + + if ($passwordCorrect !== true and $passwordCorrect !== false) { + $query = $sql->prepare("UPDATE `userdata_substitutes` SET `passwordHashed`=? WHERE `sID`=? LIMIT 1"); + $query->execute(array($passwordCorrect, $sID)); + } } } - if (isset($active) and $active == 'Y' and $security != $userpass) { + if (!isset($sID) and isset($active) and $active == 'Y' and isset($passwordCorrect) and $passwordCorrect === false) { $authLookupID = ($resellerid == $id) ? 0 : $resellerid; @@ -316,11 +298,10 @@ if ($xmlReply and isset($xmlReply->success) and $xmlReply->success == 1 and $xmlReply->user == $username) { - $externalOK = 1; - $salt = md5(mt_rand() . date('Y-m-d H:i:s:u')); + $passwordCorrect = true; - $query = $sql->prepare("UPDATE `userdata` SET `security`=?,`salt`=? WHERE `id`=? LIMIT 1"); - $query->execute(array(createHash($username, $password, $salt, $aeskey), $salt, $id)); + $query = $sql->prepare("UPDATE `userdata` SET `security`=? WHERE `id`=? LIMIT 1"); + $query->execute(array(password_hash($password, PASSWORD_DEFAULT), $id)); } else if ($xmlReply and isset($xmlReply->error)) { $externalAuthError = $xmlReply->error; @@ -331,7 +312,7 @@ } } - if (isset($active) and $active == 'Y' and ($security == $userpass or (isset($externalOK) and $externalOK == 1))) { + if (isset($active) and $active == 'Y' and isset($passwordCorrect) and $passwordCorrect) { session_unset(); session_destroy(); @@ -433,7 +414,7 @@ } } - } else if (!isset($security) or $security != $userpass) { + } else if (!isset($passwordCorrect) or $passwordCorrect === false) { $halfhour = date('Y-m-d H:i:s', strtotime('+30 minutes')); diff --git a/web/stuff/api_users.php b/web/stuff/api_users.php index ec3a6ce8..4105d5cb 100644 --- a/web/stuff/api_users.php +++ b/web/stuff/api_users.php @@ -38,6 +38,7 @@ */ include(EASYWIDIR . '/stuff/keyphrasefile.php'); +include(EASYWIDIR . '/third_party/password_compat/password.php'); $username = ''; $externalID = ''; @@ -170,11 +171,14 @@ } if (!isset($success) and isset($localID) and isset($insert) and $insert == true) { if (!isset($data['password']) or in_array($data['password'],$bad)) $password=passwordgenerate(10); - $passwordhash=createHash($username,$password,$salt,$aeskey); + $query = $sql->prepare("UPDATE `userdata` SET `cname`=?,`security`=? WHERE `id`=? LIMIT 1"); - $query->execute(array($username,$passwordhash,$localID)); + $query->execute(array($username, password_hash($password, PASSWORD_DEFAULT), $localID)); + $query = $sql->prepare("INSERT INTO `userdata_groups` (`userID`,`groupID`,`resellerID`) VALUES (?,?,?)"); - foreach ($userGroupIDs as $groupID) $query->execute(array($localID,$groupID,$resellerID)); + foreach ($userGroupIDs as $groupID) { + $query->execute(array($localID, $groupID, $resellerID)); + } } else if (!isset($success)) { $success['false'][] = 'Could not write user to database'; } @@ -200,10 +204,7 @@ $what = array(); if (isset($data['password']) and !in_array($data['password'],$bad)) { $password = $data['password']; - $salt=md5(mt_rand().date('Y-m-d H:i:s:u')); - $security=createHash($name,$data['password'],$salt,$aeskey); - $what['security'] = $security; - $what['salt'] = $salt; + $what['security'] = password_hash($password, PASSWORD_DEFAULT); } if (isset($data['email']) and ismail($data['email'])) { $what['mail'] = $data['email']; diff --git a/web/stuff/functions.php b/web/stuff/functions.php index fbe5d6ad..0c60d8c3 100644 --- a/web/stuff/functions.php +++ b/web/stuff/functions.php @@ -89,7 +89,25 @@ function createHash ($name, $pwd, $saltOne, $saltTwo = 'ZPZw$[pkJF!;SHdl', $iter return false; } - + + function passwordCheck ($password, $storedHash, $username = '', $salt = '', $aeskey = '') { + + // Easy-WI uses the PHP hash API introduced with version 5.5. + + // Return true in case the password is ok + if (password_verify($password, $storedHash)) { + return true; + + // Password is correctly but stored in an old or insecure format. We need to hash it with a secure implementation. + // Insecure implementations like md5 or sha1 are imported from other systems with the cloud.php job. + } else if (createHash($username, $password, $salt, $aeskey) == $storedHash or md5($password) == $storedHash or sha1($password) == $storedHash or passwordhash($username, $password) == $storedHash) { + return password_hash($password, PASSWORD_DEFAULT); + } + + // Password Is Not Correct + return false; + } + function szrp ($value) { $szrm = array('ä' => 'ae','ö' => 'oe','ü' => 'ue','Ä' => 'Ae','Ö' => 'Oe','Ü' => 'Ue','ß' => 'ss','á' => 'a','à' => 'a','Á' => 'A','À' => 'A','é' => 'e','è' => 'e','É' => 'E','È' => 'E','ó' => 'o','ò' => 'o','Ó' => 'O','Ò' => 'O','ú' => 'u','ù' => 'u','Ú' => 'U','Ù' => 'U'); return strtolower(preg_replace('/[^a-zA-Z0-9]{1}/', '-', strtr($value, $szrm))); diff --git a/web/stuff/global_userdata.php b/web/stuff/global_userdata.php index 44269fb0..212d3388 100644 --- a/web/stuff/global_userdata.php +++ b/web/stuff/global_userdata.php @@ -36,6 +36,7 @@ */ include(EASYWIDIR . '/stuff/keyphrasefile.php'); +include(EASYWIDIR . '/third_party/password_compat/password.php'); if ($ui->st('w', 'get') == 'se') { if ((!isset($user_id) or $main!=1) or (isset($user_id) and !$pa['usersettings'])) { @@ -88,10 +89,8 @@ $query = $sql->prepare("SELECT `cname` FROM `userdata` WHERE `id`=? AND `resellerid`=? LIMIT 1"); $query->execute(array($lookUpID,$reseller_id)); $cname = $query->fetchColumn(); - $salt = md5(mt_rand().date('Y-m-d H:i:s:u')); - $security = createHash($cname,$ui->password('pass2', 255, 'post'),$salt,$aeskey); - $query = $sql->prepare("UPDATE `userdata` SET `updateTime`=NOW(),`security`=?,`salt`=? WHERE `id`=? AND `resellerid`=? LIMIT 1"); - $query->execute(array($security,$salt,$lookUpID,$reseller_id)); + $query = $sql->prepare("UPDATE `userdata` SET `updateTime`=NOW(),`security`=? WHERE `id`=? AND `resellerid`=? LIMIT 1"); + $query->execute(array(password_hash($password, PASSWORD_DEFAULT) ,$lookUpID,$reseller_id)); if ($query->rowCount()>0) { $template_file = $spracheResponse->table_add; $loguseraction="%psw% %user% $cname"; diff --git a/web/stuff/page_register.php b/web/stuff/page_register.php index 82d1345b..ba137e99 100644 --- a/web/stuff/page_register.php +++ b/web/stuff/page_register.php @@ -1,4 +1,5 @@ . */ +include(EASYWIDIR . '/third_party/password_compat/password.php'); + if (!isset($page_include) or (isset($user_id)) or isset($admin_id) or isset($reseller_id)) { if (isset($page_data->canurl)) header('Location: '.$page_data->canurl); else header('Location: index.php'); @@ -159,11 +162,8 @@ $query->execute(array($mail,$activeHash,$salutation = $ui->id('salutation',1, 'post'),$ui->st('country', 'post'),$name,$vname,$bday,$ui->phone('phone',50, 'post'),$ui->phone('fax',50, 'post'),$ui->phone('handy',50, 'post'),$ui->names('city',50, 'post'),$ui->id('cityn',6, 'post'),$ui->names('street',50, 'post'),$ui->w('streetn',6, 'post'))); $userID = $sql->lastInsertId(); - // generate hash - $hash=createHash($rSA['prefix2'].$userID,$ui->password('password',100, 'post'),$userSalt,$aeskey); - $query = $sql->prepare("UPDATE `userdata` SET `cname`=?,`security`=?,`salt`=? WHERE `id`=? LIMIT 1"); - $query->execute(array($rSA['prefix2'].$userID,$hash,$userSalt,$userID)); + $query->execute(array($rSA['prefix2'].$userID, password_hash($ui->password('password', 100, 'post'), PASSWORD_DEFAULT), $userID)); // Setup default Group $query = $sql->prepare("SELECT `id` FROM `usergroups` WHERE `grouptype`='u' AND `active`='Y' AND `defaultgroup`='Y' AND `resellerid`=0 LIMIT 1"); diff --git a/web/stuff/user.php b/web/stuff/user.php index e0481ae1..8d917c09 100644 --- a/web/stuff/user.php +++ b/web/stuff/user.php @@ -1,4 +1,5 @@ . */ + +include(EASYWIDIR . '/stuff/keyphrasefile.php'); +include(EASYWIDIR . '/third_party/password_compat/password.php'); + if ((!isset($admin_id) or $main!=1) or (isset($admin_id) and !$pa['user'] and !$pa['user_users'])) { header('Location: admin.php'); die(); } -include(EASYWIDIR . '/stuff/keyphrasefile.php'); $sprache = getlanguagefile('user',$user_language,$reseller_id); $rsprache = getlanguagefile('reseller',$user_language,$reseller_id); $loguserid = $admin_id; @@ -281,17 +285,14 @@ function CopyAdminTable ($tablename,$id,$reseller_id,$limit,$sql,$where='') { $resellersid = $reseller_id; } - $salt = md5(mt_rand() . date('Y-m-d H:i:s:u')); - $security2 = createHash($cnamenew, $password, $salt, $aeskey); - - $query = $sql->prepare("UPDATE `userdata` SET `cname`=?,`security`=?,`salt`=?,`resellerid`=? WHERE `id`=? LIMIT 1"); + $query = $sql->prepare("UPDATE `userdata` SET `cname`=?,`security`=?,`resellerid`=? WHERE `id`=? LIMIT 1"); if ($user_accounttype == 'a') { - $query->execute(array($cnamenew, $security2, $salt, $id, $id)); + $query->execute(array($cnamenew, password_hash($password, PASSWORD_DEFAULT), $id, $id)); } else if ($user_accounttype == 'r' and $admin_id == $reseller_id) { - $query->execute(array($cnamenew, $security2, $salt, $reseller_id, $id)); + $query->execute(array($cnamenew, password_hash($password, PASSWORD_DEFAULT), $reseller_id, $id)); } else if ($user_accounttype == 'r') { - $query->execute(array($cnamenew, $security2, $salt, $admin_id, $id)); + $query->execute(array($cnamenew, password_hash($password, PASSWORD_DEFAULT), $admin_id, $id)); } sendmail('emailuseradd',$id,$cnamenew,$password); @@ -631,10 +632,8 @@ function CopyAdminTable ($tablename,$id,$reseller_id,$limit,$sql,$where='') { } else { if ($reseller_id != 0 and $admin_id != $reseller_id) $reseller_id = $admin_id; $password = $ui->password('password',20, 'post'); - $salt=md5(mt_rand().date('Y-m-d H:i:s:u')); - $security=createHash($cname,$password,$salt,$aeskey); - $query=($reseller_id == 0) ? $sql->prepare("UPDATE `userdata` SET `updateTime`=NOW(),`security`=?,`salt`=? WHERE id=? AND (`resellerid`=? OR `id`=`resellerid`) LIMIT 1") : $sql->prepare("UPDATE `userdata` SET `updateTime`=NOW(),`security`=?,`salt`=? WHERE id=? AND `resellerid`=? LIMIT 1"); - $query->execute(array($security,$salt,$id,$reseller_id)); + $query=($reseller_id == 0) ? $sql->prepare("UPDATE `userdata` SET `updateTime`=NOW(),`security`=? WHERE id=? AND (`resellerid`=? OR `id`=`resellerid`) LIMIT 1") : $sql->prepare("UPDATE `userdata` SET `updateTime`=NOW(),`security`=?,`salt`=? WHERE id=? AND `resellerid`=? LIMIT 1"); + $query->execute(array(password_hash($password, PASSWORD_DEFAULT), $id, $reseller_id)); $template_file = $spracheResponse->table_add ."
"; $loguseraction="%psw% %user% $cname"; $insertlog->execute(); diff --git a/web/stuff/userpanel_substitutes.php b/web/stuff/userpanel_substitutes.php index e99b9377..f51c147f 100644 --- a/web/stuff/userpanel_substitutes.php +++ b/web/stuff/userpanel_substitutes.php @@ -39,13 +39,14 @@ * Programm erhalten haben. Wenn nicht, siehe . */ +include(EASYWIDIR . '/stuff/keyphrasefile.php'); +include(EASYWIDIR . '/third_party/password_compat/password.php'); + if (!isset($main) or $main!=1 or !isset($user_id) or !isset($user_language) or !isset($reseller_id) or isset($_SESSION['substitute'])) { header('Location: userpanel.php'); die; } -include(EASYWIDIR . '/stuff/keyphrasefile.php'); - $sprache = getlanguagefile('user',$user_language,$reseller_id); if ($ui->w('action', 4, 'post') and !token(true)) { $template_file = $spracheResponse->token; @@ -113,8 +114,8 @@ $template_file = $userError; } else { $salt=md5(mt_rand().date('Y-m-d H:i:s:u')); - $query = $sql->prepare("INSERT INTO `userdata_substitutes` (`userID`,`active`,`loginName`,`name`,`vname`,`salt`,`passwordHashed`,`resellerID`) VALUES (?,?,?,?,?,?,?,?)"); - $query->execute(array($user_id,$ui->active('active', 'post'),$ui->names('loginName',255, 'post'),$ui->names('name',255, 'post'),$ui->names('vname',255, 'post'),$salt,createHash($ui->names('loginName',255, 'post'),$ui->password('security',255, 'post'),$salt,$aeskey),$reseller_id)); + $query = $sql->prepare("INSERT INTO `userdata_substitutes` (`userID`,`active`,`loginName`,`name`,`vname`,`passwordHashed`,`resellerID`) VALUES (?,?,?,?,?,?,?)"); + $query->execute(array($user_id,$ui->active('active', 'post'),$ui->names('loginName',255, 'post'),$ui->names('name',255, 'post'),$ui->names('vname',255, 'post'), password_hash($ui->password('security',255, 'post'), PASSWORD_DEFAULT), $reseller_id)); if ($query->rowCount()>0) { $changed = true; } @@ -126,8 +127,8 @@ $query = $sql->prepare("SELECT `loginName` FROM `userdata_substitutes` WHERE `sID`=? AND `resellerID`=? LIMIT 1"); $query->execute(array($id,$reseller_id)); $loginName = $query->fetchColumn(); - $query = $sql->prepare("UPDATE `userdata_substitutes` SET `active`=?,`name`=?,`vname`=?,`salt`=?,`passwordHashed`=? WHERE `sID`=? AND `userID`=? AND `resellerID`=? LIMIT 1"); - $query->execute(array($ui->active('active', 'post'),$ui->names('name',255, 'post'),$ui->names('vname',255, 'post'),$salt,createHash($loginName,$ui->password('security',255, 'post'),$salt,$aeskey),$id,$user_id,$reseller_id)); + $query = $sql->prepare("UPDATE `userdata_substitutes` SET `active`=?,`name`=?,`vname`=?,`passwordHashed`=? WHERE `sID`=? AND `userID`=? AND `resellerID`=? LIMIT 1"); + $query->execute(array($ui->active('active', 'post'),$ui->names('name',255, 'post'),$ui->names('vname',255, 'post'),password_hash($ui->password('security',255, 'post'), PASSWORD_DEFAULT), $id,$user_id,$reseller_id)); } else { $query = $sql->prepare("UPDATE `userdata_substitutes` SET `active`=?,`name`=?,`vname`=? WHERE `sID`=? AND `userID`=? AND `resellerID`=? LIMIT 1"); $query->execute(array($ui->active('active', 'post'),$ui->names('name',255, 'post'),$ui->names('vname',255, 'post'),$id,$user_id,$reseller_id)); diff --git a/web/stuff/voice_master.php b/web/stuff/voice_master.php index dc6ee831..c3381e20 100644 --- a/web/stuff/voice_master.php +++ b/web/stuff/voice_master.php @@ -41,6 +41,7 @@ include(EASYWIDIR . '/stuff/keyphrasefile.php'); include(EASYWIDIR . '/stuff/class_voice.php'); include(EASYWIDIR . '/stuff/ssh_exec.php'); +include(EASYWIDIR . '/third_party/password_compat/password.php'); if ((!isset($admin_id) or $main != 1) or (isset($admin_id) and !$pa['voicemasterserver'])) { header('Location: admin.php'); @@ -662,12 +663,9 @@ } if ($usernew == true) { - $initialpassword = passwordgenerate(10); - $salt = md5(mt_rand() . date('Y-m-d H:i:s:u')); - $security = createHash($ui->username("$virtualserver_id-username",50, 'post'), $initialpassword, $salt, $aeskey); - $query = $sql->prepare("INSERT INTO `userdata` (`cname`,`security`,`mail`,`accounttype`,`salt`,`resellerid`) VALUES (?,?,?,'u',?,?)"); - $query->execute(array($ui->username("$virtualserver_id-username",50, 'post'), $security, $ui->ismail("$virtualserver_id-email", 'post'), $salt, $reseller_id)); + $query = $sql->prepare("INSERT INTO `userdata` (`cname`,`security`,`mail`,`accounttype`,`resellerid`) VALUES (?,?,?,'u',?)"); + $query->execute(array($ui->username("$virtualserver_id-username",50, 'post'), password_hash(passwordgenerate(10), PASSWORD_DEFAULT), $ui->ismail("$virtualserver_id-email", 'post'), $reseller_id)); $query = $sql->prepare("SELECT `id` FROM `userdata` WHERE `cname`=? AND `mail`=? AND `resellerid`=? ORDER BY `id` DESC LIMIT 1"); $query->execute(array($ui->username("$virtualserver_id-username",50, 'post'), $ui->ismail("$virtualserver_id-email", 'post'), $reseller_id)); diff --git a/web/stuff/voice_tsdns.php b/web/stuff/voice_tsdns.php index 9a02860d..26712c22 100644 --- a/web/stuff/voice_tsdns.php +++ b/web/stuff/voice_tsdns.php @@ -1,4 +1,5 @@ username("${lookUp}-username",50, 'post'); } if ($usernew == true) { - $initialpassword=passwordgenerate(10); - $salt=md5(mt_rand().date('Y-m-d H:i:s:u')); - $security=createHash($ui->username("${lookUp}-username",50, 'post'),$initialpassword,$salt,$aeskey); $query = $sql->prepare("INSERT INTO `userdata` (`cname`,`security`,`mail`,`accounttype`,`resellerid`) VALUES (?,?,?,'u',?)"); - $query->execute(array($ui->username("${lookUp}-username",50, 'post'),$security,$ui->ismail("${lookUp}-email", 'post'),$reseller_id)); + $query->execute(array($ui->username("${lookUp}-username",50, 'post'),password_hash(passwordgenerate(10), PASSWORD_DEFAULT),$ui->ismail("${lookUp}-email", 'post'),$reseller_id)); $query = $sql->prepare("SELECT `id` FROM `userdata` WHERE `cname`=? AND `mail`=? AND `resellerid`=? ORDER BY `id` DESC LIMIT 1"); $query->execute(array($ui->username("${lookUp}-username",50, 'post'),$ui->ismail("${lookUp}-email", 'post'),$reseller_id)); foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) { diff --git a/web/template/default/page_header.tpl b/web/template/default/page_header.tpl index da741f03..7d63c890 100644 --- a/web/template/default/page_header.tpl +++ b/web/template/default/page_header.tpl @@ -140,8 +140,8 @@ lendactive=='Y'){ ?>
  • >pages['lendserver']['href'];?>
  • -
  • >pages['lendservervoice']['href'];?>
  • -
  • >pages['lendservergs']['href'];?>
  • + pages['lendservervoice'])) { ?>
  • >pages['lendservervoice']['href'];?>
  • + pages['lendservergs'])) { ?>
  • >pages['lendservergs']['href'];?>
  • diff --git a/web/third_party/password_compat/password.php b/web/third_party/password_compat/password.php new file mode 100644 index 00000000..311df947 --- /dev/null +++ b/web/third_party/password_compat/password.php @@ -0,0 +1,219 @@ + + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @copyright 2012 The Authors + */ + +if (!defined('PASSWORD_DEFAULT')) { + + define('PASSWORD_BCRYPT', 1); + define('PASSWORD_DEFAULT', PASSWORD_BCRYPT); + + /** + * Hash the password using the specified algorithm + * + * @param string $password The password to hash + * @param int $algo The algorithm to use (Defined by PASSWORD_* constants) + * @param array $options The options for the algorithm to use + * + * @return string|false The hashed password, or false on error. + */ + function password_hash($password, $algo, array $options = array()) { + if (!function_exists('crypt')) { + trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING); + return null; + } + if (!is_string($password)) { + trigger_error("password_hash(): Password must be a string", E_USER_WARNING); + return null; + } + if (!is_int($algo)) { + trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING); + return null; + } + switch ($algo) { + case PASSWORD_BCRYPT: + // Note that this is a C constant, but not exposed to PHP, so we don't define it here. + $cost = 10; + if (isset($options['cost'])) { + $cost = $options['cost']; + if ($cost < 4 || $cost > 31) { + trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING); + return null; + } + } + // The length of salt to generate + $raw_salt_len = 16; + // The length required in the final serialization + $required_salt_len = 22; + $hash_format = sprintf("$2y$%02d$", $cost); + break; + default: + trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING); + return null; + } + if (isset($options['salt'])) { + switch (gettype($options['salt'])) { + case 'NULL': + case 'boolean': + case 'integer': + case 'double': + case 'string': + $salt = (string) $options['salt']; + break; + case 'object': + if (method_exists($options['salt'], '__tostring')) { + $salt = (string) $options['salt']; + break; + } + case 'array': + case 'resource': + default: + trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING); + return null; + } + if (strlen($salt) < $required_salt_len) { + trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", strlen($salt), $required_salt_len), E_USER_WARNING); + return null; + } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) { + $salt = str_replace('+', '.', base64_encode($salt)); + } + } else { + $buffer = ''; + $buffer_valid = false; + if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) { + $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM); + if ($buffer) { + $buffer_valid = true; + } + } + if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) { + $buffer = openssl_random_pseudo_bytes($raw_salt_len); + if ($buffer) { + $buffer_valid = true; + } + } + if (!$buffer_valid && is_readable('/dev/urandom')) { + $f = fopen('/dev/urandom', 'r'); + $read = strlen($buffer); + while ($read < $raw_salt_len) { + $buffer .= fread($f, $raw_salt_len - $read); + $read = strlen($buffer); + } + fclose($f); + if ($read >= $raw_salt_len) { + $buffer_valid = true; + } + } + if (!$buffer_valid || strlen($buffer) < $raw_salt_len) { + $bl = strlen($buffer); + for ($i = 0; $i < $raw_salt_len; $i++) { + if ($i < $bl) { + $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255)); + } else { + $buffer .= chr(mt_rand(0, 255)); + } + } + } + $salt = str_replace('+', '.', base64_encode($buffer)); + } + $salt = substr($salt, 0, $required_salt_len); + + $hash = $hash_format . $salt; + + $ret = crypt($password, $hash); + + if (!is_string($ret) || strlen($ret) <= 13) { + return false; + } + + return $ret; + } + + /** + * Get information about the password hash. Returns an array of the information + * that was used to generate the password hash. + * + * array( + * 'algo' => 1, + * 'algoName' => 'bcrypt', + * 'options' => array( + * 'cost' => 10, + * ), + * ) + * + * @param string $hash The password hash to extract info from + * + * @return array The array of information about the hash. + */ + function password_get_info($hash) { + $return = array( + 'algo' => 0, + 'algoName' => 'unknown', + 'options' => array(), + ); + if (substr($hash, 0, 4) == '$2y$' && strlen($hash) == 60) { + $return['algo'] = PASSWORD_BCRYPT; + $return['algoName'] = 'bcrypt'; + list($cost) = sscanf($hash, "$2y$%d$"); + $return['options']['cost'] = $cost; + } + return $return; + } + + /** + * Determine if the password hash needs to be rehashed according to the options provided + * + * If the answer is true, after validating the password using password_verify, rehash it. + * + * @param string $hash The hash to test + * @param int $algo The algorithm used for new password hashes + * @param array $options The options array passed to password_hash + * + * @return boolean True if the password needs to be rehashed. + */ + function password_needs_rehash($hash, $algo, array $options = array()) { + $info = password_get_info($hash); + if ($info['algo'] != $algo) { + return true; + } + switch ($algo) { + case PASSWORD_BCRYPT: + $cost = isset($options['cost']) ? $options['cost'] : 10; + if ($cost != $info['options']['cost']) { + return true; + } + break; + } + return false; + } + + /** + * Verify a password against a hash using a timing attack resistant approach + * + * @param string $password The password to verify + * @param string $hash The hash to verify against + * + * @return boolean If the password matches the hash + */ + function password_verify($password, $hash) { + if (!function_exists('crypt')) { + trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING); + return false; + } + $ret = crypt($password, $hash); + if (!is_string($ret) || strlen($ret) != strlen($hash) || strlen($ret) <= 13) { + return false; + } + + $status = 0; + for ($i = 0; $i < strlen($ret); $i++) { + $status |= (ord($ret[$i]) ^ ord($hash[$i])); + } + + return $status === 0; + } +} \ No newline at end of file