composer format ...

pull/142/head
David Goodwin 7 years ago
parent 6446f3f6cc
commit b79ad2ae28

@ -892,152 +892,151 @@ function validate_password($password) {
} }
function _pacrypt_md5crypt($pw, $pw_db) { function _pacrypt_md5crypt($pw, $pw_db) {
$split_salt = preg_split('/\$/', $pw_db); $split_salt = preg_split('/\$/', $pw_db);
if (isset($split_salt[2])) { if (isset($split_salt[2])) {
$salt = $split_salt[2]; $salt = $split_salt[2];
return md5crypt($pw, $salt); return md5crypt($pw, $salt);
} }
return md5crypt($pw); return md5crypt($pw);
} }
function _pacrypt_crypt($pw, $pw_db) { function _pacrypt_crypt($pw, $pw_db) {
if ($pw_db) {
if ($pw_db) { return crypt($pw, $pw_db);
return crypt($pw, $pw_db); }
} return crypt($pw);
return crypt($pw);
} }
function _pacrypt_mysql_encrypt($pw, $pw_db) { function _pacrypt_mysql_encrypt($pw, $pw_db) {
// See https://sourceforge.net/tracker/?func=detail&atid=937966&aid=1793352&group_id=191583 // See https://sourceforge.net/tracker/?func=detail&atid=937966&aid=1793352&group_id=191583
// this is apparently useful for pam_mysql etc. // this is apparently useful for pam_mysql etc.
$pw = escape_string($pw); $pw = escape_string($pw);
if ($pw_db!="") { if ($pw_db!="") {
$salt=escape_string(substr($pw_db, 0, 2)); $salt=escape_string(substr($pw_db, 0, 2));
$res=db_query("SELECT ENCRYPT('".$pw."','".$salt."');"); $res=db_query("SELECT ENCRYPT('".$pw."','".$salt."');");
} else { } else {
$res=db_query("SELECT ENCRYPT('".$pw."');"); $res=db_query("SELECT ENCRYPT('".$pw."');");
} }
$l = db_row($res["result"]); $l = db_row($res["result"]);
$password = $l[0]; $password = $l[0];
return $password; return $password;
} }
function _pacrypt_authlib($pw, $pw_db) { function _pacrypt_authlib($pw, $pw_db) {
global $CONF; global $CONF;
$flavor = $CONF['authlib_default_flavor']; $flavor = $CONF['authlib_default_flavor'];
$salt = substr(create_salt(), 0, 2); # courier-authlib supports only two-character salts $salt = substr(create_salt(), 0, 2); # courier-authlib supports only two-character salts
if (preg_match('/^{.*}/', $pw_db)) { if (preg_match('/^{.*}/', $pw_db)) {
// we have a flavor in the db -> use it instead of default flavor // we have a flavor in the db -> use it instead of default flavor
$result = preg_split('/[{}]/', $pw_db, 3); # split at { and/or } $result = preg_split('/[{}]/', $pw_db, 3); # split at { and/or }
$flavor = $result[1]; $flavor = $result[1];
$salt = substr($result[2], 0, 2); $salt = substr($result[2], 0, 2);
} }
if (stripos($flavor, 'md5raw') === 0) { if (stripos($flavor, 'md5raw') === 0) {
$password = '{' . $flavor . '}' . md5($pw); $password = '{' . $flavor . '}' . md5($pw);
} elseif (stripos($flavor, 'md5') === 0) { } elseif (stripos($flavor, 'md5') === 0) {
$password = '{' . $flavor . '}' . base64_encode(md5($pw, true)); $password = '{' . $flavor . '}' . base64_encode(md5($pw, true));
} elseif (stripos($flavor, 'crypt') === 0) { } elseif (stripos($flavor, 'crypt') === 0) {
$password = '{' . $flavor . '}' . crypt($pw, $salt); $password = '{' . $flavor . '}' . crypt($pw, $salt);
} elseif (stripos($flavor, 'SHA') === 0) { } elseif (stripos($flavor, 'SHA') === 0) {
$password = '{' . $flavor . '}' . base64_encode(sha1($pw, true)); $password = '{' . $flavor . '}' . base64_encode(sha1($pw, true));
} else { } else {
die("authlib_default_flavor '" . $flavor . "' unknown. Valid flavors are 'md5raw', 'md5', 'SHA' and 'crypt'"); die("authlib_default_flavor '" . $flavor . "' unknown. Valid flavors are 'md5raw', 'md5', 'SHA' and 'crypt'");
} }
return $password; return $password;
} }
function _pacrypt_dovecot($pw, $pw_db) { function _pacrypt_dovecot($pw, $pw_db) {
global $CONF; global $CONF;
$split_method = preg_split('/:/', $CONF['encrypt']); $split_method = preg_split('/:/', $CONF['encrypt']);
$method = strtoupper($split_method[1]); $method = strtoupper($split_method[1]);
# If $pw_db starts with {method}, change $method accordingly # If $pw_db starts with {method}, change $method accordingly
if (!empty($pw_db) && preg_match('/^\{([A-Z0-9.-]+)\}.+/', $pw_db, $method_matches)) { if (!empty($pw_db) && preg_match('/^\{([A-Z0-9.-]+)\}.+/', $pw_db, $method_matches)) {
$method = $method_matches[1]; $method = $method_matches[1];
} }
if (! preg_match("/^[A-Z0-9.-]+$/", $method)) { if (! preg_match("/^[A-Z0-9.-]+$/", $method)) {
die("invalid dovecot encryption method"); die("invalid dovecot encryption method");
} }
# TODO: check against a fixed list? # TODO: check against a fixed list?
# if (strtolower($method) == 'md5-crypt') die("\$CONF['encrypt'] = 'dovecot:md5-crypt' will not work because dovecotpw generates a random salt each time. Please use \$CONF['encrypt'] = 'md5crypt' instead."); # if (strtolower($method) == 'md5-crypt') die("\$CONF['encrypt'] = 'dovecot:md5-crypt' will not work because dovecotpw generates a random salt each time. Please use \$CONF['encrypt'] = 'md5crypt' instead.");
# $crypt_method = preg_match ("/.*-CRYPT$/", $method); # $crypt_method = preg_match ("/.*-CRYPT$/", $method);
# digest-md5 and SCRAM-SHA-1 hashes include the username - until someone implements it, let's declare it as unsupported # digest-md5 and SCRAM-SHA-1 hashes include the username - until someone implements it, let's declare it as unsupported
if (strtolower($method) == 'digest-md5') { if (strtolower($method) == 'digest-md5') {
die("Sorry, \$CONF['encrypt'] = 'dovecot:digest-md5' is not supported by PostfixAdmin."); die("Sorry, \$CONF['encrypt'] = 'dovecot:digest-md5' is not supported by PostfixAdmin.");
} }
if (strtoupper($method) == 'SCRAM-SHA-1') { if (strtoupper($method) == 'SCRAM-SHA-1') {
die("Sorry, \$CONF['encrypt'] = 'dovecot:scram-sha-1' is not supported by PostfixAdmin."); die("Sorry, \$CONF['encrypt'] = 'dovecot:scram-sha-1' is not supported by PostfixAdmin.");
} }
# TODO: add -u option for those hashes, or for everything that is salted (-u was available before dovecot 2.1 -> no problem with backward compability) # TODO: add -u option for those hashes, or for everything that is salted (-u was available before dovecot 2.1 -> no problem with backward compability)
$dovecotpw = "doveadm pw"; $dovecotpw = "doveadm pw";
if (!empty($CONF['dovecotpw'])) { if (!empty($CONF['dovecotpw'])) {
$dovecotpw = $CONF['dovecotpw']; $dovecotpw = $CONF['dovecotpw'];
} }
# Use proc_open call to avoid safe_mode problems and to prevent showing plain password in process table # Use proc_open call to avoid safe_mode problems and to prevent showing plain password in process table
$spec = array( $spec = array(
0 => array("pipe", "r"), // stdin 0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout 1 => array("pipe", "w"), // stdout
2 => array("pipe", "w"), // stderr 2 => array("pipe", "w"), // stderr
); );
$nonsaltedtypes = "SHA|SHA1|SHA256|SHA512|CLEAR|CLEARTEXT|PLAIN|PLAIN-TRUNC|CRAM-MD5|HMAC-MD5|PLAIN-MD4|PLAIN-MD5|LDAP-MD5|LANMAN|NTLM|RPA"; $nonsaltedtypes = "SHA|SHA1|SHA256|SHA512|CLEAR|CLEARTEXT|PLAIN|PLAIN-TRUNC|CRAM-MD5|HMAC-MD5|PLAIN-MD4|PLAIN-MD5|LDAP-MD5|LANMAN|NTLM|RPA";
$salted = ! preg_match("/^($nonsaltedtypes)(\.B64|\.BASE64|\.HEX)?$/", strtoupper($method)); $salted = ! preg_match("/^($nonsaltedtypes)(\.B64|\.BASE64|\.HEX)?$/", strtoupper($method));
$dovepasstest = ''; $dovepasstest = '';
if ($salted && (!empty($pw_db))) { if ($salted && (!empty($pw_db))) {
# only use -t for salted passwords to be backward compatible with dovecot < 2.1 # only use -t for salted passwords to be backward compatible with dovecot < 2.1
$dovepasstest = " -t " . escapeshellarg($pw_db); $dovepasstest = " -t " . escapeshellarg($pw_db);
} }
$pipe = proc_open("$dovecotpw '-s' $method$dovepasstest", $spec, $pipes); $pipe = proc_open("$dovecotpw '-s' $method$dovepasstest", $spec, $pipes);
if (!$pipe) { if (!$pipe) {
die("can't proc_open $dovecotpw"); die("can't proc_open $dovecotpw");
} }
// use dovecot's stdin, it uses getpass() twice (except when using -t) // use dovecot's stdin, it uses getpass() twice (except when using -t)
// Write pass in pipe stdin // Write pass in pipe stdin
if (empty($dovepasstest)) { if (empty($dovepasstest)) {
fwrite($pipes[0], $pw . "\n", 1+strlen($pw)); fwrite($pipes[0], $pw . "\n", 1+strlen($pw));
usleep(1000); usleep(1000);
} }
fwrite($pipes[0], $pw . "\n", 1+strlen($pw)); fwrite($pipes[0], $pw . "\n", 1+strlen($pw));
fclose($pipes[0]); fclose($pipes[0]);
// Read hash from pipe stdout // Read hash from pipe stdout
$password = fread($pipes[1], "200"); $password = fread($pipes[1], "200");
if (empty($dovepasstest)) { if (empty($dovepasstest)) {
if (!preg_match('/^\{' . $method . '\}/', $password)) { if (!preg_match('/^\{' . $method . '\}/', $password)) {
$stderr_output = stream_get_contents($pipes[2]); $stderr_output = stream_get_contents($pipes[2]);
error_log('dovecotpw password encryption failed.'); error_log('dovecotpw password encryption failed.');
error_log('STDERR output: ' . $stderr_output); error_log('STDERR output: ' . $stderr_output);
die("can't encrypt password with dovecotpw, see error log for details"); die("can't encrypt password with dovecotpw, see error log for details");
} }
} else { } else {
if (!preg_match('(verified)', $password)) { if (!preg_match('(verified)', $password)) {
$password="Thepasswordcannotbeverified"; $password="Thepasswordcannotbeverified";
} else { } else {
$password = rtrim(str_replace('(verified)', '', $password)); $password = rtrim(str_replace('(verified)', '', $password));
} }
} }
fclose($pipes[1]); fclose($pipes[1]);
fclose($pipes[2]); fclose($pipes[2]);
proc_close($pipe); proc_close($pipe);
if ((!empty($pw_db)) && (substr($pw_db, 0, 1) != '{')) { if ((!empty($pw_db)) && (substr($pw_db, 0, 1) != '{')) {
# for backward compability with "old" dovecot passwords that don't have the {method} prefix # for backward compability with "old" dovecot passwords that don't have the {method} prefix
$password = str_replace('{' . $method . '}', '', $password); $password = str_replace('{' . $method . '}', '', $password);
} }
return rtrim($password); return rtrim($password);
} }
@ -1061,22 +1060,21 @@ function pacrypt($pw, $pw_db="") {
return _pacrypt_md5crypt($pw, $pw_db); return _pacrypt_md5crypt($pw, $pw_db);
case 'md5': case 'md5':
return md5($pw); return md5($pw);
case 'system' : case 'system':
return _pacrypt_crypt($pw, $pw_db); return _pacrypt_crypt($pw, $pw_db);
case 'cleartext' : case 'cleartext':
return $pw; return $pw;
case 'mysql_encrypt' : case 'mysql_encrypt':
return _pacrypt_mysql_encrypt($pw, $pw_db); return _pacrypt_mysql_encrypt($pw, $pw_db);
case 'authlib': case 'authlib':
return _pacrypt_authlib($pw, $pw_db); return _pacrypt_authlib($pw, $pw_db);
} }
if (preg_match("/^dovecot:/", $CONF['encrypt'])) { if (preg_match("/^dovecot:/", $CONF['encrypt'])) {
return _pacrypt_dovecot($pw, $pw_db); return _pacrypt_dovecot($pw, $pw_db);
} }
die('unknown/invalid $CONF["encrypt"] setting: ' . $CONF['encrypt']); die('unknown/invalid $CONF["encrypt"] setting: ' . $CONF['encrypt']);
} }
// //

