From 94929d8e660ccebeeb90bc4312dc4af0a323a165 Mon Sep 17 00:00:00 2001 From: Rafael Cossovan Date: Mon, 5 Mar 2018 19:36:35 -0300 Subject: [PATCH] Update postfixadmin-change-password plugin. https://github.com/RainLoop/rainloop-webmail/tree/master/plugins/postfixadmin-change-password --- .../ChangePasswordPostfixAdminDriver.php | 43 +++- .../postfixadmin-change-password/LICENSE | 20 ++ .../postfixadmin-change-password/README | 1 + .../postfixadmin-change-password/VERSION | 1 + .../postfixadmin-change-password/index.php | 195 +++++++++--------- .../postfixadmin-change-password/md5crypt.php | 139 +++++++++++++ 6 files changed, 301 insertions(+), 98 deletions(-) create mode 100644 rootfs/usr/local/include/postfixadmin-change-password/LICENSE create mode 100644 rootfs/usr/local/include/postfixadmin-change-password/README create mode 100644 rootfs/usr/local/include/postfixadmin-change-password/VERSION create mode 100644 rootfs/usr/local/include/postfixadmin-change-password/md5crypt.php diff --git a/rootfs/usr/local/include/postfixadmin-change-password/ChangePasswordPostfixAdminDriver.php b/rootfs/usr/local/include/postfixadmin-change-password/ChangePasswordPostfixAdminDriver.php index bf4249a..fd2284b 100644 --- a/rootfs/usr/local/include/postfixadmin-change-password/ChangePasswordPostfixAdminDriver.php +++ b/rootfs/usr/local/include/postfixadmin-change-password/ChangePasswordPostfixAdminDriver.php @@ -2,6 +2,11 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface { + /** + * @var string + */ + private $sEngine = 'MySQL'; + /** * @var string */ @@ -57,6 +62,17 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePass */ private $oLogger = null; + /** + * @param string $sEngine + * + * @return \ChangePasswordPostfixAdminDriver + */ + public function SetEngine($sEngine) + { + $this->sEngine = $sEngine; + return $this; + } + /** * @param string $sHost * @@ -215,7 +231,19 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePass { try { - $sDsn = 'mysql:host='.$this->sHost.';port='.$this->iPort.';dbname='.$this->sDatabase; + $sDsn = ''; + switch($this->sEngine){ + case 'MySQL': + $sDsn = 'mysql:host='.$this->sHost.';port='.$this->iPort.';dbname='.$this->sDatabase; + break; + case 'PostgreSQL': + $sDsn = 'pgsql:host='.$this->sHost.';port='.$this->iPort.';dbname='.$this->sDatabase; + break; + default: + $sDsn = 'mysql:host='.$this->sHost.';port='.$this->iPort.';dbname='.$this->sDatabase; + break; + } + $oPdo = new \PDO($sDsn, $this->sUser, $this->sPassword); $oPdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); @@ -267,6 +295,11 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePass $sResult = '{PLAIN}' . $sPassword; break; + case 'md5crypt': + include_once __DIR__.'/md5crypt.php'; + $sResult = '{MD5-CRYPT}' . md5crypt($sPassword); + break; + case 'md5': $sResult = '{PLAIN-MD5}' . md5($sPassword); break; @@ -284,7 +317,8 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePass break; case 'mysql_encrypt': - $oStmt = $oPdo->prepare('SELECT ENCRYPT(?) AS encpass'); + if($this->sEngine == 'MySQL'){ + $oStmt = $oPdo->prepare('SELECT ENCRYPT(?) AS encpass'); if ($oStmt->execute(array($sPassword))) { $aFetchResult = $oStmt->fetchAll(\PDO::FETCH_ASSOC); @@ -293,7 +327,10 @@ class ChangePasswordPostfixAdminDriver implements \RainLoop\Providers\ChangePass $sResult = $aFetchResult[0]['encpass']; } } - break; + }else{ + throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::CouldNotSaveNewPassword); + } + break; } return $sResult; diff --git a/rootfs/usr/local/include/postfixadmin-change-password/LICENSE b/rootfs/usr/local/include/postfixadmin-change-password/LICENSE new file mode 100644 index 0000000..c6cb63d --- /dev/null +++ b/rootfs/usr/local/include/postfixadmin-change-password/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2015 RainLoop Team, @zaffkea + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/rootfs/usr/local/include/postfixadmin-change-password/README b/rootfs/usr/local/include/postfixadmin-change-password/README new file mode 100644 index 0000000..342f4d4 --- /dev/null +++ b/rootfs/usr/local/include/postfixadmin-change-password/README @@ -0,0 +1 @@ +Plugin that adds functionality to change the email account password (PostfixAdmin). \ No newline at end of file diff --git a/rootfs/usr/local/include/postfixadmin-change-password/VERSION b/rootfs/usr/local/include/postfixadmin-change-password/VERSION new file mode 100644 index 0000000..7e32cd5 --- /dev/null +++ b/rootfs/usr/local/include/postfixadmin-change-password/VERSION @@ -0,0 +1 @@ +1.3 diff --git a/rootfs/usr/local/include/postfixadmin-change-password/index.php b/rootfs/usr/local/include/postfixadmin-change-password/index.php index aec05f4..ef2f5ee 100644 --- a/rootfs/usr/local/include/postfixadmin-change-password/index.php +++ b/rootfs/usr/local/include/postfixadmin-change-password/index.php @@ -1,95 +1,100 @@ -addHook('main.fabrica', 'MainFabrica'); - } - - /** - * @return string - */ - public function Supported() - { - if (!extension_loaded('pdo') || !class_exists('PDO')) - { - return 'The PHP exention PDO (mysql) must be installed to use this plugin'; - } - - $aDrivers = \PDO::getAvailableDrivers(); - if (!is_array($aDrivers) || !in_array('mysql', $aDrivers)) - { - return 'The PHP exention PDO (mysql) must be installed to use this plugin'; - } - - return ''; - } - - /** - * @param string $sName - * @param mixed $oProvider - */ - public function MainFabrica($sName, &$oProvider) - { - switch ($sName) - { - case 'change-password': - - include_once __DIR__.'/ChangePasswordPostfixAdminDriver.php'; - - $oProvider = new ChangePasswordPostfixAdminDriver(); - - $oProvider - ->SetHost($this->Config()->Get('plugin', 'host', '')) - ->SetPort((int) $this->Config()->Get('plugin', 'port', 3306)) - ->SetDatabase($this->Config()->Get('plugin', 'database', '')) - ->SetTable($this->Config()->Get('plugin', 'table', '')) - ->SetUserColumn($this->Config()->Get('plugin', 'usercol', '')) - ->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', '')) - ->SetUser($this->Config()->Get('plugin', 'user', '')) - ->SetPassword($this->Config()->Get('plugin', 'password', '')) - ->SetEncrypt($this->Config()->Get('plugin', 'encrypt', '')) - ->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', '')))) - ->SetLogger($this->Manager()->Actions()->Logger()) - ; - - break; - } - } - - /** - * @return array - */ - public function configMapping() - { - return array( - \RainLoop\Plugins\Property::NewInstance('host')->SetLabel('MySQL Host') - ->SetDefaultValue('mariadb'), - \RainLoop\Plugins\Property::NewInstance('port')->SetLabel('MySQL Port') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::INT) - ->SetDefaultValue(3306), - \RainLoop\Plugins\Property::NewInstance('database')->SetLabel('MySQL Database') - ->SetDefaultValue('postfix'), - \RainLoop\Plugins\Property::NewInstance('table')->SetLabel('MySQL table') - ->SetDefaultValue('mailbox'), - \RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('MySQL username column') - ->SetDefaultValue('username'), - \RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('MySQL password column') - ->SetDefaultValue('password'), - \RainLoop\Plugins\Property::NewInstance('user')->SetLabel('MySQL User') - ->SetDefaultValue('postfix'), - \RainLoop\Plugins\Property::NewInstance('password')->SetLabel('MySQL Password') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD) - ->SetDefaultValue(''), - \RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) - ->SetDefaultValue(array('SHA512-CRYPT','SHA256-CRYPT','md5', 'system', 'cleartext', 'mysql_encrypt')) - ->SetDescription('In what way do you want the passwords to be crypted ?'), - \RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails') - ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) - ->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net') - ->SetDefaultValue('*') - ); - } -} +addHook('main.fabrica', 'MainFabrica'); + } + + /** + * @return string + */ + public function Supported() + { + if (!extension_loaded('pdo') || !class_exists('PDO')) + { + return 'The PHP extension PDO must be installed to use this plugin'; + } + + $aDrivers = \PDO::getAvailableDrivers(); + if (!is_array($aDrivers) || (!in_array('mysql', $aDrivers) && !in_array('pgsql', $aDrivers))) + { + return 'The PHP extension PDO (mysql or pgsql) must be installed to use this plugin'; + } + + return ''; + } + + /** + * @param string $sName + * @param mixed $oProvider + */ + public function MainFabrica($sName, &$oProvider) + { + switch ($sName) + { + case 'change-password': + + include_once __DIR__.'/ChangePasswordPostfixAdminDriver.php'; + + $oProvider = new ChangePasswordPostfixAdminDriver(); + + $oProvider + ->SetEngine($this->Config()->Get('plugin', 'engine','')) + ->SetHost($this->Config()->Get('plugin', 'host', '')) + ->SetPort((int) $this->Config()->Get('plugin', 'port', 3306)) + ->SetDatabase($this->Config()->Get('plugin', 'database', '')) + ->SetTable($this->Config()->Get('plugin', 'table', '')) + ->SetUserColumn($this->Config()->Get('plugin', 'usercol', '')) + ->SetPasswordColumn($this->Config()->Get('plugin', 'passcol', '')) + ->SetUser($this->Config()->Get('plugin', 'user', '')) + ->SetPassword($this->Config()->Get('plugin', 'password', '')) + ->SetEncrypt($this->Config()->Get('plugin', 'encrypt', '')) + ->SetAllowedEmails(\strtolower(\trim($this->Config()->Get('plugin', 'allowed_emails', '')))) + ->SetLogger($this->Manager()->Actions()->Logger()) + ; + + break; + } + } + + /** + * @return array + */ + public function configMapping() + { + return array( + \RainLoop\Plugins\Property::NewInstance('engine')->SetLabel('Engine') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) + ->SetDefaultValue(array('MySQL', 'PostgreSQL')) + ->SetDescription('Database Engine'), + \RainLoop\Plugins\Property::NewInstance('host')->SetLabel('Host') + ->SetDefaultValue('127.0.0.1'), + \RainLoop\Plugins\Property::NewInstance('port')->SetLabel('Port') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::INT) + ->SetDefaultValue(3306), + \RainLoop\Plugins\Property::NewInstance('database')->SetLabel('Database') + ->SetDefaultValue('postfixadmin'), + \RainLoop\Plugins\Property::NewInstance('table')->SetLabel('table') + ->SetDefaultValue('mailbox'), + \RainLoop\Plugins\Property::NewInstance('usercol')->SetLabel('username column') + ->SetDefaultValue('username'), + \RainLoop\Plugins\Property::NewInstance('passcol')->SetLabel('password column') + ->SetDefaultValue('password'), + \RainLoop\Plugins\Property::NewInstance('user')->SetLabel('User') + ->SetDefaultValue('postfixadmin'), + \RainLoop\Plugins\Property::NewInstance('password')->SetLabel('Password') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD) + ->SetDefaultValue(''), + \RainLoop\Plugins\Property::NewInstance('encrypt')->SetLabel('Encrypt') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::SELECTION) + ->SetDefaultValue(array('md5crypt', 'md5', 'system', 'cleartext', 'mysql_encrypt', 'SHA256-CRYPT', 'SHA512-CRYPT')) + ->SetDescription('In what way do you want the passwords to be crypted ?'), + \RainLoop\Plugins\Property::NewInstance('allowed_emails')->SetLabel('Allowed emails') + ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT) + ->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net') + ->SetDefaultValue('*') + ); + } +} diff --git a/rootfs/usr/local/include/postfixadmin-change-password/md5crypt.php b/rootfs/usr/local/include/postfixadmin-change-password/md5crypt.php new file mode 100644 index 0000000..13f878e --- /dev/null +++ b/rootfs/usr/local/include/postfixadmin-change-password/md5crypt.php @@ -0,0 +1,139 @@ + 0; $i -= 16) + { + if ($i > 16) + { + $ctx .= substr($final,0,16); + } + else + { + $ctx .= substr($final,0,$i); + } + } + + $i = strlen($pw); + + while ($i > 0) + { + if ($i & 1) + { + $ctx .= chr(0); + } + else + { + $ctx .= $pw[0]; + } + + $i = $i >> 1; + } + + $final = hex2bin(md5($ctx)); + + for ($i=0; $i<1000; $i++) + { + $ctx1 = ""; + if ($i & 1) + { + $ctx1 .= $pw; + } + else + { + $ctx1 .= substr($final,0,16); + } + if ($i % 3) + { + $ctx1 .= $salt; + } + if ($i % 7) + { + $ctx1 .= $pw; + } + if ($i & 1) + { + $ctx1 .= substr($final, 0, 16); + } + else + { + $ctx1 .= $pw; + } + + $final = hex2bin(md5($ctx1)); + } + + $passwd = ""; + $passwd .= to64(((ord($final[0]) << 16) | (ord($final[6]) << 8) | (ord($final[12]))), 4); + $passwd .= to64(((ord($final[1]) << 16) | (ord($final[7]) << 8) | (ord($final[13]))), 4); + $passwd .= to64(((ord($final[2]) << 16) | (ord($final[8]) << 8) | (ord($final[14]))), 4); + $passwd .= to64(((ord($final[3]) << 16) | (ord($final[9]) << 8) | (ord($final[15]))), 4); + $passwd .= to64(((ord($final[4]) << 16) | (ord($final[10]) << 8) | (ord($final[5]))), 4); + $passwd .= to64(ord($final[11]), 2); + + return $magic.$salt.'$'.$passwd; +} + +function create_salt() +{ + srand((double) microtime() * 1000000); + return substr(md5(rand(0,9999999)), 0, 8); +} + +// PHP around 5.3.8 includes hex2bin as native function - http://php.net/hex2bin +if (!function_exists('hex2bin')) +{ + function hex2bin($str) + { + $len = strlen($str); + $nstr = ""; + for ($i = 0; $i < $len; $i += 2) + { + $num = sscanf(substr($str, $i, 2), "%x"); + $nstr .= chr($num[0]); + } + + return $nstr; + } +} + +function to64($v, $n) +{ + $ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + $ret = ""; + + while (($n - 1) >= 0) + { + $n--; + $ret .= $ITOA64[$v & 0x3f]; + $v = $v >> 6; + } + + return $ret; +} \ No newline at end of file