From 2d6d9eb4ffaaf5371ecfba1734ab1f86873013ea Mon Sep 17 00:00:00 2001
From: Marius Burkard <m.burkard@pixcept.de>
Date: Sat, 27 Jul 2019 21:18:24 +0200
Subject: [PATCH] - Support CRYPT-SHA512 and SHA256 for passwords, implements
 #5353

---
 .../sql/incremental/upd_dev_collection.sql    |  5 ++++
 install/sql/ispconfig3.sql                    | 10 ++++----
 interface/lib/classes/auth.inc.php            | 25 +++++++++++++++----
 interface/lib/classes/remote.d/client.inc.php | 14 ++++-------
 interface/lib/classes/remoting.inc.php        | 10 ++------
 interface/web/admin/users_edit.php            | 10 +++-----
 interface/web/client/reseller_edit.php        | 24 +++++++-----------
 7 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/install/sql/incremental/upd_dev_collection.sql b/install/sql/incremental/upd_dev_collection.sql
index e69de29bb2..d5b7b0e017 100644
--- a/install/sql/incremental/upd_dev_collection.sql
+++ b/install/sql/incremental/upd_dev_collection.sql
@@ -0,0 +1,5 @@
+ALTER TABLE `client` CHANGE COLUMN `password` `password` VARCHAR(200) DEFAULT NULL;
+ALTER TABLE `ftp_user` CHANGE COLUMN `password` `password` VARCHAR(200) DEFAULT NULL;
+ALTER TABLE `shell_user` CHANGE COLUMN `password` `password` VARCHAR(200) DEFAULT NULL;
+ALTER TABLE `sys_user` CHANGE COLUMN `passwort` `passwort` VARCHAR(200) DEFAULT NULL;
+ALTER TABLE `webdav_user` CHANGE COLUMN `password` `password` VARCHAR(200) DEFAULT NULL;
\ No newline at end of file
diff --git a/install/sql/ispconfig3.sql b/install/sql/ispconfig3.sql
index 2417ef0d21..3f534eedf0 100644
--- a/install/sql/ispconfig3.sql
+++ b/install/sql/ispconfig3.sql
@@ -243,7 +243,7 @@ CREATE TABLE `client` (
   `limit_openvz_vm_template_id` int(11) NOT NULL DEFAULT '0',
   `parent_client_id` int(11) unsigned NOT NULL DEFAULT '0',
   `username` varchar(64) DEFAULT NULL,
-  `password` varchar(64) DEFAULT NULL,
+  `password` varchar(200) DEFAULT NULL,
   `language` char(2) NOT NULL DEFAULT 'en',
   `usertheme` varchar(32) NOT NULL DEFAULT 'default',
   `template_master` int(11) unsigned NOT NULL DEFAULT '0',
@@ -705,7 +705,7 @@ CREATE TABLE `ftp_user` (
   `parent_domain_id` int(11) unsigned NOT NULL default '0',
   `username` varchar(64) default NULL,
   `username_prefix` varchar(50) NOT NULL default '',
-  `password` varchar(64) default NULL,
+  `password` varchar(200) default NULL,
   `quota_size` bigint(20) NOT NULL default '-1',
   `active` enum('n','y') NOT NULL default 'y',
   `uid` varchar(64) default NULL,
@@ -1440,7 +1440,7 @@ CREATE TABLE `shell_user` (
   `parent_domain_id` int(11) unsigned NOT NULL default '0',
   `username` varchar(64) default NULL,
   `username_prefix` varchar(50) NOT NULL default '',
-  `password` varchar(64) default NULL,
+  `password` varchar(200) default NULL,
   `quota_size` bigint(20) NOT NULL default '-1',
   `active` enum('n','y') NOT NULL default 'y',
   `puser` varchar(255) default NULL,
@@ -1864,7 +1864,7 @@ CREATE TABLE `sys_user` (
   `sys_perm_group` varchar(5) NOT NULL default 'riud',
   `sys_perm_other` varchar(5) NOT NULL default '',
   `username` varchar(64) NOT NULL default '',
-  `passwort` varchar(64) NOT NULL default '',
+  `passwort` varchar(200) NOT NULL default '',
   `modules` varchar(255) NOT NULL default '',
   `startmodule` varchar(255) NOT NULL default '',
   `app_theme` varchar(32) NOT NULL default 'default',
@@ -1899,7 +1899,7 @@ CREATE TABLE `webdav_user` (
   `parent_domain_id` int(11) unsigned NOT NULL DEFAULT '0',
   `username` varchar(64) DEFAULT NULL,
   `username_prefix` varchar(50) NOT NULL default '',
-  `password` varchar(64) DEFAULT NULL,
+  `password` varchar(200) DEFAULT NULL,
   `active` enum('n','y') NOT NULL DEFAULT 'y',
   `dir` varchar(255) DEFAULT NULL,
   PRIMARY KEY (`webdav_user_id`)
diff --git a/interface/lib/classes/auth.inc.php b/interface/lib/classes/auth.inc.php
index 6658c4c116..afe50ac692 100644
--- a/interface/lib/classes/auth.inc.php
+++ b/interface/lib/classes/auth.inc.php
@@ -231,12 +231,27 @@ class auth {
 		if($charset != 'UTF-8') {
 			$cleartext_password = mb_convert_encoding($cleartext_password, $charset, 'UTF-8');
 		}
-		$salt="$1$";
-		$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-		for ($n=0;$n<8;$n++) {
-			$salt.=$base64_alphabet[mt_rand(0, 63)];
+		
+		if(defined('CRYPT_SHA512') && CRYPT_SHA512 == 1) {
+			$salt = '$6$rounds=5000$';
+			$salt_length = 16;
+		} elseif(defined('CRYPT_SHA256') && CRYPT_SHA256 == 1) {
+			$salt = '$5$rounds=5000$';
+			$salt_length = 16;
+		} else {
+			$salt = '$1$';
+			$salt_length = 12;
+		}
+		
+		if(function_exists('openssl_random_pseudo_bytes')) {
+			$salt .= substr(bin2hex(openssl_random_pseudo_bytes($salt_length)), 0, $salt_length);
+		} else {
+			$base64_alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
+			for($n = 0; $n < $salt_length; $n++) {
+				$salt .= $base64_alphabet[mt_rand(0, 63)];
+			}
 		}
-		$salt.="$";
+		$salt .= "$";
 		return crypt($cleartext_password, $salt);
 	}
 	
diff --git a/interface/lib/classes/remote.d/client.inc.php b/interface/lib/classes/remote.d/client.inc.php
index b91909c9d3..e07e227e60 100644
--- a/interface/lib/classes/remote.d/client.inc.php
+++ b/interface/lib/classes/remote.d/client.inc.php
@@ -604,11 +604,9 @@ class remoting_client extends remoting {
 			if($user) {
 				$saved_password = stripslashes($user['password']);
 
-				if(substr($saved_password, 0, 3) == '$1$') {
-					//* The password is crypt-md5 encrypted
-					$salt = '$1$'.substr($saved_password, 3, 8).'$';
-
-					if(crypt(stripslashes($password), $salt) != $saved_password) {
+				if(preg_match('/^\$[156]\$/', $saved_password)) {
+					//* The password is crypt encrypted
+					if(crypt(stripslashes($password), $saved_password) !== $saved_password) {
 						$user = false;
 					}
 				} else {
@@ -636,11 +634,9 @@ class remoting_client extends remoting {
 			if($user) {
 				$saved_password = stripslashes($user['passwort']);
 
-				if(substr($saved_password, 0, 3) == '$1$') {
+				if(preg_match('/^\$[156]\$/', $saved_password)) {
 					//* The password is crypt-md5 encrypted
-					$salt = '$1$'.substr($saved_password, 3, 8).'$';
-
-					if(crypt(stripslashes($password), $salt) != $saved_password) {
+					if(crypt(stripslashes($password), $saved_password) != $saved_password) {
 						$user = false;
 					}
 				} else {
diff --git a/interface/lib/classes/remoting.inc.php b/interface/lib/classes/remoting.inc.php
index 6e551355a6..e1fc1ada86 100644
--- a/interface/lib/classes/remoting.inc.php
+++ b/interface/lib/classes/remoting.inc.php
@@ -99,28 +99,22 @@ class remoting {
 			if($user) {
 				$saved_password = stripslashes($user['passwort']);
 
-				if(substr($saved_password, 0, 3) == '$1$') {
+				if(preg_match('/^\$[156]\$/', $saved_password)) {
 					//* The password is crypt-md5 encrypted
-					$salt = '$1$'.substr($saved_password, 3, 8).'$';
-
-					if(crypt(stripslashes($password), $salt) != $saved_password) {
+					if(crypt(stripslashes($password), $saved_password) != $saved_password) {
 						throw new SoapFault('client_login_failed', 'The login failed. Username or password wrong.');
-						return false;
 					}
 				} else {
 					//* The password is md5 encrypted
 					if(md5($password) != $saved_password) {
 						throw new SoapFault('client_login_failed', 'The login failed. Username or password wrong.');
-						return false;
 					}
 				}
 			} else {
 				throw new SoapFault('client_login_failed', 'The login failed. Username or password wrong.');
-				return false;
 			}
 			if($user['active'] != 1) {
 				throw new SoapFault('client_login_failed', 'The login failed. User is blocked.');
-				return false;
 			}
 
 			// now we need the client data
diff --git a/interface/web/admin/users_edit.php b/interface/web/admin/users_edit.php
index 4c5c97409f..7f0c691c42 100644
--- a/interface/web/admin/users_edit.php
+++ b/interface/web/admin/users_edit.php
@@ -104,6 +104,8 @@ class page_action extends tform_actions {
 	function onAfterUpdate() {
 		global $app, $conf;
 
+		$app->uses('auth');
+		
 		$client = $app->db->queryOneRecord("SELECT * FROM sys_user WHERE userid = ?", $this->id);
 		$client_id = $app->functions->intval($client['client_id']);
 		$username = $this->dataRecord["username"];
@@ -121,13 +123,7 @@ class page_action extends tform_actions {
 		// password changed
 		if(isset($conf['demo_mode']) && $conf['demo_mode'] != true && isset($this->dataRecord["passwort"]) && $this->dataRecord["passwort"] != '') {
 			$password = $this->dataRecord["passwort"];
-			$salt="$1$";
-			$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-			for ($n=0;$n<8;$n++) {
-				$salt.=$base64_alphabet[mt_rand(0, 63)];
-			}
-			$salt.="$";
-			$password = crypt(stripslashes($password), $salt);
+			$password = $app->auth->crypt_password($password);
 			$sql = "UPDATE client SET password = ? WHERE client_id = ? AND username = ?";
 			$app->db->query($sql, $password, $client_id, $username);
 		}
diff --git a/interface/web/client/reseller_edit.php b/interface/web/client/reseller_edit.php
index 59699ec163..3078e01fbc 100644
--- a/interface/web/client/reseller_edit.php
+++ b/interface/web/client/reseller_edit.php
@@ -200,6 +200,9 @@ class page_action extends tform_actions {
 	*/
 	function onAfterInsert() {
 		global $app, $conf;
+		
+		$app->uses('auth');
+		
 		// Create the group for the reseller
 		$groupid = $app->db->datalogInsert('sys_group', array("name" => $this->dataRecord["username"], "description" => '', "client_id" => $this->id), 'groupid');
 		$groups = $groupid;
@@ -213,14 +216,8 @@ class page_action extends tform_actions {
 		$active = 1;
 		$language = $this->dataRecord["language"];
 
-		$salt="$1$";
-		$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-		for ($n=0;$n<8;$n++) {
-			$salt.=$base64_alphabet[mt_rand(0, 63)];
-		}
-		$salt.="$";
-		$password = crypt(stripslashes($password), $salt);
-
+		$password = $app->auth->crypt_password(stripslashes($password));
+		
 		// Create the controlpaneluser for the reseller
 		$sql = "INSERT INTO sys_user (`username`,`passwort`,`modules`,`startmodule`,`app_theme`,`typ`, `active`,`language`,`groups`,`default_group`,`client_id`)
 		VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
@@ -313,6 +310,8 @@ class page_action extends tform_actions {
 	function onAfterUpdate() {
 		global $app, $conf;
 
+		$app->uses('auth');
+		
 		// username changed
 		if(isset($conf['demo_mode']) && $conf['demo_mode'] != true && isset($this->dataRecord['username']) && $this->dataRecord['username'] != '' && $this->oldDataRecord['username'] != $this->dataRecord['username']) {
 			$username = $this->dataRecord["username"];
@@ -329,13 +328,8 @@ class page_action extends tform_actions {
 		if(isset($conf['demo_mode']) && $conf['demo_mode'] != true && isset($this->dataRecord["password"]) && $this->dataRecord["password"] != '') {
 			$password = $this->dataRecord["password"];
 			$client_id = $this->id;
-			$salt="$1$";
-			$base64_alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-			for ($n=0;$n<8;$n++) {
-				$salt.=$base64_alphabet[mt_rand(0, 63)];
-			}
-			$salt.="$";
-			$password = crypt(stripslashes($password), $salt);
+			
+			$password = $app->auth->crypt_password(stripslashes($password));
 			$sql = "UPDATE sys_user SET passwort = ? WHERE client_id = ?";
 			$app->db->query($sql, $password, $client_id);
 		}
-- 
GitLab