@ -3,7 +3,6 @@
require_once('common.php'); require_once('common.php');
class PaCryptTest extends PHPUnit_Framework_TestCase { class PaCryptTest extends PHPUnit_Framework_TestCase {
public function testMd5Crypt() { public function testMd5Crypt() {
$hash = _pacrypt_md5crypt('test', ''); $hash = _pacrypt_md5crypt('test', '');
@ -23,11 +22,10 @@ class PaCryptTest extends PHPUnit_Framework_TestCase {
$this->assertNotEquals('test', $hash); $this->assertNotEquals('test', $hash);
$this->assertEquals($hash, _pacrypt_crypt('test', $hash)); $this->assertEquals($hash, _pacrypt_crypt('test', $hash));
} }
public function testMySQLEncrypt() { public function testMySQLEncrypt() {
if(!db_mysql()) { if (!db_mysql()) {
$this->markTestSkipped('Not using MySQL'); $this->markTestSkipped('Not using MySQL');
} }
@ -49,25 +47,24 @@ class PaCryptTest extends PHPUnit_Framework_TestCase {
public function testAuthlib() { public function testAuthlib() {
// too many options! // too many options!
foreach( foreach (
['md5raw' => '098f6bcd4621d373cade4e832627b4f6', ['md5raw' => '098f6bcd4621d373cade4e832627b4f6',
'md5' => 'CY9rzUYh03PK3k6DJie09g==', 'md5' => 'CY9rzUYh03PK3k6DJie09g==',
// crypt requires salt ... // crypt requires salt ...
'SHA' => 'qUqP5cyxm6YcTAhz05Hph5gvu9M='] as $flavour => $hash) { 'SHA' => 'qUqP5cyxm6YcTAhz05Hph5gvu9M='] as $flavour => $hash) {
$CONF['authlib_default_flavour'] = $flavour; $CONF['authlib_default_flavour'] = $flavour;
$stored = "{" . $flavour . "}$hash"; $stored = "{" . $flavour . "}$hash";
$hash = _pacrypt_authlib('test', $stored); $hash = _pacrypt_authlib('test', $stored);
$this->assertEquals($hash, $stored, "Hash: $hash vs Stored: $stored" ); $this->assertEquals($hash, $stored, "Hash: $hash vs Stored: $stored");
//var_dump("Hash: $hash from $flavour"); //var_dump("Hash: $hash from $flavour");
} }
} }
public function testPacryptDovecot() { public function testPacryptDovecot() {
global $CONF; global $CONF;
if(!file_exists('/usr/bin/doveadm')) { if (!file_exists('/usr/bin/doveadm')) {
$this->markTestSkipped("No /usr/bin/doveadm"); $this->markTestSkipped("No /usr/bin/doveadm");
} }
@ -79,10 +76,7 @@ class PaCryptTest extends PHPUnit_Framework_TestCase {
$this->assertEquals($expected_hash, _pacrypt_dovecot('test', '')); $this->assertEquals($expected_hash, _pacrypt_dovecot('test', ''));
$this->assertEquals($expected_hash, _pacrypt_dovecot('test', $expected_hash)); $this->assertEquals($expected_hash, _pacrypt_dovecot('test', $expected_hash));
} }
} }
/* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */ /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */

@ -8,8 +8,6 @@
require_once('RemoteTest.php'); require_once('RemoteTest.php');
class RemoteUserTest extends RemoteTest { class RemoteUserTest extends RemoteTest {
public function testChangePassword() { public function testChangePassword() {
try { try {
$this->assertTrue($this->user->login($this->username, $this->password)); $this->assertTrue($this->user->login($this->username, $this->password));

Loading…
Cancel
Save