On Wed, Jun 18, 2003 at 09:11:25AM +0200, Sebastian Hagedorn wrote: > Hmm, are those patches freely available? Smartsieve is also PHP-based and > only offers PLAIN, so I'd be interested if your patches would work there as > well.
Yes, they are. I posted it to the info-cyrus list way back when but here's a copy attached. This requires mhash to be compiled into PHP. -- Scott Russell <[EMAIL PROTECTED]> IBM Linux Technology Center, System Admin
--- sieve-php.lib.orig Thu Jan 31 19:48:40 2002 +++ sieve-php.lib Sun Sep 22 20:03:32 2002 @@ -489,6 +489,82 @@ return false; $this->loggedin=true; return true; + break; + + case "DIGEST-MD5": + // SASL DIGEST-MD5 support works with timsieved 1.1.0 + // follows rfc2831 for generating the $response to $challenge + // requires php mhash extension + fputs($this->fp, "AUTHENTICATE \"DIGEST-MD5\"\r\n"); + // $clen is length of server challenge, we ignore it. + $clen = fgets($this->fp, 1024); + // read for 2048, rfc2831 max length allowed + $challenge = fgets($this->fp, 2048); + // vars used when building $response_value and $response + $cnonce = base64_encode(bin2hex(mhash(MHASH_MD5, microtime()))); + $ncount = "00000001"; + $qop_value = "auth"; + $digest_uri_value = "sieve/$this->host"; + // decode the challenge string + $result = decode_challenge($challenge); + // verify server supports qop=auth + $qop = explode(",",$result['qop']); + if (!in_array($qop_value, $qop)) { + // rfc2831: client MUST fail if no qop methods supported + return false; + } + // build the $response_value + $string_a1 = utf8_encode($this->user).":"; + $string_a1 .= utf8_encode($result['realm']).":"; + $string_a1 .= utf8_encode($this->pass); + $string_a1 = mhash(MHASH_MD5, $string_a1); + $A1 = $string_a1.":".$result['nonce'].":".$cnonce.":".utf8_encode($this->auth); + $A1 = bin2hex(mhash(MHASH_MD5, $A1)); + $A2 = bin2hex(mhash(MHASH_MD5, "AUTHENTICATE:$digest_uri_value")); + $string_response = $result['nonce'].":".$ncount.":".$cnonce.":".$qop_value; + $response_value = bin2hex(mhash(MHASH_MD5, $A1.":".$string_response.":".$A2)); + // build the challenge $response + $reply = "charset=utf-8,username=\"".$this->user."\",realm=\"".$result['realm']."\","; + $reply .= "nonce=\"".$result['nonce']."\",nc=$ncount,cnonce=\"$cnonce\","; + $reply .= "digest-uri=\"$digest_uri_value\",response=$response_value,"; + $reply .= "qop=$qop_value,authzid=\"".utf8_encode($this->auth)."\""; + $response = base64_encode($reply); + fputs($this->fp, "\"$response\"\r\n"); + + $this->line = fgets($this->fp, 1024); + while(sieve::status($this->line) == F_DATA) + $this->line = fgets($this->fp,1024); + + if(sieve::status($this->line) == F_NO) + return false; + $this->loggedin = TRUE; + return TRUE; + break; + + case "CRAM-MD5": + // SASL CRAM-MD5 support works with timsieved 1.1.0 + // follows rfc2195 for generating the $response to $challenge + // CRAM-MD5 does not support proxy of $auth by $user + // requires php mhash extension + fputs($this->fp, "AUTHENTICATE \"CRAM-MD5\"\r\n"); + // $clen is the length of the challenge line the server gives us + $clen = fgets($this->fp, 1024); + // read for 1024, should be long enough? + $challenge = fgets($this->fp, 1024); + // build a response to the challenge + $hash = bin2hex(mhash(MHASH_MD5, base64_decode($challenge), $this->pass)); + $response = base64_encode($this->user." ".$hash); + // respond to the challenge string + fputs($this->fp, "\"$response\"\r\n"); + + $this->line = fgets($this->fp, 1024); + while(sieve::status($this->line) == F_DATA) + $this->line = fgets($this->fp,1024); + + if(sieve::status($this->line) == F_NO) + return false; + $this->loggedin = TRUE; + return TRUE; break; default: @@ -503,6 +579,18 @@ } - +function decode_challenge ($input) { + // FIXME: this function is a hack to decode the challenge + // from timsieved 1.1.0. It may not work with other versions + // and most certainly won't work with other DIGEST-MD5 implentations + $input = base64_decode($input); + preg_match("/nonce=\"(.*)\"/U",$input, $matches); + $resp['nonce'] = $matches[1]; + preg_match("/realm=\"(.*)\"/U",$input, $matches); + $resp['realm'] = $matches[1]; + preg_match("/qop=\"(.*)\"/U",$input, $matches); + $resp['qop'] = $matches[1]; + return $resp; +} ?>
pgp00000.pgp
Description: PGP signature