[ Index ] |
|
Code source de Horde 3.1.3 |
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 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |