Created
December 28, 2011 03:33
-
-
Save jerrykan/1526059 to your computer and use it in GitHub Desktop.
sqlite3 driver for roundcube password plugin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* sqlite3 Password Driver | |
* | |
* Driver for passwords stored in sqlite3 database | |
* | |
* @version 0.8 | |
* @author John Kristensen <[email protected]> | |
* | |
*/ | |
function password_save($curpass, $passwd) | |
{ | |
$rcmail = rcmail::get_instance(); | |
if (!($sql = $rcmail->config->get('password_query'))) | |
$sql = 'SELECT update_passwd(%c, %u)'; | |
if ($dsn = $rcmail->config->get('password_db_dsn')) { | |
$db = new PDO($dsn); | |
} else { | |
$db = $rcmail->get_dbh(); | |
} | |
if ($err = $db->errorCode()) | |
return PASSWORD_ERROR; | |
// crypted password | |
if (strpos($sql, '%c') !== FALSE) { | |
$salt = ''; | |
if (CRYPT_MD5) { | |
// Always use eight salt characters for MD5 (#1488136) | |
$len = 8; | |
} else if (CRYPT_STD_DES) { | |
$len = 2; | |
} else { | |
return PASSWORD_CRYPT_ERROR; | |
} | |
//Restrict the character set used as salt (#1488136) | |
$seedchars = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; | |
for ($i = 0; $i < $len ; $i++) { | |
$salt .= $seedchars[rand(0, 63)]; | |
} | |
$sql = str_replace('%c', $db->quote(crypt($passwd, CRYPT_MD5 ? '$1$'.$salt.'$' : $salt)), $sql); | |
} | |
// dovecotpw | |
if (strpos($sql, '%D') !== FALSE) { | |
if (!($dovecotpw = $rcmail->config->get('password_dovecotpw'))) | |
$dovecotpw = 'dovecotpw'; | |
if (!($method = $rcmail->config->get('password_dovecotpw_method'))) | |
$method = 'CRAM-MD5'; | |
// use common temp dir | |
$tmp_dir = $rcmail->config->get('temp_dir'); | |
$tmpfile = tempnam($tmp_dir, 'roundcube-'); | |
$pipe = popen("$dovecotpw -s '$method' > '$tmpfile'", "w"); | |
if (!$pipe) { | |
unlink($tmpfile); | |
return PASSWORD_CRYPT_ERROR; | |
} | |
else { | |
fwrite($pipe, $passwd . "\n", 1+strlen($passwd)); usleep(1000); | |
fwrite($pipe, $passwd . "\n", 1+strlen($passwd)); | |
pclose($pipe); | |
$newpass = trim(file_get_contents($tmpfile), "\n"); | |
if (!preg_match('/^\{' . $method . '\}/', $newpass)) { | |
return PASSWORD_CRYPT_ERROR; | |
} | |
if (!$rcmail->config->get('password_dovecotpw_with_method')) | |
$newpass = trim(str_replace('{' . $method . '}', '', $newpass)); | |
unlink($tmpfile); | |
} | |
$sql = str_replace('%D', $db->quote($newpass), $sql); | |
} | |
// hashed passwords | |
if (preg_match('/%[n|q]/', $sql)) { | |
if (!extension_loaded('hash')) { | |
raise_error(array( | |
'code' => 600, | |
'type' => 'php', | |
'file' => __FILE__, 'line' => __LINE__, | |
'message' => "Password plugin: 'hash' extension not loaded!" | |
), true, false); | |
return PASSWORD_ERROR; | |
} | |
if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) | |
$hash_algo = 'sha1'; | |
$hash_passwd = hash($hash_algo, $passwd); | |
$hash_curpass = hash($hash_algo, $curpass); | |
if ($rcmail->config->get('password_hash_base64')) { | |
$hash_passwd = base64_encode(pack('H*', $hash_passwd)); | |
$hash_curpass = base64_encode(pack('H*', $hash_curpass)); | |
} | |
$sql = str_replace('%n', $db->quote($hash_passwd, PDO::PARAM_STR), $sql); | |
$sql = str_replace('%q', $db->quote($hash_curpass, PDO::PARAM_STR), $sql); | |
} | |
// Handle clear text passwords securely (#1487034) | |
$sql_vars = array(); | |
if (preg_match_all('/%[p|o]/', $sql, $m)) { | |
foreach ($m[0] as $var) { | |
if ($var == '%p') { | |
$sql = preg_replace('/%p/', '?', $sql, 1); | |
$sql_vars[] = (string) $passwd; | |
} | |
else { // %o | |
$sql = preg_replace('/%o/', '?', $sql, 1); | |
$sql_vars[] = (string) $curpass; | |
} | |
} | |
} | |
$local_part = $rcmail->user->get_username('local'); | |
$domain_part = $rcmail->user->get_username('domain'); | |
$username = $_SESSION['username']; | |
$host = $_SESSION['imap_host']; | |
// convert domains to/from punnycode | |
if ($rcmail->config->get('password_idn_ascii')) { | |
$domain_part = rcube_idn_to_ascii($domain_part); | |
$username = rcube_idn_to_ascii($username); | |
$host = rcube_idn_to_ascii($host); | |
} | |
else { | |
$domain_part = rcube_idn_to_utf8($domain_part); | |
$username = rcube_idn_to_utf8($username); | |
$host = rcube_idn_to_utf8($host); | |
} | |
// at least we should always have the local part | |
$sql = str_replace('%l', $db->quote($local_part, PDO::PARAM_STR), $sql); | |
$sql = str_replace('%d', $db->quote($domain_part, PDO::PARAM_STR), $sql); | |
$sql = str_replace('%u', $db->quote($username, PDO::PARAM_STR), $sql); | |
$sql = str_replace('%h', $db->quote($host, PDO::PARAM_STR), $sql); | |
$res = $db->prepare($sql); | |
$res->execute($sql_vars); | |
if (!intval($res->errorCode())) { | |
if (strtolower(substr(trim($query),0,6))=='select') { | |
if ($result = $res->fetchAll()) | |
return PASSWORD_SUCCESS; | |
} else { | |
// This is the good case: 1 row updated | |
if ($res->rowCount() == 1) | |
return PASSWORD_SUCCESS; | |
// @TODO: Some queries don't affect any rows | |
// Should we assume a success if there was no error? | |
} | |
} | |
return PASSWORD_ERROR; | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What this can be used for?