function digest_md5($username, $password)
{
global $config, $user;
$this->server_send('AUTH DIGEST-MD5');
if ($err_msg = $this->server_parse('334', __LINE__)) {
return $this->numeric_response_code == 503 ? false : $err_msg;
}
$md5_challenge = base64_decode($this->responses[0]);
// Parse the md5 challenge - from AUTH_SASL (PEAR)
$tokens = array();
while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\\)"|[^,]+)/i', $md5_challenge, $matches)) {
// Ignore these as per rfc2831
if ($matches[1] == 'opaque' || $matches[1] == 'domain') {
$md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
continue;
}
// Allowed multiple "realm" and "auth-param"
if (!empty($tokens[$matches[1]]) && ($matches[1] == 'realm' || $matches[1] == 'auth-param')) {
if (is_array($tokens[$matches[1]])) {
$tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
} else {
$tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
}
} else {
if (!empty($tokens[$matches[1]])) {
$tokens = array();
break;
} else {
$tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
}
}
// Remove the just parsed directive from the challenge
$md5_challenge = substr($md5_challenge, strlen($matches[0]) + 1);
}
// Realm
if (empty($tokens['realm'])) {
$tokens['realm'] = function_exists('php_uname') ? php_uname('n') : $user->host;
}
// Maxbuf
if (empty($tokens['maxbuf'])) {
$tokens['maxbuf'] = 65536;
}
// Required: nonce, algorithm
if (empty($tokens['nonce']) || empty($tokens['algorithm'])) {
$tokens = array();
}
$md5_challenge = $tokens;
if (!empty($md5_challenge)) {
$str = '';
for ($i = 0; $i < 32; $i++) {
$str .= chr(mt_rand(0, 255));
}
$cnonce = base64_encode($str);
$digest_uri = 'smtp/' . $config['smtp_host'];
$auth_1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $username, $md5_challenge['realm'], $password))), $md5_challenge['nonce'], $cnonce);
$auth_2 = 'AUTHENTICATE:' . $digest_uri;
$response_value = md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($auth_1), $md5_challenge['nonce'], $cnonce, md5($auth_2)));
$input_string = sprintf('username="%s",realm="%s",nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $username, $md5_challenge['realm'], $md5_challenge['nonce'], $cnonce, $digest_uri, $response_value, $md5_challenge['maxbuf']);
} else {
return isset($user->lang['INVALID_DIGEST_CHALLENGE']) ? $user->lang['INVALID_DIGEST_CHALLENGE'] : 'Invalid digest challenge';
}
$base64_method_digest_md5 = base64_encode($input_string);
$this->server_send($base64_method_digest_md5, true);
if ($err_msg = $this->server_parse('334', __LINE__)) {
return $err_msg;
}
$this->server_send(' ');
if ($err_msg = $this->server_parse('235', __LINE__)) {
return $err_msg;
}
return false;
}