Skip to content

Commit 0df5c4b

Browse files
author
Marius Burkard
committed
Merge branch 'develop' into 'develop'
Improve security Closes #5985 and #5984 See merge request ispconfig/ispconfig3!1380
2 parents fd59be5 + a739ab2 commit 0df5c4b

File tree

10 files changed

+110
-80
lines changed

10 files changed

+110
-80
lines changed

install/dist/lib/fedora.lib.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,8 +1227,8 @@ public function install_ispconfig()
12271227
caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
12281228

12291229
if ($this->install_ispconfig_interface == true && isset($conf['interface_password']) && $conf['interface_password']!='admin') {
1230-
$sql = "UPDATE sys_user SET passwort = md5(?) WHERE username = 'admin';";
1231-
$this->db->query($sql, $conf['interface_password']);
1230+
$sql = "UPDATE sys_user SET passwort = ? WHERE username = 'admin';";
1231+
$this->db->query($sql, $this->crypt_password($conf['interface_password']));
12321232
}
12331233

12341234
if($conf['apache']['installed'] == true && $this->install_ispconfig_interface == true){
@@ -1372,6 +1372,7 @@ public function install_ispconfig()
13721372
//* Create the ispconfig log directory
13731373
if(!is_dir($conf['ispconfig_log_dir'])) mkdir($conf['ispconfig_log_dir']);
13741374
if(!is_file($conf['ispconfig_log_dir'].'/ispconfig.log')) exec('touch '.$conf['ispconfig_log_dir'].'/ispconfig.log');
1375+
chmod($conf['ispconfig_log_dir'].'/ispconfig.log', 0600);
13751376

13761377
if(is_user('getmail')) {
13771378
exec('mv /usr/local/ispconfig/server/scripts/run-getmail.sh /usr/local/bin/run-getmail.sh');

install/dist/lib/gentoo.lib.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,8 +1115,8 @@ public function install_ispconfig()
11151115
caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
11161116

11171117
if ($this->install_ispconfig_interface == true && isset($conf['interface_password']) && $conf['interface_password']!='admin') {
1118-
$sql = "UPDATE sys_user SET passwort = md5(?) WHERE username = 'admin';";
1119-
$this->db->query($sql, $conf['interface_password']);
1118+
$sql = "UPDATE sys_user SET passwort = ? WHERE username = 'admin';";
1119+
$this->db->query($sql, $this->crypt_password($conf['interface_password']));
11201120
}
11211121

11221122
if($conf['apache']['installed'] == true && $this->install_ispconfig_interface == true){
@@ -1252,6 +1252,7 @@ public function install_ispconfig()
12521252
if (!is_file($conf['ispconfig_log_dir'].'/ispconfig.log')) {
12531253
touch($conf['ispconfig_log_dir'].'/ispconfig.log');
12541254
}
1255+
chmod($conf['ispconfig_log_dir'].'/ispconfig.log', 0600);
12551256

12561257
//* Create the ispconfig auth log file and set uid/gid
12571258
if(!is_file($conf['ispconfig_log_dir'].'/auth.log')) {

install/dist/lib/opensuse.lib.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,8 +1215,8 @@ public function install_ispconfig()
12151215
caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
12161216

12171217
if ($this->install_ispconfig_interface == true && isset($conf['interface_password']) && $conf['interface_password']!='admin') {
1218-
$sql = "UPDATE sys_user SET passwort = md5(?) WHERE username = 'admin';";
1219-
$this->db->query($sql, $conf['interface_password']);
1218+
$sql = "UPDATE sys_user SET passwort = ? WHERE username = 'admin';";
1219+
$this->db->query($sql, $this->crypt_password($conf['interface_password']));
12201220
}
12211221

12221222
if($conf['apache']['installed'] == true && $this->install_ispconfig_interface == true){
@@ -1369,6 +1369,7 @@ public function install_ispconfig()
13691369
//* Create the ispconfig log directory
13701370
if(!is_dir($conf['ispconfig_log_dir'])) mkdir($conf['ispconfig_log_dir']);
13711371
if(!is_file($conf['ispconfig_log_dir'].'/ispconfig.log')) exec('touch '.$conf['ispconfig_log_dir'].'/ispconfig.log');
1372+
chmod($conf['ispconfig_log_dir'].'/ispconfig.log', 0600);
13721373

13731374
if(is_user('getmail')) {
13741375
exec('mv /usr/local/ispconfig/server/scripts/run-getmail.sh /usr/local/bin/run-getmail.sh');

install/lib/installer_base.lib.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,34 @@ public function get_php_version() {
157157
else return true;
158158
}
159159

160+
public function crypt_password($cleartext_password, $charset = 'UTF-8') {
161+
if($charset != 'UTF-8') {
162+
$cleartext_password = mb_convert_encoding($cleartext_password, $charset, 'UTF-8');
163+
}
164+
165+
if(defined('CRYPT_SHA512') && CRYPT_SHA512 == 1) {
166+
$salt = '$6$rounds=5000$';
167+
$salt_length = 16;
168+
} elseif(defined('CRYPT_SHA256') && CRYPT_SHA256 == 1) {
169+
$salt = '$5$rounds=5000$';
170+
$salt_length = 16;
171+
} else {
172+
$salt = '$1$';
173+
$salt_length = 12;
174+
}
175+
176+
if(function_exists('openssl_random_pseudo_bytes')) {
177+
$salt .= substr(bin2hex(openssl_random_pseudo_bytes($salt_length)), 0, $salt_length);
178+
} else {
179+
$base64_alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
180+
for($n = 0; $n < $salt_length; $n++) {
181+
$salt .= $base64_alphabet[mt_rand(0, 63)];
182+
}
183+
}
184+
$salt .= "$";
185+
return crypt($cleartext_password, $salt);
186+
}
187+
160188
//** Detect installed applications
161189
public function find_installed_apps() {
162190
global $conf;
@@ -3415,8 +3443,8 @@ public function install_ispconfig() {
34153443
caselog($command.' &> /dev/null', __FILE__, __LINE__, "EXECUTED: $command", "Failed to execute the command $command");
34163444

34173445
if ($this->install_ispconfig_interface == true && isset($conf['interface_password']) && $conf['interface_password']!='admin') {
3418-
$sql = "UPDATE sys_user SET passwort = md5(?) WHERE username = 'admin';";
3419-
$this->db->query($sql, $conf['interface_password']);
3446+
$sql = "UPDATE sys_user SET passwort = ? WHERE username = 'admin';";
3447+
$this->db->query($sql, $this->crypt_password($conf['interface_password']));
34203448
}
34213449

34223450
if($conf['apache']['installed'] == true && $this->install_ispconfig_interface == true){
@@ -3560,6 +3588,7 @@ public function install_ispconfig() {
35603588
if(!is_dir($conf['ispconfig_log_dir'])) mkdir($conf['ispconfig_log_dir'], 0755);
35613589
touch($conf['ispconfig_log_dir'].'/ispconfig.log');
35623590
}
3591+
chmod($conf['ispconfig_log_dir'].'/ispconfig.log', 0600);
35633592

35643593
//* Create the ispconfig auth log file and set uid/gid
35653594
if(!is_file($conf['ispconfig_log_dir'].'/auth.log')) {

install/sql/ispconfig3.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2580,7 +2580,7 @@ INSERT INTO `sys_theme` (`var_id`, `tpl_name`, `username`, `logo_url`) VALUES (N
25802580
-- Dumping data for table `sys_user`
25812581
--
25822582

2583-
INSERT INTO `sys_user` (`userid`, `sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `username`, `passwort`, `modules`, `startmodule`, `app_theme`, `typ`, `active`, `language`, `groups`, `default_group`, `client_id`) VALUES (1, 1, 0, 'riud', 'riud', '', 'admin', '21232f297a57a5a743894a0e4a801fc3', 'dashboard,admin,client,mail,monitor,sites,dns,vm,tools,help', 'dashboard', 'default', 'admin', 1, 'en', '1,2', 1, 0);
2583+
INSERT INTO `sys_user` (`userid`, `sys_userid`, `sys_groupid`, `sys_perm_user`, `sys_perm_group`, `sys_perm_other`, `username`, `passwort`, `modules`, `startmodule`, `app_theme`, `typ`, `active`, `language`, `groups`, `default_group`, `client_id`) VALUES (1, 1, 0, 'riud', 'riud', '', 'admin', 'xxx', 'dashboard,admin,client,mail,monitor,sites,dns,vm,tools,help', 'dashboard', 'default', 'admin', 1, 'en', '1,2', 1, 0);
25842584

25852585
-- --------------------------------------------------------
25862586

interface/lib/classes/db_mysql.inc.php

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,10 @@ public function _build_query_string($sQuery = '') {
171171
} elseif(is_null($sValue) || (is_string($sValue) && (strcmp($sValue, '#NULL#') == 0))) {
172172
$sTxt = 'NULL';
173173
} elseif(is_array($sValue)) {
174-
if(isset($sValue['SQL'])) {
175-
$sTxt = $sValue['SQL'];
176-
} else {
177-
$sTxt = '';
178-
foreach($sValue as $sVal) $sTxt .= ',\'' . $this->escape($sVal) . '\'';
179-
$sTxt = '(' . substr($sTxt, 1) . ')';
180-
if($sTxt == '()') $sTxt = '(0)';
181-
}
174+
$sTxt = '';
175+
foreach($sValue as $sVal) $sTxt .= ',\'' . $this->escape($sVal) . '\'';
176+
$sTxt = '(' . substr($sTxt, 1) . ')';
177+
if($sTxt == '()') $sTxt = '(0)';
182178
} else {
183179
$sTxt = '\'' . $this->escape($sValue) . '\'';
184180
}
@@ -258,7 +254,7 @@ private function securityScan($string) {
258254

259255
private function _query($sQuery = '') {
260256
global $app;
261-
257+
262258
$aArgs = func_get_args();
263259

264260
if ($sQuery == '') {
@@ -354,7 +350,7 @@ public function query($sQuery = '') {
354350
* @return array result row or NULL if none found
355351
*/
356352
public function queryOneRecord($sQuery = '') {
357-
353+
358354
$aArgs = func_get_args();
359355
if(!empty($aArgs)) {
360356
$sQuery = array_shift($aArgs);
@@ -363,7 +359,7 @@ public function queryOneRecord($sQuery = '') {
363359
}
364360
array_unshift($aArgs, $sQuery);
365361
}
366-
362+
367363
$oResult = call_user_func_array([&$this, 'query'], $aArgs);
368364
if(!$oResult) return null;
369365

@@ -750,7 +746,7 @@ public function datalogInsert($tablename, $insert_data, $index_field) {
750746
foreach($insert_data as $key => $val) {
751747
$key_str .= '??,';
752748
$params[] = $key;
753-
749+
754750
$val_str .= '?,';
755751
$v_params[] = $val;
756752
}
@@ -764,7 +760,7 @@ public function datalogInsert($tablename, $insert_data, $index_field) {
764760
$this->query("INSERT INTO ?? $insert_data_str", $tablename);
765761
$app->log("deprecated use of passing values to datalogInsert() - table " . $tablename, 1);
766762
}
767-
763+
768764
$old_rec = array();
769765
$index_value = $this->insertID();
770766
if(!$index_value && isset($insert_data[$index_field])) {
@@ -1112,7 +1108,7 @@ public function mapType($metaType, $typeValue) {
11121108
* @access public
11131109
* @return string 'mariadb' or string 'mysql'
11141110
*/
1115-
1111+
11161112
public function getDatabaseType() {
11171113
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
11181114
if(stristr($tmp['version'],'mariadb')) {
@@ -1140,7 +1136,7 @@ public function getDatabaseVersion($major_version_only = false) {
11401136
return $version[0];
11411137
}
11421138
}
1143-
1139+
11441140
/**
11451141
* Get a mysql password hash
11461142
*
@@ -1150,9 +1146,9 @@ public function getDatabaseVersion($major_version_only = false) {
11501146
*/
11511147

11521148
public function getPasswordHash($password) {
1153-
1149+
11541150
$password_type = 'password';
1155-
1151+
11561152
/* Disabled until caching_sha2_password is implemented
11571153
if($this->getDatabaseType() == 'mysql' && $this->getDatabaseVersion(true) >= 8) {
11581154
// we are in MySQL 8 mode
@@ -1162,16 +1158,16 @@ public function getPasswordHash($password) {
11621158
}
11631159
}
11641160
*/
1165-
1161+
11661162
if($password_type == 'caching_sha2_password') {
11671163
/*
1168-
caching_sha2_password hashing needs to be implemented, have not
1164+
caching_sha2_password hashing needs to be implemented, have not
11691165
found valid PHP implementation for the new password hash type.
11701166
*/
11711167
} else {
11721168
$password_hash = '*'.strtoupper(sha1(sha1($password, true)));
11731169
}
1174-
1170+
11751171
return $password_hash;
11761172
}
11771173

interface/web/login/index.php

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,23 @@
8383
* The actual user is NOT a admin or reseller, but maybe he
8484
* has logged in as "normal" user before...
8585
*/
86-
86+
8787
if (isset($_SESSION['s_old'])&& ($_SESSION['s_old']['user']['typ'] == 'admin' || $app->auth->has_clients($_SESSION['s_old']['user']['userid']))){
8888
/* The "old" user is admin or reseller, so everything is ok
8989
* if he is reseller, we need to check if he logs in to one of his clients
9090
*/
9191
if($_SESSION['s_old']['user']['typ'] != 'admin') {
92-
92+
9393
/* this is the one currently logged in (normal user) */
9494
$old_client_group_id = $app->functions->intval($_SESSION["s"]["user"]["default_group"]);
9595
$old_client = $app->db->queryOneRecord("SELECT client.client_id, client.parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ?", $old_client_group_id);
96-
96+
9797
/* this is the reseller, that shall be re-logged in */
9898
$sql = "SELECT * FROM sys_user WHERE USERNAME = ? and PASSWORT = ?";
9999
$tmp = $app->db->queryOneRecord($sql, $username, $password);
100100
$client_group_id = $app->functions->intval($tmp['default_group']);
101101
$tmp_client = $app->db->queryOneRecord("SELECT client.client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ?", $client_group_id);
102-
102+
103103
if(!$tmp_client || $old_client["parent_client_id"] != $tmp_client["client_id"] || $tmp["default_group"] != $_SESSION["s_old"]["user"]["default_group"] ) {
104104
die("You don't have the right to 'login as' this user!");
105105
}
@@ -115,12 +115,12 @@
115115
/* a reseller wants to 'login as', we need to check if he is allowed to */
116116
$res_client_group_id = $app->functions->intval($_SESSION["s"]["user"]["default_group"]);
117117
$res_client = $app->db->queryOneRecord("SELECT client.client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ?", $res_client_group_id);
118-
118+
119119
/* this is the user the reseller wants to 'login as' */
120120
$sql = "SELECT * FROM sys_user WHERE USERNAME = ? and PASSWORT = ?";
121121
$tmp = $app->db->queryOneRecord($sql, $username, $password);
122122
$tmp_client = $app->db->queryOneRecord("SELECT client.client_id, client.parent_client_id FROM sys_group, client WHERE sys_group.client_id = client.client_id and sys_group.groupid = ?", $tmp["default_group"]);
123-
123+
124124
if(!$tmp || $tmp_client["parent_client_id"] != $res_client["client_id"]) {
125125
die("You don't have the right to login as this user!");
126126
}
@@ -129,16 +129,16 @@
129129
unset($tmp_client);
130130
}
131131
$loginAs = true;
132-
132+
133133
} else {
134134
/* normal login */
135135
$loginAs = false;
136136
}
137-
137+
138138
//* Check if there are already wrong logins
139139
$sql = "SELECT * FROM `attempts_login` WHERE `ip`= ? AND `login_time` > (NOW() - INTERVAL 1 MINUTE) LIMIT 1";
140140
$alreadyfailed = $app->db->queryOneRecord($sql, $ip);
141-
141+
142142
//* too many failedlogins
143143
if($alreadyfailed['times'] > 5) {
144144
$error = $app->lng('error_user_too_many_logins');
@@ -148,7 +148,7 @@
148148
$sql = "SELECT * FROM sys_user WHERE USERNAME = ? and PASSWORT = ?";
149149
$user = $app->db->queryOneRecord($sql, $username, $password);
150150
} else {
151-
151+
152152
if(stristr($username, '@')) {
153153
//* mailuser login
154154
$sql = "SELECT * FROM mail_user WHERE login = ? or email = ?";
@@ -160,7 +160,7 @@
160160
if(crypt(stripslashes($password), $saved_password) == $saved_password) {
161161
//* Get the sys_user language of the client of the mailuser
162162
$sys_user_lang = $app->db->queryOneRecord("SELECT language FROM sys_user WHERE default_group = ?", $mailuser['sys_groupid'] );
163-
163+
164164
//* we build a fake user here which has access to the mailuser module only and userid 0
165165
$user = array();
166166
$user['userid'] = 0;
@@ -196,26 +196,30 @@
196196
//* The password is md5 encrypted
197197
if(md5($password) != $saved_password) {
198198
$user = false;
199+
} else {
200+
// update password with secure algo
201+
$sql = 'UPDATE `sys_user` SET `passwort` = ? WHERE `username` = ?';
202+
$app->db->query($sql, $app->auth->crypt_password($password), $username);
199203
}
200204
}
201205
} else {
202206
$user = false;
203207
}
204208
}
205209
}
206-
210+
207211
if($user) {
208212
if($user['active'] == 1) {
209213
// Maintenance mode - allow logins only when maintenance mode is off or if the user is admin
210214
if(!$app->is_under_maintenance() || $user['typ'] == 'admin'){
211-
215+
212216
// User login right, so attempts can be deleted
213217
$sql = "DELETE FROM `attempts_login` WHERE `ip`=?";
214218
$app->db->query($sql, $ip);
215219
$user = $app->db->toLower($user);
216-
220+
217221
if ($loginAs) $oldSession = $_SESSION['s'];
218-
222+
219223
// Session regenerate causes login problems on some systems, see Issue #3827
220224
// Set session_regenerate_id to no in security settings, it you encounter
221225
// this problem.
@@ -231,7 +235,7 @@
231235
$_SESSION['s']['language'] = $app->functions->check_language($user['language']);
232236
$_SESSION["s"]['theme'] = $_SESSION['s']['user']['theme'];
233237
if ($loginAs) $_SESSION['s']['plugin_cache'] = $_SESSION['s_old']['plugin_cache'];
234-
238+
235239
if(is_file(ISPC_WEB_PATH . '/' . $_SESSION['s']['user']['startmodule'].'/lib/module.conf.php')) {
236240
include_once $app->functions->check_include_path(ISPC_WEB_PATH . '/' . $_SESSION['s']['user']['startmodule'].'/lib/module.conf.php');
237241
$menu_dir = ISPC_WEB_PATH.'/' . $_SESSION['s']['user']['startmodule'] . '/lib/menu.d';
@@ -257,20 +261,20 @@
257261
$_SESSION['show_error_msg'] = $app->lng('theme_not_compatible');
258262
}
259263
}
260-
264+
261265
$app->plugin->raiseEvent('login', $username);
262-
266+
263267
//* Save successfull login message to var
264-
$authlog = 'Successful login for user \''. $username .'\' from '. $_SERVER['REMOTE_ADDR'] .' at '. date('Y-m-d H:i:s') . ' with session ID ' .session_id();
268+
$authlog = 'Successful login for user \''. $username .'\' from '. $_SERVER['REMOTE_ADDR'] .' at '. date('Y-m-d H:i:s') . ' with session ID ' .session_id();
265269
$authlog_handle = fopen($conf['ispconfig_log_dir'].'/auth.log', 'a');
266270
fwrite($authlog_handle, $authlog ."\n");
267271
fclose($authlog_handle);
268-
272+
269273
/*
270274
* We need LOGIN_REDIRECT instead of HEADER_REDIRECT to load the
271275
* new theme, if the logged-in user has another
272276
*/
273-
277+
274278
if ($loginAs){
275279
echo 'LOGIN_REDIRECT:'.$_SESSION['s']['module']['startpage'];
276280
exit;
@@ -327,7 +331,7 @@
327331
} else {
328332
$app->tpl->setVar('pw_lost_show', 0);
329333
}
330-
334+
331335
$app->tpl->setVar('error', $error);
332336
$app->tpl->setVar('error_txt', $app->lng('error_txt'));
333337
$app->tpl->setVar('login_txt', $app->lng('login_txt'));

0 commit comments

Comments
 (0)