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;
+}
 
 ?>

Attachment: pgp00000.pgp
Description: PGP signature

Reply via email to