[ Index ]
 

Code source de Horde 3.1.3

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/Horde/IMAP/ACL/ -> rfc2086.php (source)

   1  <?php
   2  /**
   3   * Contains functions related to managing Access Control Lists on an IMAP
   4   * server using RFC 2086.
   5   *
   6   * Required parameters:<pre>
   7   *   'username'  The username for the server connection
   8   *   'password'  The password for the server connection
   9   *   'hostspec'  The hostname or IP address of the server.
  10   *               DEFAULT: 'localhost'
  11   *   'port'      The server port to which we will connect.
  12   *               IMAP is generally 143, while IMAP-SSL is generally 993.
  13   *               DEFAULT: 143
  14   *   'protocol'  The connection protocol (e.g. 'imap', 'pop3', 'nntp').
  15   *               Protocol is one of 'imap/notls' (or only 'imap' if you
  16   *               have a c-client version 2000c or older), 'imap/ssl', or
  17   *               'imap/ssl/novalidate-cert' (for a self-signed certificate).
  18   *               DEFAULT: 'imap'</pre>
  19   *
  20   * $Horde: framework/IMAP/IMAP/ACL/rfc2086.php,v 1.6.8.12 2006/07/26 19:34:45 chuck Exp $
  21   *
  22   * Copyright 2003-2006 Chris Hastie <imp@oak-wood.co.uk>
  23   *
  24   * See the enclosed file COPYING for license information (LGPL). If you did
  25   * not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  26   *
  27   * @author  Chris Hastie <imp@oak-wood.co.uk>
  28   * @since   Horde 3.0
  29   * @package Horde_IMAP
  30   */
  31  class IMAP_ACL_rfc2086 extends IMAP_ACL {
  32  
  33      /**
  34       * IMAP resource.
  35       *
  36       * @var resource
  37       */
  38      var $_imap;
  39  
  40      /**
  41       * List of server's capabilities, output of CAPABILITY command. Formated
  42       * as a hash
  43       * <code>
  44       * array(
  45       *     *capability* => 1
  46       * )
  47       * </code>
  48       *
  49       * @var array
  50       */
  51      var $_caps = array();
  52  
  53      /**
  54       * Constructor.
  55       *
  56       * @param array $params  Any additional parameters this driver may need.
  57       */
  58      function IMAP_ACL_rfc2086($params = array())
  59      {
  60          $this->_params = array_merge(array('hostspec' => 'localhost',
  61                                             'port' => 143,
  62                                             'protocol' => 'imap'),
  63                                       $params);
  64  
  65          $this->_caps = $this->_getCapability();
  66          if (is_a($this->_caps, 'PEAR_Error')) {
  67              $this->_error = $this->_caps;
  68              return;
  69          }
  70  
  71          if (substr($this->_params['protocol'], 0, 4) != 'imap') {
  72              /* No point in going any further if it's not an IMAP server. */
  73              $this->_error = PEAR::raiseError(_("Only IMAP servers support shared folders."));
  74              $this->_supported = false;
  75          } elseif (!isset($this->_caps['acl'])) {
  76              /* If we couldn't get the server's capability, we'll assume ACL is
  77                 not supported for now. */
  78              $this->_supported = false;
  79          } else {
  80              $this->_supported = true;
  81          }
  82  
  83          $this->_protected = array($this->_params['username']);
  84  
  85          $this->_rightsList = array(
  86               'l' => _("List - user can see the folder"),
  87               'r' => _("Read messages"),
  88               's' => _("Mark with Seen/Unseen flags"),
  89               'w' => _("Mark with other flags (e.g. Important/Answered)"),
  90               'i' => _("Insert messages"),
  91               'p' => _("Post to this folder (not enforced by IMAP)"),
  92               'c' => _("Create sub folders"),
  93               'd' => _("Delete and purge messages"),
  94               'a' => _("Administer - set permissions for other users")
  95          );
  96      }
  97  
  98      function _connect()
  99      {
 100          if (!$this->_imap) {
 101              $this->_imap = @imap_open(sprintf('{%s:%d/%s}',
 102                                                $this->_params['hostspec'],
 103                                                $this->_params['port'],
 104                                                $this->_params['protocol']),
 105                                        $this->_params['username'],
 106                                        $this->_params['password'],
 107                                        OP_HALFOPEN);
 108              if (!$this->_imap) {
 109                  $this->_imap = PEAR::raiseError(imap_last_error());
 110              }
 111          }
 112          return !is_a($this->_imap, 'PEAR_Error');
 113      }
 114  
 115      /**
 116       * Sets the ACL on an IMAP server.
 117       *
 118       * @param string $folder      The folder on which to edit the ACL.
 119       * @param string $share_user  The user to grant rights to.
 120       * @param array $acl          An array, the keys of which are the rights to
 121       *                            be granted (see RFC 2086).
 122       *
 123       * @return mixed  True on success, PEAR_Error on failure or if server
 124       *                doesn't support ACLs.
 125       */
 126      function createACL($folder, $share_user, $acl)
 127      {
 128          if (!$this->_connect()) {
 129              return $this->_imap;
 130          }
 131  
 132          $acl_str = '';
 133          if (!empty($acl)) {
 134              foreach ($acl as $key => $val) {
 135                  $acl_str .= $key;
 136              }
 137          }
 138  
 139          /* Can't call this as @imap_setacl() as suppressing errors leads to
 140             imap_errors() returning nothing. */
 141          $result = imap_setacl($this->_imap, $folder, $share_user, $acl_str);
 142  
 143          if (!$result) {
 144              $errors = imap_errors();
 145              if (is_array($errors)) {
 146                  $error_string = '';
 147                  foreach ($errors as $err) {
 148                      if ($err == 'ACL not available on this IMAP server') {
 149                          $err .= _("This IMAP server does not support sharing folders.");
 150                      }
 151                      $error_string .= $err;
 152                  }
 153                  return PEAR::raiseError($error_string);
 154              }
 155              return PEAR::raiseError(sprintf(_("Couldn't give user \"%s\" the following rights for the folder \"%s\": %s"), $share_user, $folder, $acl_str));
 156          }
 157  
 158          /* If PHP 5 isn't available wait a bit to ensure ACL propagates in
 159           * Cyrus Murder configuration. */
 160          if (!function_exists('imap_getacl')) {
 161              sleep(5);
 162          }
 163  
 164          return $result;
 165      }
 166  
 167      /**
 168       * Edits an ACL on an IMAP server.
 169       *
 170       * @param string $folder      The folder on which to edit the ACL.
 171       * @param string $share_user  The user to grant rights to.
 172       * @param array $acl          An array, the keys of which are the rights to
 173       *                            be granted (see RFC 2086).
 174       *
 175       * @return mixed  True on success, false on failure unless server doesn't
 176       *                support ACLs, returns 'no_support'
 177       */
 178      function editACL($folder, $share_user, $acl)
 179      {
 180          return $this->createACL($folder, $share_user, $acl);
 181      }
 182  
 183      /**
 184       * Attempts to get the result of a CAPABILITY command to the current IMAP
 185       * server.
 186       *
 187       * @access private
 188       *
 189       * @return array  An array containing the server's capabilities.
 190       */
 191      function _getCapability()
 192      {
 193          $capabilities = null;
 194          $server = $this->_params['hostspec'];
 195          $sub_proto = null;
 196  
 197          if (preg_match('|^[^/]+/ssl|', $this->_params['protocol'])) {
 198              $server = 'ssl://' . $server;
 199          }
 200  
 201          $imap = fsockopen($server, $this->_params['port'], $errno, $errstr, 30);
 202  
 203          if (!$imap) {
 204              return PEAR::raiseError(_("Could not retrieve server's capabilities") . ' - ' . ($errno ? _("Connection failed: ") . $errno . ' : ' . $errstr : _("Connection failed.")));
 205              return null;
 206          } else {
 207              $response = fgets($imap, 4096);
 208              if (preg_match('/^\*\s+OK/', $response)) {
 209                  fputs($imap, "x CAPABILITY\r\n");
 210                  $response = trim(fgets($imap, 1024));
 211                  if (preg_match('/^\*\s+CAPABILITY/', $response)) {
 212                      $response_array = explode(' ', $response);
 213                      foreach ($response_array as $var) {
 214                          if (strpos($var, '=') !== false) {
 215                              $var2 = explode('=', $var, 2);
 216                              $capabilities[String::lower($var2[0])][String::lower($var2[1])] = 1;
 217                          } else {
 218                              $capabilities[String::lower($var)] = 1;
 219                          }
 220                      }
 221  
 222                  } else {
 223                      fclose ($imap);
 224                      return PEAR::raiseError(_("Could not retrieve server's capabilities") . ' - ' . _("Unexpected response from server to: ") . '\'x CAPABILITY\' : ' . $response);
 225                  }
 226              } else {
 227                  fclose ($imap);
 228                  return PEAR::raiseError(_("Could not retrieve server's capabilities") . ' - ' . _("Unexpected response from server on connection: ") . $response);
 229              }
 230              fclose ($imap);
 231          }
 232  
 233          return $capabilities;
 234      }
 235  
 236      /**
 237       * Attempts to retrieve the existing ACL for a folder from the current
 238       * IMAP server.
 239       *
 240       * @param string folder  The folder to get the ACL for.
 241       *
 242       * @return array  A hash containing information on the ACL.
 243       * <pre>
 244       * Array (
 245       *   user => Array (
 246       *     right => 1
 247       *   )
 248       * )
 249       * </pre>
 250       */
 251      function getACL($folder)
 252      {
 253          if (isset($this->_caps['auth']['digest-md5'])) {
 254              return $this->_getACL($folder, 'digest-md5');
 255          } elseif (isset($this->_caps['auth']['cram-md5'])) {
 256              return $this->_getACL($folder, 'cram-md5');
 257          } else {
 258              return $this->_getACL($folder, 'login');
 259          }
 260      }
 261  
 262      /**
 263       * Attempts to retrieve the existing ACL for a folder from the current
 264       * IMAP server.
 265       *
 266       * NB: if Auth_SASL is not installed this function will send the users
 267       * password to the IMAP server as plain text!!
 268       *
 269       * @access private
 270       *
 271       * @param string folder    The folder to get the ACL for.
 272       * @param string authMech  The authorisation mechanism to use. One of
 273       *                         cram-md5, digest-md5 or login.
 274       *
 275       * @return array  A hash containing information on the ACL
 276       * <pre>
 277       * Array (
 278       *   user => Array (
 279       *     right => 1
 280       *   )
 281       * )
 282       * </pre>
 283       */
 284      function _getACL($folder, $authMech)
 285      {
 286          /* If imap_getacl() is available, use it */
 287          if (function_exists('imap_getacl')) {
 288              if (!$this->_connect()) {
 289                  return $this->_imap;
 290              }
 291  
 292              $result = @imap_getacl($this->_imap, $folder);
 293              if (!$result) {
 294                  $errors = imap_errors();
 295                  if (is_array($errors)) {
 296                      $error_string = '';
 297                      foreach ($errors as $err) {
 298                          if ($err == 'ACL not available on this IMAP server') {
 299                              $err .= _("This IMAP server does not support sharing folders.");
 300                          }
 301                          $error_string .= $err;
 302                      }
 303                      return PEAR::raiseError($error_string);
 304                  }
 305                  return PEAR::raiseError(sprintf(_("Could not retrieve ACL")));
 306              }
 307  
 308              $returnACL = array();
 309              foreach ($result as $user => $rights) {
 310                  for ($i = 0, $iMax = strlen($rights); $i < $iMax; $i++) {
 311                      $returnACL[$user][$rights[$i]] = 1;
 312                  }
 313              }
 314  
 315              return $returnACL;
 316          }
 317  
 318          global $notification;
 319  
 320          $have_sasl = false;
 321          $returnACL = array();
 322          $server = $this->_params['hostspec'];
 323          $sub_proto = null;
 324          $txid = 0;
 325  
 326          /* Silence warnings during check if Auth_SASL module is installed. */
 327          if (@include_once 'Auth/SASL.php') {
 328              $have_sasl = true;
 329          }
 330  
 331          $pass = $this->_params['password'];
 332  
 333          if (preg_match('|^[^/]+/ssl|', $this->_params['protocol'])) {
 334              $server = 'ssl://' . $server;
 335          }
 336  
 337          /* Quote the folder string if it contains non alpha-numeric
 338             characters. */
 339          if (preg_match('/\W/',$folder)) {
 340              $folder = '"' . $folder . '"';
 341          }
 342  
 343          $imap = fsockopen($server, $this->_params['port'], $errno, $errstr, 30);
 344  
 345          if (!$imap) {
 346              return PEAR::raiseError(_("Could not retrieve ACL")
 347                  . ' - ' . ($errno ? _("Connection failed: ") . $errno.' : ' . $errstr : _("Connection failed.")));
 348          } else {
 349              $response = fgets($imap, 4096);
 350              if (preg_match('/^\*\s+OK/', $response)) {
 351  
 352                  /* login using the preferred mechanism default to login if
 353                     Auth_SASL is not installed. */
 354                  if ($have_sasl && ($authMech == 'cram-md5')) {
 355                      $login = Auth_SASL::factory('crammd5');
 356  
 357                      fputs($imap, "$txid AUTHENTICATE CRAM-MD5\r\n");
 358                      $challenge = explode(' ', trim(fgets($imap, 1024)));
 359  
 360                      $response = $login->getResponse($_SESSION['imp']['user'], $pass, base64_decode($challenge[1]));
 361                      fputs($imap, base64_encode($response) . "\r\n");
 362  
 363                  } elseif($have_sasl && ($authMech == 'digest-md5')) {
 364                      $login = Auth_SASL::factory('digestmd5');
 365  
 366                      fputs($imap, "$txid AUTHENTICATE DIGEST-MD5\r\n");
 367                      $challenge = explode(' ', trim(fgets($imap, 1024)));
 368  
 369                      $response = $login->getResponse($_SESSION['imp']['user'], $pass, base64_decode($challenge[1]),
 370                          $_SESSION['imp']['server'], $_SESSION['imp']['base_protocol']);
 371  
 372                      fputs($imap, base64_encode($response) . "\r\n");
 373                      $response = explode(' ', trim(fgets($imap, 1024)));
 374                      $response = base64_decode($response[1]);
 375                      if (strpos($response, 'rspauth=') === false) {
 376                          fclose($imap);
 377                          return PEAR::raiseError(_("Could not retrieve ACL")
 378                              . ' - ' . _("Unexpected response from server to: ") . 'Digest-MD5 response', 'horde.warning');
 379                      }
 380                      fputs($imap, "\r\n");
 381  
 382                  } else {
 383                      if (preg_match('/\W/', $pass)) {
 384                          $pass = addslashes($pass);
 385                          $pass = '"' . $pass . '"';
 386                      }
 387                      fputs($imap, "$txid LOGIN " . $_SESSION['imp']['user'] . ' ' . $pass . "\r\n");
 388  
 389                  }
 390                  $response = trim(fgets($imap, 1024));
 391                  if (preg_match("/^$txid\sOK/", $response)) {
 392                      $txid++;
 393                      fputs($imap, "$txid GETACL " . $folder . "\r\n");
 394                      $response = trim(fgets($imap, 4096));
 395                      if (preg_match('/^\*\s+ACL\s+(.*)/i', $response, $matches)) {
 396                          $res_arr = $this->_atomise($matches[1]);
 397                          $res_folder = array_shift($res_arr);
 398                          $is_key = 1;
 399                          $key = null;
 400                          foreach ($res_arr as $var) {
 401                              if ($is_key) {
 402                                  $key = $var;
 403                                  $is_key = 0;
 404                              } else {
 405                                  $perms = preg_split('//', $var, -1, PREG_SPLIT_NO_EMPTY);
 406                                  foreach ($perms as $p_key => $p_var) {
 407                                      $returnACL[$key][$p_var] = 1;
 408                                  }
 409                                  $is_key = 1;
 410                              }
 411                          }
 412                      } else {
 413                          fclose($imap);
 414                          return PEAR::raiseError(_("Could not retrieve ACL")
 415                              . ' - ' . _("Unexpected response from server to: ") . "'$txid GETACL' : " .$response);
 416  
 417                      }
 418                  } else {
 419                      fclose($imap);
 420                      return PEAR::raiseError(_("Could not retrieve ACL")
 421                          . ' - ' . _("Unexpected response from server to: ") . 'login : ' . $response);
 422  
 423                  }
 424              } else {
 425                  fclose($imap);
 426                  return PEAR::raiseError(_("Could not retrieve ACL")
 427                      . ' - ' . _("Unexpected response from server on connection: ") . $response);
 428  
 429              }
 430              fclose($imap);
 431          }
 432  
 433          return $returnACL;
 434      }
 435  
 436      /**
 437       * Can a user edit the ACL for this folder?
 438       *
 439       * @param string $folder  The folder name.
 440       * @param string $user    A user name.
 441       *
 442       * @return boolean  True if $user has permission to edit the ACL on
 443       *                  $folder.
 444       */
 445      function canEdit($folder, $user)
 446      {
 447          /* We can't establish if the user is in a group with the 'a'
 448             privilege, so just return true and leave the decision to the
 449             server */
 450          return true;
 451      }
 452  
 453      /**
 454       * Crudely split a string into 'atoms'.
 455       *
 456       * @access private
 457       *
 458       * @param string $in  The string to split.
 459       *
 460       * @return array  An array of 'atoms'.
 461       */
 462      function _atomise($in)
 463      {
 464          $length = strlen($in);
 465          $qt = false;
 466          $idx = 0;
 467          $out = array();
 468  
 469          for ($i = 0; $i < $length; $i++) {
 470              $char = substr($in, $i, 1);
 471              if (($char == '"') && !$qt) {
 472                  $qt = true;
 473                  $idx++;
 474                  continue;
 475              } elseif (($char == ' ') && !$qt) {
 476                  $idx++;
 477              } elseif (($char == '"') && $qt) {
 478                  $qt = false;
 479                  $idx++;
 480              } else {
 481                  if (empty($out[$idx])) {
 482                      $out[$idx] = $char;
 483                  } else {
 484                      $out[$idx] .= $char;
 485                  }
 486              }
 487          }
 488  
 489          return $out;
 490      }
 491  
 492  }


Généré le : Sun Feb 25 18:01:28 2007 par Balluche grâce à PHPXref 0.7