public function check_password($username, $password)
 {
     $ticket = new KRB5CCache();
     try {
         $ticket->initPassword(strtolower($username) . "@" . $this->realm, $password);
     } catch (Exception $e) {
         if ($this->debug) {
             echo "{$e}\n";
         }
         return false;
     }
     return true;
 }
 /**
  * DIGEST-MD5/CRAM-MD5/PLAIN Authentication
  *
  * @param string $user Username
  * @param string $pass Password
  * @param string $type Authentication type (PLAIN/CRAM-MD5/DIGEST-MD5)
  *
  * @return resource Connection resourse on success, error code on error
  */
 protected function authenticate($user, $pass, $type = 'PLAIN')
 {
     if ($type == 'CRAM-MD5' || $type == 'DIGEST-MD5') {
         if ($type == 'DIGEST-MD5' && !class_exists('Auth_SASL')) {
             $this->setError(self::ERROR_BYE, "The Auth_SASL package is required for DIGEST-MD5 authentication");
             return self::ERROR_BAD;
         }
         $this->putLine($this->nextTag() . " AUTHENTICATE {$type}");
         $line = trim($this->readReply());
         if ($line[0] == '+') {
             $challenge = substr($line, 2);
         } else {
             return $this->parseResult($line);
         }
         if ($type == 'CRAM-MD5') {
             // RFC2195: CRAM-MD5
             $ipad = '';
             $opad = '';
             // 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);
             }
             // generate hash
             $hash = md5($this->_xor($pass, $opad) . pack("H*", md5($this->_xor($pass, $ipad) . base64_decode($challenge))));
             $reply = base64_encode($user . ' ' . $hash);
             // send result
             $this->putLine($reply, true, true);
         } else {
             // RFC2831: DIGEST-MD5
             // proxy authorization
             if (!empty($this->prefs['auth_cid'])) {
                 $authc = $this->prefs['auth_cid'];
                 $pass = $this->prefs['auth_pw'];
             } else {
                 $authc = $user;
                 $user = '';
             }
             $auth_sasl = Auth_SASL::factory('digestmd5');
             $reply = base64_encode($auth_sasl->getResponse($authc, $pass, base64_decode($challenge), $this->host, 'imap', $user));
             // send result
             $this->putLine($reply, true, true);
             $line = trim($this->readReply());
             if ($line[0] != '+') {
                 return $this->parseResult($line);
             }
             // check response
             $challenge = substr($line, 2);
             $challenge = base64_decode($challenge);
             if (strpos($challenge, 'rspauth=') === false) {
                 $this->setError(self::ERROR_BAD, "Unexpected response from server to DIGEST-MD5 response");
                 return self::ERROR_BAD;
             }
             $this->putLine('');
         }
         $line = $this->readReply();
         $result = $this->parseResult($line);
     } else {
         if ($type == 'GSSAPI') {
             if (!extension_loaded('krb5')) {
                 $this->setError(self::ERROR_BYE, "The krb5 extension is required for GSSAPI authentication");
                 return self::ERROR_BAD;
             }
             if (empty($this->prefs['gssapi_cn'])) {
                 $this->setError(self::ERROR_BYE, "The gssapi_cn parameter is required for GSSAPI authentication");
                 return self::ERROR_BAD;
             }
             if (empty($this->prefs['gssapi_context'])) {
                 $this->setError(self::ERROR_BYE, "The gssapi_context parameter is required for GSSAPI authentication");
                 return self::ERROR_BAD;
             }
             putenv('KRB5CCNAME=' . $this->prefs['gssapi_cn']);
             try {
                 $ccache = new KRB5CCache();
                 $ccache->open($this->prefs['gssapi_cn']);
                 $gssapicontext = new GSSAPIContext();
                 $gssapicontext->acquireCredentials($ccache);
                 $token = '';
                 $success = $gssapicontext->initSecContext($this->prefs['gssapi_context'], null, null, null, $token);
                 $token = base64_encode($token);
             } catch (Exception $e) {
                 trigger_error($e->getMessage(), E_USER_WARNING);
                 $this->setError(self::ERROR_BYE, "GSSAPI authentication failed");
                 return self::ERROR_BAD;
             }
             $this->putLine($this->nextTag() . " AUTHENTICATE GSSAPI " . $token);
             $line = trim($this->readReply());
             if ($line[0] != '+') {
                 return $this->parseResult($line);
             }
             try {
                 $challenge = base64_decode(substr($line, 2));
                 $gssapicontext->unwrap($challenge, $challenge);
                 $gssapicontext->wrap($challenge, $challenge, true);
             } catch (Exception $e) {
                 trigger_error($e->getMessage(), E_USER_WARNING);
                 $this->setError(self::ERROR_BYE, "GSSAPI authentication failed");
                 return self::ERROR_BAD;
             }
             $this->putLine(base64_encode($challenge));
             $line = $this->readReply();
             $result = $this->parseResult($line);
         } else {
             // PLAIN
             // proxy authorization
             if (!empty($this->prefs['auth_cid'])) {
                 $authc = $this->prefs['auth_cid'];
                 $pass = $this->prefs['auth_pw'];
             } else {
                 $authc = $user;
                 $user = '';
             }
             $reply = base64_encode($user . chr(0) . $authc . chr(0) . $pass);
             // RFC 4959 (SASL-IR): save one round trip
             if ($this->getCapability('SASL-IR')) {
                 list($result, $line) = $this->execute("AUTHENTICATE PLAIN", array($reply), self::COMMAND_LASTLINE | self::COMMAND_CAPABILITY | self::COMMAND_ANONYMIZED);
             } else {
                 $this->putLine($this->nextTag() . " AUTHENTICATE PLAIN");
                 $line = trim($this->readReply());
                 if ($line[0] != '+') {
                     return $this->parseResult($line);
                 }
                 // send result, get reply and process it
                 $this->putLine($reply, true, true);
                 $line = $this->readReply();
                 $result = $this->parseResult($line);
             }
         }
     }
     if ($result == self::ERROR_OK) {
         // optional CAPABILITY response
         if ($line && preg_match('/\\[CAPABILITY ([^]]+)\\]/i', $line, $matches)) {
             $this->parseCapability($matches[1], true);
         }
         return $this->fp;
     } else {
         $this->setError($result, "AUTHENTICATE {$type}: {$line}");
     }
     return $result;
 }