Skip to content

Instantly share code, notes, and snippets.

@jerrykan
Created December 28, 2011 03:33
Show Gist options
  • Save jerrykan/1526059 to your computer and use it in GitHub Desktop.
Save jerrykan/1526059 to your computer and use it in GitHub Desktop.
sqlite3 driver for roundcube password plugin
<?php
/**
* sqlite3 Password Driver
*
* Driver for passwords stored in sqlite3 database
*
* @version 0.8
* @author John Kristensen <john@jerrykan.com>
*
*/
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;
}
?>
@naidu
Copy link

naidu commented Mar 21, 2017

What this can be used for?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment