Skip to content

Commit ec11409

Browse files
author
Till Brehm
committed
Merge branch 'stable-3.1' into 'forward_via_postfix'
# Conflicts: # install/sql/ispconfig3.sql
2 parents 66aab00 + 6c4eb9b commit ec11409

File tree

10 files changed

+316
-44
lines changed

10 files changed

+316
-44
lines changed

install/lib/installer_base.lib.php

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,27 @@ public function reconfigure_app($service, $reconfigure_services_answer) {
235235
public function configure_database() {
236236
global $conf;
237237

238-
//* check sql-mode
239-
/*$check_sql_mode = $this->db->queryOneRecord("SELECT @@sql_mode");
240-
241-
if ($check_sql_mode['@@sql_mode'] != '' && $check_sql_mode['@@sql_mode'] != 'NO_ENGINE_SUBSTITUTION') {
242-
echo "Wrong SQL-mode. You should use NO_ENGINE_SUBSTITUTION. Add\n\n";
243-
echo " sql-mode=\"NO_ENGINE_SUBSTITUTION\"\n\n";
244-
echo"to the mysqld-section in your mysql-config on this server and restart mysqld afterwards\n";
245-
die();
246-
}*/
247-
248-
$unwanted_sql_plugins = array('validate_password');
249-
$sql_plugins = $this->db->queryAllRecords("SELECT plugin_name FROM information_schema.plugins WHERE plugin_status='ACTIVE' AND plugin_name IN ?", $unwanted_sql_plugins);
250-
if(is_array($sql_plugins) && !empty($sql_plugins)) {
251-
foreach ($sql_plugins as $plugin) echo "Login in to MySQL and disable $plugin[plugin_name] with:\n\n UNINSTALL PLUGIN $plugin[plugin_name];";
252-
die();
238+
//** Check for unwanted plugins
239+
if ($this->db->getDatabaseType() == 'mysql' && $this->db->getDatabaseVersion(true) >= 8) {
240+
// component approach since MySQL 8.0
241+
$unwanted_components = [
242+
'file://component_validate_password',
243+
];
244+
$sql_components = $this->db->queryAllRecords("SELECT * FROM mysql.component where component_urn IN ?", $unwanted_components);
245+
if(is_array($sql_components) && !empty($sql_components)) {
246+
foreach ($sql_components as $component) {
247+
$component_name = parse_url($component['component_urn'], PHP_URL_HOST);
248+
echo "Login in to MySQL and disable '{$component_name}' with:\n\n UNINSTALL COMPONENT '{$component['component_urn']}';\n\n";
249+
}
250+
die();
251+
}
252+
} else {
253+
$unwanted_sql_plugins = array('validate_password');
254+
$sql_plugins = $this->db->queryAllRecords("SELECT plugin_name FROM information_schema.plugins WHERE plugin_status='ACTIVE' AND plugin_name IN ?", $unwanted_sql_plugins);
255+
if(is_array($sql_plugins) && !empty($sql_plugins)) {
256+
foreach ($sql_plugins as $plugin) echo "Login in to MySQL and disable $plugin[plugin_name] with:\n\n UNINSTALL PLUGIN $plugin[plugin_name];";
257+
die();
258+
}
253259
}
254260

255261
//** Create the database
@@ -308,6 +314,15 @@ public function add_database_server_record() {
308314
if(!$this->db->query($query, $conf['mysql']['database'] . ".*", $conf['mysql']['ispconfig_user'], $from_host)) {
309315
$this->error('Unable to grant databse permissions to user: '.$conf['mysql']['ispconfig_user'].' Error: '.$this->db->errorMessage);
310316
}
317+
318+
// add correct administrative rights to IPSConfig user (SUPER is deprecated and unnecessarily powerful)
319+
if ($this->db->getDatabaseType() == 'mysql' && $this->db->getDatabaseVersion(true) >= 8) {
320+
// there might be more needed on replicated db environments, this was not tested
321+
$query = 'GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO ?@?';
322+
if(!$this->db->query($query, $conf['mysql']['ispconfig_user'], $from_host)) {
323+
$this->error('Unable to grant administrative permissions to user: '.$conf['mysql']['ispconfig_user'].' Error: '.$this->db->errorMessage);
324+
}
325+
}
311326

312327
//* Set the database name in the DB library
313328
$this->db->setDBName($conf['mysql']['database']);

install/lib/mysql.lib.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,41 @@ public function mapType($metaType, $typeValue) {
761761
break;
762762
}
763763
}
764+
765+
/**
766+
* Get the database type (mariadb or mysql)
767+
*
768+
* @access public
769+
* @return string 'mariadb' or string 'mysql'
770+
*/
771+
772+
public function getDatabaseType() {
773+
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
774+
if(stristr($tmp['version'],'mariadb')) {
775+
return 'mariadb';
776+
} else {
777+
return 'mysql';
778+
}
779+
}
780+
781+
/**
782+
* Get the database version
783+
*
784+
* @access public
785+
* @param bool $major_version_only = true will return the major version only, e.g. 8 for MySQL 8
786+
* @return string version number
787+
*/
788+
789+
public function getDatabaseVersion($major_version_only = false) {
790+
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
791+
$version = explode('-', $tmp['version']);
792+
if($major_version_only == true) {
793+
$version_parts = explode('.', $version[0]);
794+
return $version_parts[0];
795+
} else {
796+
return $version[0];
797+
}
798+
}
764799

765800
}
766801

install/sql/incremental/upd_dev_collection.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ ALTER TABLE `mail_user` ADD `disableindexer-worker` ENUM('n','y') CHARACTER SET
3737
ALTER TABLE `dns_rr` CHANGE `type` `type` ENUM('A','AAAA','ALIAS','CNAME','DNAME','CAA','DS','HINFO','LOC','MX','NAPTR','NS','PTR','RP','SRV','SSHFP','TXT','TLSA','DNSKEY') NULL DEFAULT NULL AFTER `name`;
3838

3939
-- change cc and sender_cc column type
40-
ALTER TABLE `mail_user` CHANGE `cc` `cc` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '';
40+
ALTER TABLE `mail_user` CHANGE `cc` `cc` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci;
4141

4242
-- remove SPDY option
4343
ALTER TABLE `web_domain` DROP COLUMN `enable_spdy`;
@@ -62,7 +62,7 @@ ALTER TABLE `web_domain` CHANGE `nginx_directives` `nginx_directives` mediumtext
6262
ALTER TABLE `mail_user` MODIFY `move_junk` enum('y','a','n') NOT NULL DEFAULT 'y';
6363

6464
-- Change id_rsa column to TEXT format
65-
ALTER TABLE `client` CHANGE `id_rsa` `id_rsa` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '';
65+
ALTER TABLE `client` CHANGE `id_rsa` `id_rsa` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci;
6666

6767
ALTER TABLE `directive_snippets` ADD `update_sites` ENUM('y','n') NOT NULL DEFAULT 'n' ;
6868

install/sql/ispconfig3.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ CREATE TABLE `client` (
253253
`canceled` enum('n','y') NOT NULL DEFAULT 'n',
254254
`can_use_api` enum('n','y') NOT NULL DEFAULT 'n',
255255
`tmp_data` mediumblob,
256-
`id_rsa` text NOT NULL DEFAULT '',
256+
`id_rsa` text,
257257
`ssh_rsa` varchar(600) NOT NULL DEFAULT '',
258258
`customer_no_template` varchar(255) DEFAULT 'R[CLIENTID]C[CUSTOMER_NO]',
259259
`customer_no_start` int(11) NOT NULL DEFAULT '1',
@@ -1040,7 +1040,7 @@ CREATE TABLE `mail_user` (
10401040
`maildir` varchar(255) NOT NULL default '',
10411041
`maildir_format` varchar(255) NOT NULL default 'maildir',
10421042
`quota` bigint(20) NOT NULL default '-1',
1043-
`cc` text NOT NULL default '',
1043+
`cc` text,
10441044
`forward_in_lda` enum('n','y') NOT NULL default 'n',
10451045
`sender_cc` varchar(255) NOT NULL default '',
10461046
`homedir` varchar(255) NOT NULL default '',

interface/lib/classes/db_mysql.inc.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,76 @@ public function mapType($metaType, $typeValue) {
11061106
}
11071107
}
11081108

1109+
/**
1110+
* Get the database type (mariadb or mysql)
1111+
*
1112+
* @access public
1113+
* @return string 'mariadb' or string 'mysql'
1114+
*/
1115+
1116+
public function getDatabaseType() {
1117+
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
1118+
if(stristr($tmp['version'],'mariadb')) {
1119+
return 'mariadb';
1120+
} else {
1121+
return 'mysql';
1122+
}
1123+
}
1124+
1125+
/**
1126+
* Get the database version
1127+
*
1128+
* @access public
1129+
* @param bool $major_version_only = true will return the major version only, e.g. 8 for MySQL 8
1130+
* @return string version number
1131+
*/
1132+
1133+
public function getDatabaseVersion($major_version_only = false) {
1134+
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
1135+
$version = explode('-', $tmp['version']);
1136+
if($major_version_only == true) {
1137+
$version_parts = explode('.', $version[0]);
1138+
return $version_parts[0];
1139+
} else {
1140+
return $version[0];
1141+
}
1142+
}
1143+
1144+
/**
1145+
* Get a mysql password hash
1146+
*
1147+
* @access public
1148+
* @param string cleartext password
1149+
* @return string Password hash
1150+
*/
1151+
1152+
public function getPasswordHash($password) {
1153+
1154+
$password_type = 'password';
1155+
1156+
/* Disabled until caching_sha2_password is implemented
1157+
if($this->getDatabaseType() == 'mysql' && $this->getDatabaseVersion(true) >= 8) {
1158+
// we are in MySQL 8 mode
1159+
$tmp = $this->queryOneRecord("show variables like 'default_authentication_plugin'");
1160+
if($tmp['default_authentication_plugin'] == 'caching_sha2_password') {
1161+
$password_type = 'caching_sha2_password';
1162+
}
1163+
}
1164+
*/
1165+
1166+
if($password_type == 'caching_sha2_password') {
1167+
/*
1168+
caching_sha2_password hashing needs to be implemented, have not
1169+
found valid PHP implementation for the new password hash type.
1170+
*/
1171+
} else {
1172+
$password_hash = '*'.strtoupper(sha1(sha1($password, true)));
1173+
}
1174+
1175+
return $password_hash;
1176+
}
1177+
1178+
11091179
}
11101180

11111181
/**

interface/lib/classes/tform_base.inc.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,8 +1358,7 @@ protected function _getSQL($record, $tab, $action = 'INSERT', $primary_id = 0, $
13581358
$record[$key] = $app->auth->crypt_password(stripslashes($record[$key]),'ISO-8859-1');
13591359
$sql_insert_val .= "'".$app->db->quote($record[$key])."', ";
13601360
} elseif (isset($field['encryption']) && $field['encryption'] == 'MYSQL') {
1361-
$tmp = $app->db->queryOneRecord("SELECT PASSWORD(?) as `crypted`", stripslashes($record[$key]));
1362-
$record[$key] = $tmp['crypted'];
1361+
$record[$key] = $app->db->getPasswordHash($record[$key]);
13631362
$sql_insert_val .= "'".$app->db->quote($record[$key])."', ";
13641363
} else {
13651364
$record[$key] = md5(stripslashes($record[$key]));
@@ -1390,8 +1389,7 @@ protected function _getSQL($record, $tab, $action = 'INSERT', $primary_id = 0, $
13901389
$record[$key] = $app->auth->crypt_password(stripslashes($record[$key]),'ISO-8859-1');
13911390
$sql_update .= "`$key` = '".$app->db->quote($record[$key])."', ";
13921391
} elseif (isset($field['encryption']) && $field['encryption'] == 'MYSQL') {
1393-
$tmp = $app->db->queryOneRecord("SELECT PASSWORD(?) as `crypted`", stripslashes($record[$key]));
1394-
$record[$key] = $tmp['crypted'];
1392+
$record[$key] = $app->db->getPasswordHash($record[$key]);
13951393
$sql_update .= "`$key` = '".$app->db->quote($record[$key])."', ";
13961394
} else {
13971395
$record[$key] = md5(stripslashes($record[$key]));

interface/web/sites/web_vhost_domain_edit.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,7 +1490,7 @@ function onBeforeUpdate () {
14901490
$rec = $app->db->queryOneRecord("SELECT server_id from web_domain WHERE domain_id = ?", $this->id);
14911491
if($rec['server_id'] != $this->dataRecord["server_id"]) {
14921492
//* Add a error message and switch back to old server
1493-
$app->tform->errorMessage .= $app->lng('error_server_change_not_possible');
1493+
$app->tform->errorMessage .= $app->tform->lng('error_server_change_not_possible');
14941494
$this->dataRecord["server_id"] = $rec['server_id'];
14951495
}
14961496
unset($rec);
@@ -1501,17 +1501,17 @@ function onBeforeUpdate () {
15011501
$rec = $app->db->queryOneRecord("SELECT sys_perm_group, domain, ip_address, ipv6_address from web_domain WHERE domain_id = ?", $this->id);
15021502
if(isset($this->dataRecord["domain"]) && $rec['domain'] != $this->dataRecord["domain"] && !$app->tform->checkPerm($this->id, 'u')) {
15031503
//* Add a error message and switch back to old server
1504-
$app->tform->errorMessage .= $app->lng('error_domain_change_forbidden');
1504+
$app->tform->errorMessage .= $app->tform->lng('error_domain_change_forbidden');
15051505
$this->dataRecord["domain"] = $rec['domain'];
15061506
}
15071507
if(isset($this->dataRecord["ip_address"]) && $rec['ip_address'] != $this->dataRecord["ip_address"] && $rec['sys_perm_group'] != 'riud') {
15081508
//* Add a error message and switch back to old server
1509-
$app->tform->errorMessage .= $app->lng('error_ipv4_change_forbidden');
1509+
$app->tform->errorMessage .= $app->tform->lng('error_ipv4_change_forbidden');
15101510
$this->dataRecord["ip_address"] = $rec['ip_address'];
15111511
}
15121512
if(isset($this->dataRecord["ipv6_address"]) && $rec['ipv6_address'] != $this->dataRecord["ipv6_address"] && $rec['sys_perm_group'] != 'riud') {
15131513
//* Add a error message and switch back to old server
1514-
$app->tform->errorMessage .= $app->lng('error_ipv6_change_forbidden');
1514+
$app->tform->errorMessage .= $app->tform->lng('error_ipv6_change_forbidden');
15151515
$this->dataRecord["ipv6_address"] = $rec['ipv6_address'];
15161516
}
15171517
unset($rec);

server/lib/classes/db_mysql.inc.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,75 @@ public function mapType($metaType, $typeValue) {
11061106
}
11071107
}
11081108

1109+
/**
1110+
* Get the database type (mariadb or mysql)
1111+
*
1112+
* @access public
1113+
* @return string 'mariadb' or string 'mysql'
1114+
*/
1115+
1116+
public function getDatabaseType() {
1117+
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
1118+
if(stristr($tmp['version'],'mariadb')) {
1119+
return 'mariadb';
1120+
} else {
1121+
return 'mysql';
1122+
}
1123+
}
1124+
1125+
/**
1126+
* Get the database version
1127+
*
1128+
* @access public
1129+
* @param bool $major_version_only = true will return the major version only, e.g. 8 for MySQL 8
1130+
* @return string version number
1131+
*/
1132+
1133+
public function getDatabaseVersion($major_version_only = false) {
1134+
$tmp = $this->queryOneRecord('SELECT VERSION() as version');
1135+
$version = explode('-', $tmp['version']);
1136+
if($major_version_only == true) {
1137+
$version_parts = explode('.', $version[0]);
1138+
return $version_parts[0];
1139+
} else {
1140+
return $version[0];
1141+
}
1142+
}
1143+
1144+
/**
1145+
* Get a mysql password hash
1146+
*
1147+
* @access public
1148+
* @param string cleartext password
1149+
* @return string Password hash
1150+
*/
1151+
1152+
public function getPasswordHash($password) {
1153+
1154+
$password_type = 'password';
1155+
1156+
/* Disabled until caching_sha2_password is implemented
1157+
if($this->getDatabaseType() == 'mysql' && $this->getDatabaseVersion(true) >= 8) {
1158+
// we are in MySQL 8 mode
1159+
$tmp = $this->queryOneRecord("show variables like 'default_authentication_plugin'");
1160+
if($tmp['default_authentication_plugin'] == 'caching_sha2_password') {
1161+
$password_type = 'caching_sha2_password';
1162+
}
1163+
}
1164+
*/
1165+
1166+
if($password_type == 'caching_sha2_password') {
1167+
/*
1168+
caching_sha2_password hashing needs to be implemented, have not
1169+
found valid PHP implementation for the new password hash type.
1170+
*/
1171+
} else {
1172+
$password_hash = '*'.strtoupper(sha1(sha1($password, true)));
1173+
}
1174+
1175+
return $password_hash;
1176+
}
1177+
11091178
}
11101179

11111180
/**

server/lib/classes/letsencrypt.inc.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
class letsencrypt {
3232

33-
/**
33+
/**
3434
* Construct for this class
3535
*
3636
* @return system
@@ -373,13 +373,38 @@ public function request_certificates($data, $server_type = 'apache') {
373373
if((isset($web_config['skip_le_check']) && $web_config['skip_le_check'] == 'y') || (isset($server_config['migration_mode']) && $server_config['migration_mode'] == 'y')) {
374374
$le_domains[] = $temp_domain;
375375
} else {
376-
$le_hash_check = trim(@file_get_contents('http://' . $temp_domain . '/.well-known/acme-challenge/' . $le_rnd_file));
377-
if($le_hash_check == $le_rnd_hash) {
378-
$le_domains[] = $temp_domain;
379-
$app->log("Verified domain " . $temp_domain . " should be reachable for letsencrypt.", LOGLEVEL_DEBUG);
376+
//check caa-record
377+
$caa_check = false;
378+
$caa_domain = $temp_domain;
379+
$count = substr_count($caa_domain, '.');
380+
if($count === 2) {
381+
if(strlen(explode('.', $caa_domain)[1]) > 3) {
382+
$caa_domain = explode('.', $caa_domain, 2)[1];
383+
}
384+
} else if($count > 2) {
385+
$caa_domain = get_domain(explode('.', $caa_domain, 2)[1]);
386+
}
387+
$caa_records = @dns_get_record($caa_domain, DNS_CAA); // requieres PHP 7.0.16, 7.1.2
388+
if(is_array($caa_records) && !empty($caa_records)) {
389+
foreach ($records as $record) {
390+
if($record['value'] == 'letsencrypt.org') $caa_check = true;
391+
}
392+
} else {
393+
$caa_check = true;
394+
}
395+
396+
if($caa_check === true) {
397+
$le_hash_check = trim(@file_get_contents('http://' . $temp_domain . '/.well-known/acme-challenge/' . $le_rnd_file));
398+
if($le_hash_check == $le_rnd_hash) {
399+
$le_domains[] = $temp_domain;
400+
$app->log("Verified domain " . $temp_domain . " should be reachable for letsencrypt.", LOGLEVEL_DEBUG);
401+
} else {
402+
$app->log("Could not verify domain " . $temp_domain . ", so excluding it from letsencrypt request.", LOGLEVEL_WARN);
403+
}
380404
} else {
381-
$app->log("Could not verify domain " . $temp_domain . ", so excluding it from letsencrypt request.", LOGLEVEL_WARN);
405+
$app->log("Incomplete CAA-Records for " . $temp_domain . ", so excluding it from letsencrypt request.", LOGLEVEL_WARN);
382406
}
407+
383408
}
384409
}
385410
$temp_domains = $le_domains;

0 commit comments

Comments
 (0)