summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralecpl <alec@alec.pl>2010-10-22 18:52:20 +0000
committeralecpl <alec@alec.pl>2010-10-22 18:52:20 +0000
commit7bf255bfe1e2fb573da7d1b107bc7cb7fef35198 (patch)
tree08713795e24b7dd82c4550433def663d4bd76b2a
parentcb7d32ebdd1c783f201e2f3fa6c52f1fafdc6fcf (diff)
- Add SASL-IR support (RFC 4959)
- Add LOGINDISABLED support (RFC 2595) - Add support for AUTH=PLAIN authentication to IMAP
-rw-r--r--CHANGELOG15
-rw-r--r--config/main.inc.php.dist4
-rw-r--r--program/include/rcube_imap_generic.php170
3 files changed, 124 insertions, 65 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 6cb80558e..ca435bd09 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -21,8 +21,8 @@ CHANGELOG Roundcube Webmail
- Improve tabs to fixed width and add tabs in identities info (#1486974)
- Add unique index on users.username+users.mail_host
- Make htmleditor option more consistent and add option to use HTML on reply to HTML message (#1485840)
-- Use empty envelope sender address for message disposition notifications (RFC2298.3)
-- Support SMTP Delivery Status Notifications - RFC3461 (#1486142)
+- Use empty envelope sender address for message disposition notifications (RFC 2298.3)
+- Support SMTP Delivery Status Notifications - RFC 3461 (#1486142)
- Use css sprite image for messages list
- Add (different) attachment icon for messages of type multipart/report (#1486165)
- Prevent from inserting empty link when composing HTML message (#1486944)
@@ -31,16 +31,19 @@ CHANGELOG Roundcube Webmail
- Improve displaying of UI messages (#1486977)
- Fix double e-mail filed in identity form (#1487054)
- Display IMAP errors for LIST/THREAD/SEARCH commands (#1486905)
-- Add LITERAL+ (IMAP4 non-synchronizing literals) support (RFC2088)
+- Add LITERAL+ (IMAP4 non-synchronizing literals) support (RFC 2088)
- Add separate column for message status icon (#1486665)
-- Add ACL extension support into IMAP classes (RFC4314)
+- Add ACL extension support into IMAP classes (RFC 4314)
- Add ANNOTATEMORE extension support into IMAP classes (draft-daboo-imap-annotatemore)
-- Add METADATA extension support into IMAP classes (RFC5464)
+- Add METADATA extension support into IMAP classes (RFC 5464)
- Fix decoding of e-mail address strings in message headers (#1487068)
- Fix handling of attachments when Content-Disposition is not inline nor attachment (#1487051)
- Improve performance of unseen messages counting (#1487058)
- Improve performance of messages counting using ESEARCH extension (RFC4731)
-- Add LIST-STATUS support in rcube_imap_generic class (RFC5819)
+- Add LIST-STATUS support in rcube_imap_generic class (RFC 5819)
+- Add SASL-IR support in IMAP (RFC 4959)
+- Add LOGINDISABLED support (RFC 2595)
+- Add support for AUTH=PLAIN in IMAP authentication
RELEASE 0.4.2
-------------
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 4540adc34..664251217 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -70,8 +70,8 @@ $rcmail_config['default_host'] = '';
// TCP port used for IMAP connections
$rcmail_config['default_port'] = 143;
-// IMAP auth type. Can be "auth" (CRAM-MD5), "plain" (PLAIN) or "check" to auto detect.
-// Optional, defaults to "check"
+// IMAP auth type. Can be "auth" (CRAM-MD5), "plain" (PLAIN), "login" (LOGIN)
+// or "check" (or empty) to auto detect. Optional, defaults to "check"
$rcmail_config['imap_auth_type'] = null;
// If you know your imap's root directory and its folder delimiter,
diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php
index bea9d07c0..67d71f619 100644
--- a/program/include/rcube_imap_generic.php
+++ b/program/include/rcube_imap_generic.php
@@ -370,44 +370,95 @@ class rcube_imap_generic
$this->capability_readed = false;
}
- function authenticate($user, $pass, $encChallenge)
+ /**
+ * CRAM-MD5/PLAIN Authentication
+ *
+ * @param string $user
+ * @param string $pass
+ * @param string $type Authentication type (PLAIN or CRAM-MD5)
+ *
+ * @return resource Connection resourse on success, error code on error
+ */
+ function authenticate($user, $pass, $type='PLAIN')
{
- $ipad = '';
- $opad = '';
+ if ($type == 'CRAM-MD5') {
+ $ipad = '';
+ $opad = '';
- // initialize ipad, opad
- for ($i=0; $i<64; $i++) {
- $ipad .= chr(0x36);
- $opad .= chr(0x5C);
- }
+ // initialize ipad, opad
+ for ($i=0; $i<64; $i++) {
+ $ipad .= chr(0x36);
+ $opad .= chr(0x5C);
+ }
- // pad $pass so it's 64 bytes
- $padLen = 64 - strlen($pass);
- for ($i=0; $i<$padLen; $i++) {
- $pass .= chr(0);
- }
+ // pad $pass so it's 64 bytes
+ $padLen = 64 - strlen($pass);
+ for ($i=0; $i<$padLen; $i++) {
+ $pass .= chr(0);
+ }
+
+ $this->putLine($this->next_tag() . " AUTHENTICATE CRAM-MD5");
+ $line = trim($this->readLine(1024));
+
+ if ($line[0] == '+') {
+ $challenge = substr($line,2);
+ }
+ else {
+ return self::ERROR_BYE;
+ }
- // generate hash
- $hash = md5($this->_xor($pass,$opad) . pack("H*", md5($this->_xor($pass, $ipad) . base64_decode($encChallenge))));
+ // generate hash
+ $hash = md5($this->_xor($pass, $opad) . pack("H*", md5($this->_xor($pass, $ipad) . base64_decode($encChallenge))));
+ $reply = base64_encode($user . ' ' . $hash);
- // generate reply
- $reply = base64_encode($user . ' ' . $hash);
+ // send result, get reply and process it
+ $this->putLine($reply);
+ $line = $this->readLine(1024);
+ $result = $this->parseResult($line);
+ if ($result != self::ERROR_OK) {
+ $this->set_error($result, "Unble to authenticate user (CRAM-MD5): $line");
+ }
+ }
+ else { // PLAIN
+ $reply = base64_encode($user . chr(0) . $user . chr(0) . $pass);
- // send result, get reply
- $this->putLine($reply);
- $line = $this->readLine(1024);
+ // RFC 4959 (SASL-IR): save one round trip
+ if ($this->getCapability('SASL-IR')) {
+ $result = $this->execute("AUTHENTICATE PLAIN", array($reply), self::COMMAND_NORESPONSE);
+ }
+ else {
+ $this->putLine($this->next_tag() . " AUTHENTICATE PLAIN");
+ $line = trim($this->readLine(1024));
+
+ if ($line[0] != '+') {
+ return self::ERROR_BYE;
+ }
+
+ // send result, get reply and process it
+ $this->putLine($reply);
+ $line = $this->readLine(1024);
+ $result = $this->parseResult($line);
+ if ($result != self::ERROR_OK) {
+ $this->set_error($result, "Unble to authenticate user (AUTH): $line");
+ }
+ }
+ }
- // process result
- $result = $this->parseResult($line);
if ($result == self::ERROR_OK) {
return $this->fp;
}
- $this->error = "Authentication for $user failed (AUTH): $line";
-
return $result;
}
+ /**
+ * LOGIN Authentication
+ *
+ * @param string $user
+ * @param string $pass
+ *
+ * @return resource Connection resourse on success, error code on error
+ */
function login($user, $password)
{
list($code, $response) = $this->execute('LOGIN', array(
@@ -422,9 +473,6 @@ class rcube_imap_generic
return $this->fp;
}
- @fclose($this->fp);
- $this->fp = false;
-
return $code;
}
@@ -634,44 +682,48 @@ class rcube_imap_generic
}
}
- $orig_method = $auth_method;
+ $auth_methods = array();
+ $result = null;
+ // check for supported auth methods
if ($auth_method == 'CHECK') {
- // check for supported auth methods
if ($this->getCapability('AUTH=CRAM-MD5') || $this->getCapability('AUTH=CRAM_MD5')) {
- $auth_method = 'AUTH';
+ $auth_methods[] = 'AUTH';
}
- else {
- // default to plain text auth
- $auth_method = 'PLAIN';
+ if ($this->getCapability('AUTH=PLAIN')) {
+ $auth_methods[] = 'PLAIN';
+ }
+ // RFC 2595 (LOGINDISABLED) LOGIN disabled when connection is not secure
+ if (!$this->getCapability('LOGINDISABLED')) {
+ $auth_methods[] = 'LOGIN';
}
}
+ else {
+ $auth_methods[] = $auth_method;
+ }
- if ($auth_method == 'AUTH') {
- // do CRAM-MD5 authentication
- $this->putLine($this->next_tag() . " AUTHENTICATE CRAM-MD5");
- $line = trim($this->readLine(1024));
-
- if ($line[0] == '+') {
- // got a challenge string, try CRAM-MD5
- $result = $this->authenticate($user, $password, substr($line,2));
-
- // stop if server sent BYE response
- if ($result == self::ERROR_BYE) {
- return false;
- }
- }
+ // Authenticate
+ foreach ($auth_methods as $method) {
+ switch ($method) {
+ case 'AUTH':
+ $result = $this->authenticate($user, $password, 'CRAM-MD5');
+ break;
+ case 'PLAIN':
+ $result = $this->authenticate($user, $password, 'PLAIN');
+ break;
+ case 'LOGIN':
+ $result = $this->login($user, $password);
+ break;
+ default:
+ $this->set_error(self::ERROR_BAD, "Configuration error. Unknown auth method: $method");
+ }
- if (!is_resource($result) && $orig_method == 'CHECK') {
- $auth_method = 'PLAIN';
+ if (is_resource($result)) {
+ break;
}
}
- if ($auth_method == 'PLAIN') {
- // do plain text auth
- $result = $this->login($user, $password);
- }
-
+ // Connected and authenticated
if (is_resource($result)) {
if ($this->prefs['force_caps']) {
$this->clearCapability();
@@ -680,9 +732,13 @@ class rcube_imap_generic
$this->logged = true;
return true;
- } else {
- return false;
- }
+ }
+
+ // Close connection
+ @fclose($this->fp);
+ $this->fp = false;
+
+ return false;
}
function connected()