From ab0b51a1fef87bcc643c3aaf2e635c811b28ccd8 Mon Sep 17 00:00:00 2001 From: alecpl <alec@alec.pl> Date: Tue, 15 Feb 2011 06:10:59 -0500 Subject: [PATCH] - Use only one from IMAP authentication methods to prevent login delays (1487784) --- program/include/rcube_imap_generic.php | 158 +++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 111 insertions(+), 47 deletions(-) diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php index 9eeb028..cc590e0 100644 --- a/program/include/rcube_imap_generic.php +++ b/program/include/rcube_imap_generic.php @@ -5,7 +5,7 @@ | program/include/rcube_imap_generic.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2010, Roundcube Dev. - Switzerland | + | Copyright (C) 2005-2010, The Roundcube Dev Team | | Licensed under the GNU GPL | | | | PURPOSE: | @@ -371,10 +371,43 @@ return false; } - function getCapability($name) + private function hasCapability($name) { + if (empty($this->capability) || $name == '') { + return false; + } + if (in_array($name, $this->capability)) { return true; + } + else if (strpos($name, '=')) { + return false; + } + + $result = array(); + foreach ($this->capability as $cap) { + $entry = explode('=', $cap); + if ($entry[0] == $name) { + $result[] = $entry[1]; + } + } + + return !empty($result) ? $result : false; + } + + /** + * Capabilities checker + * + * @param string $name Capability name + * + * @return mixed Capability values array for key=value pairs, true/false for others + */ + function getCapability($name) + { + $result = $this->hasCapability($name); + + if (!empty($result)) { + return $result; } else if ($this->capability_readed) { return false; @@ -390,11 +423,7 @@ $this->capability_readed = true; - if (in_array($name, $this->capability)) { - return true; - } - - return false; + return $this->hasCapability($name); } function clearCapability() @@ -730,23 +759,35 @@ } } + // Send ID info + if (!empty($this->prefs['ident']) && $this->getCapability('ID')) { + $this->id($this->prefs['ident']); + } + $auth_methods = array(); $result = null; // check for supported auth methods if ($auth_method == 'CHECK') { - if ($this->getCapability('AUTH=DIGEST-MD5')) { - $auth_methods[] = 'DIGEST-MD5'; - } - if ($this->getCapability('AUTH=CRAM-MD5') || $this->getCapability('AUTH=CRAM_MD5')) { - $auth_methods[] = 'CRAM-MD5'; - } - if ($this->getCapability('AUTH=PLAIN')) { - $auth_methods[] = 'PLAIN'; + if ($auth_caps = $this->getCapability('AUTH')) { + $auth_methods = $auth_caps; } // RFC 2595 (LOGINDISABLED) LOGIN disabled when connection is not secure - if (!$this->getCapability('LOGINDISABLED')) { + $login_disabled = $this->getCapability('LOGINDISABLED'); + if (($key = array_search('LOGIN', $auth_methods)) !== false) { + if ($login_disabled) { + unset($auth_methods[$key]); + } + } + else if (!$login_disabled) { $auth_methods[] = 'LOGIN'; + } + + // Use best (for security) supported authentication method + foreach (array('DIGEST-MD5', 'CRAM-MD5', 'CRAM_MD5', 'PLAIN', 'LOGIN') as $auth_method) { + if (in_array($auth_method, $auth_methods)) { + break; + } } } else { @@ -757,30 +798,28 @@ return false; } // replace AUTH with CRAM-MD5 for backward compat. - $auth_methods[] = $auth_method == 'AUTH' ? 'CRAM-MD5' : $auth_method; + if ($auth_method == 'AUTH') { + $auth_method = 'CRAM-MD5'; + } } // pre-login capabilities can be not complete $this->capability_readed = false; // Authenticate - foreach ($auth_methods as $method) { - switch ($method) { - case 'DIGEST-MD5': + switch ($auth_method) { + case 'CRAM_MD5': + $auth_method = 'CRAM-MD5'; case 'CRAM-MD5': + case 'DIGEST-MD5': case 'PLAIN': - $result = $this->authenticate($user, $password, $method); + $result = $this->authenticate($user, $password, $auth_method); break; case 'LOGIN': $result = $this->login($user, $password); break; default: - $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $method"); - } - - if (is_resource($result)) { - break; - } + $this->setError(self::ERROR_BAD, "Configuration error. Unknown auth method: $auth_method"); } // Connected and authenticated @@ -1126,6 +1165,44 @@ return false; } + /** + * Executes ID command (RFC2971) + * + * @param array $items Client identification information key/value hash + * + * @return array Server identification information key/value hash + * @access public + * @since 0.6 + */ + function id($items=array()) + { + if (is_array($items) && !empty($items)) { + foreach ($items as $key => $value) { + $args[] = $this->escape($key); + $args[] = $this->escape($value); + } + } + + list($code, $response) = $this->execute('ID', array( + !empty($args) ? '(' . implode(' ', (array) $args) . ')' : $this->escape(null) + )); + + + if ($code == self::ERROR_OK && preg_match('/\* ID /i', $response)) { + $response = substr($response, 5); // remove prefix "* ID " + $items = $this->tokenizeResponse($response); + $result = null; + + for ($i=0, $len=count($items); $i<$len; $i += 2) { + $result[$items[$i]] = $items[$i+1]; + } + + return $result; + } + + return false; + } + function sort($mailbox, $field, $add='', $is_uid=FALSE, $encoding = 'US-ASCII') { $field = strtoupper($field); @@ -1463,7 +1540,7 @@ // INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...) // BODY[HEADER.FIELDS ... - if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/s', $line, $matches)) { + if (preg_match('/^\* [0-9]+ FETCH \((.*) BODY/sU', $line, $matches)) { $str = $matches[1]; // swap parents with quotes, then explode @@ -1500,7 +1577,7 @@ // BODYSTRUCTURE if ($bodystr) { - while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/s', $line, $m)) { + while (!preg_match('/ BODYSTRUCTURE (.*) BODY\[HEADER.FIELDS/sU', $line, $m)) { $line2 = $this->readLine(1024); $line .= $this->multLine($line2, true); } @@ -1600,7 +1677,7 @@ break; case 'content-type': $ctype_parts = preg_split('/[; ]/', $string); - $result[$id]->ctype = array_shift($ctype_parts); + $result[$id]->ctype = strtolower(array_shift($ctype_parts)); if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) { $result[$id]->charset = $regs[1]; } @@ -3192,21 +3269,7 @@ */ private function strToTime($date) { - // support non-standard "GMTXXXX" literal - $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date); - // if date parsing fails, we have a date in non-rfc format. - // remove token from the end and try again - while ((($ts = @strtotime($date))===false) || ($ts < 0)) { - $d = explode(' ', $date); - array_pop($d); - if (!$d) { - break; - } - $date = implode(' ', $d); - } - - $ts = (int) $ts; - + $ts = (int) rcube_strtotime($date); return $ts < 0 ? 0 : $ts; } @@ -3253,10 +3316,11 @@ else if ($string === '') { return '""'; } + // need quoted-string? find special chars: SP, CTL, (, ), {, %, *, ", \, ] + // plus [ character as a workaround for DBMail's bug (#1487766) else if ($force_quotes || - preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5C\x5D\x7F]+)/', $string) + preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5B\x5C\x5D\x7F]+)/', $string) ) { - // string: special chars: SP, CTL, (, ), {, %, *, ", \, ] return '"' . strtr($string, array('"'=>'\\"', '\\' => '\\\\')) . '"'; } -- Gitblit v1.9.1