home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Auth / SASL / DigestMD5.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  8.5 KB  |  199 lines

  1. <?php
  2. // +-----------------------------------------------------------------------+ 
  3. // | Copyright (c) 2002-2003 Richard Heyes                                 | 
  4. // | All rights reserved.                                                  | 
  5. // |                                                                       | 
  6. // | Redistribution and use in source and binary forms, with or without    | 
  7. // | modification, are permitted provided that the following conditions    | 
  8. // | are met:                                                              | 
  9. // |                                                                       | 
  10. // | o Redistributions of source code must retain the above copyright      | 
  11. // |   notice, this list of conditions and the following disclaimer.       | 
  12. // | o Redistributions in binary form must reproduce the above copyright   | 
  13. // |   notice, this list of conditions and the following disclaimer in the | 
  14. // |   documentation and/or other materials provided with the distribution.| 
  15. // | o The names of the authors may not be used to endorse or promote      | 
  16. // |   products derived from this software without specific prior written  | 
  17. // |   permission.                                                         | 
  18. // |                                                                       | 
  19. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   | 
  20. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     | 
  21. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
  22. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  | 
  23. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
  24. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      | 
  25. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
  26. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
  27. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   | 
  28. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
  29. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  | 
  30. // |                                                                       | 
  31. // +-----------------------------------------------------------------------+ 
  32. // | Author: Richard Heyes <richard@php.net>                               | 
  33. // +-----------------------------------------------------------------------+ 
  34. // 
  35. // $Id: DigestMD5.php,v 1.8 2006/03/22 05:20:11 amistry Exp $
  36.  
  37. /**
  38. * Implmentation of DIGEST-MD5 SASL mechanism
  39. *
  40. * @author  Richard Heyes <richard@php.net>
  41. * @access  public
  42. * @version 1.0
  43. * @package Auth_SASL
  44. */
  45.  
  46. require_once('Auth/SASL/Common.php');
  47.  
  48. class Auth_SASL_DigestMD5 extends Auth_SASL_Common
  49. {
  50.     /**
  51.     * Provides the (main) client response for DIGEST-MD5
  52.     * requires a few extra parameters than the other
  53.     * mechanisms, which are unavoidable.
  54.     * 
  55.     * @param  string $authcid   Authentication id (username)
  56.     * @param  string $pass      Password
  57.     * @param  string $challenge The digest challenge sent by the server
  58.     * @param  string $hostname  The hostname of the machine you're connecting to
  59.     * @param  string $service   The servicename (eg. imap, pop, acap etc)
  60.     * @param  string $authzid   Authorization id (username to proxy as)
  61.     * @return string            The digest response (NOT base64 encoded)
  62.     * @access public
  63.     */
  64.     function getResponse($authcid, $pass, $challenge, $hostname, $service, $authzid = '')
  65.     {
  66.         $challenge = $this->_parseChallenge($challenge);
  67.         $authzid_string = '';
  68.         if ($authzid != '') {
  69.             $authzid_string = ',authzid="' . $authzid . '"'; 
  70.         }
  71.  
  72.         if (!empty($challenge)) {
  73.             $cnonce         = $this->_getCnonce();
  74.             $digest_uri     = sprintf('%s/%s', $service, $hostname);
  75.             $response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid);
  76.  
  77.             if ($challenge['realm']) {
  78.                 return sprintf('username="%s",realm="%s"' . $authzid_string  .
  79. ',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
  80.             } else {
  81.                 return sprintf('username="%s"' . $authzid_string  . ',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
  82.             }
  83.         } else {
  84.             return PEAR::raiseError('Invalid digest challenge');
  85.         }
  86.     }
  87.     
  88.     /**
  89.     * Parses and verifies the digest challenge*
  90.     *
  91.     * @param  string $challenge The digest challenge
  92.     * @return array             The parsed challenge as an assoc
  93.     *                           array in the form "directive => value".
  94.     * @access private
  95.     */
  96.     function _parseChallenge($challenge)
  97.     {
  98.         $tokens = array();
  99.         while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) {
  100.  
  101.             // Ignore these as per rfc2831
  102.             if ($matches[1] == 'opaque' OR $matches[1] == 'domain') {
  103.                 $challenge = substr($challenge, strlen($matches[0]) + 1);
  104.                 continue;
  105.             }
  106.  
  107.             // Allowed multiple "realm" and "auth-param"
  108.             if (!empty($tokens[$matches[1]]) AND ($matches[1] == 'realm' OR $matches[1] == 'auth-param')) {
  109.                 if (is_array($tokens[$matches[1]])) {
  110.                     $tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
  111.                 } else {
  112.                     $tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
  113.                 }
  114.  
  115.             // Any other multiple instance = failure
  116.             } elseif (!empty($tokens[$matches[1]])) {
  117.                 $tokens = array();
  118.                 break;
  119.  
  120.             } else {
  121.                 $tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
  122.             }
  123.  
  124.             // Remove the just parsed directive from the challenge
  125.             $challenge = substr($challenge, strlen($matches[0]) + 1);
  126.         }
  127.  
  128.         /**
  129.         * Defaults and required directives
  130.         */
  131.         // Realm
  132.         if (empty($tokens['realm'])) {
  133.             $tokens['realm'] = "";
  134.         }
  135.  
  136.         // Maxbuf
  137.         if (empty($tokens['maxbuf'])) {
  138.             $tokens['maxbuf'] = 65536;
  139.         }
  140.  
  141.         // Required: nonce, algorithm
  142.         if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) {
  143.             return array();
  144.         }
  145.  
  146.         return $tokens;
  147.     }
  148.  
  149.     /**
  150.     * Creates the response= part of the digest response
  151.     *
  152.     * @param  string $authcid    Authentication id (username)
  153.     * @param  string $pass       Password
  154.     * @param  string $realm      Realm as provided by the server
  155.     * @param  string $nonce      Nonce as provided by the server
  156.     * @param  string $cnonce     Client nonce
  157.     * @param  string $digest_uri The digest-uri= value part of the response
  158.     * @param  string $authzid    Authorization id
  159.     * @return string             The response= part of the digest response
  160.     * @access private
  161.     */    
  162.     function _getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '')
  163.     {
  164.         if ($authzid == '') {
  165.             $A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce);
  166.         } else {
  167.             $A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid);
  168.         }
  169.         $A2 = 'AUTHENTICATE:' . $digest_uri;
  170.         return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2)));
  171.     }
  172.  
  173.     /**
  174.     * Creates the client nonce for the response
  175.     *
  176.     * @return string  The cnonce value
  177.     * @access private
  178.     */
  179.     function _getCnonce()
  180.     {
  181.         if (file_exists('/dev/urandom') && $fd = @fopen('/dev/urandom', 'r')) {
  182.             return base64_encode(fread($fd, 32));
  183.  
  184.         } elseif (file_exists('/dev/random') && $fd = @fopen('/dev/random', 'r')) {
  185.             return base64_encode(fread($fd, 32));
  186.  
  187.         } else {
  188.             $str = '';
  189.             mt_srand((double)microtime()*10000000);
  190.             for ($i=0; $i<32; $i++) {
  191.                 $str .= chr(mt_rand(0, 255));
  192.             }
  193.             
  194.             return base64_encode($str);
  195.         }
  196.     }
  197. }
  198. ?>
  199.