Changeset 1327 for trunk


Ignore:
Timestamp:
06/22/12 14:01:51 (7 years ago)
Author:
gogo
Message:

#1595 - suhosin caused breakage of MootoolsFileManager?, typical error session expired due to suhosin having killed the session, this works around it.

Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/contrib/php-xinha.php

    r1321 r1327  
    11<?php 
     2  /** Pass data to a Xinha plugin backend without using PHP session handling functions. 
     3   * 
     4   *  Why?  Suhosin, that's why.  Suhosin has an option to encrypt sessions, which sounds 
     5   *  great, but is a bad idea for us, particularly when it includes the user_agent in the 
     6   *  encryption key, because any flash file doing a GET/POST has a different user agent to  
     7   *  the browser itself causing the session to not decrypt, and worse, causes the session 
     8   *  to reset even though it doesn't decrypt. 
     9   * 
     10   *  As a result, this method (in combination with the above) uses a simple file-storage 
     11   *  mechanism to record the necessary secret data instead of the php sessions. 
     12   * 
     13   *  Caution, if you are load balancing, then all the servers in that cluster will need  
     14   *  to be able to get to the tmp_path, or you tie each user to a certain server. 
     15   * 
     16   * @param array   The data to pass 
     17   * @param string  The path to a temporary folder where we can create some folders and files 
     18   *                  if not supplied, it will be sys_get_temp_dir() 
     19   * @param bool    If you want the data returned as a PHP structure instead of echo'd as javascript 
     20   */ 
     21    
     22  function xinha_pass_to_php_backend_without_php_sessions($data, $tmp_path = NULL, $ReturnPHP = FALSE) 
     23  {    
     24    $bk = array();         
     25    $bk['data']                     = serialize($data);                    
     26    $key = xinha_get_backend_hash_key($bk, $tmp_path);     
     27     
     28    $bk['hash']         =  
     29      function_exists('sha1') ?  
     30        sha1($key . $bk['data'])  
     31      : md5($key . $bk['data']); 
     32       
     33       
     34    // The data will be passed via a postback to the  
     35    // backend, we want to make sure these are going to come 
     36    // out from the PHP as an array like $bk above, so  
     37    // we need to adjust the keys. 
     38    $backend_data = array(); 
     39    foreach($bk as $k => $v) 
     40    { 
     41      $backend_data["backend_data[$k]"] = $v;  
     42    } 
     43     
     44    if($ReturnPHP) 
     45    {       
     46      return array('backend_data' => $backend_data);       
     47    } 
     48    else 
     49    {       
     50      echo 'backend_data = ' . xinha_to_js($backend_data) . "; \n";   
     51    }                 
     52  }   
     53    
     54  /** The completment of xinha_pass_to_php_backend_without_php_sessions(), read the backend 
     55   *  data which was passed and return it. 
     56   * 
     57   *  @return array|NULL As was supplied as $data to xinha_pass_to_php_backend_without_php_sessions() 
     58   *         
     59   */ 
     60    
     61  function xinha_read_passed_data_without_php_sessions() 
     62  { 
     63    $bk = $_REQUEST['backend_data']; 
     64    $key  = xinha_get_backend_hash_key($bk);    
     65    $hash = function_exists('sha1') ?  
     66        sha1($key . $bk['data'])  
     67      : md5($key . $bk['data']); 
     68       
     69    if(!strlen($hash) || ($hash !== $bk['hash'])) 
     70    { 
     71      throw new Exception("Security error, hash mis-match."); 
     72    } 
     73     
     74    return unserialize($bk['data']); 
     75  } 
     76   
     77  /**  
     78   * For a given backend data, return a key (salt) to use when hashing. 
     79   * 
     80   * @param  array  array('data' =>  'serialized data' ) 
     81   * @param  string Path to store temporary files which contain the keys, must be writable 
     82   *                 defaults to sys_get_temp_dir() 
     83   * 
     84   * @modifies $bk will be modified to add ['tmp_path'] and ['xinha-backend-key-id'] 
     85   *                 the former is added only if it does not exist and will be equivalent to 
     86   *                 the supplied $tmp_path 
     87   * 
     88   *                 the latter is added only if it does not exist, and is generated as a unique  
     89   *                 identifier of arbitrary length 
     90   * 
     91   * @access private 
     92   */ 
     93    
     94  function xinha_get_backend_hash_key(&$bk, $tmp_path = NULL) 
     95  {   
     96    // The key itself will be written into a file inside the "tmp_path",  
     97    if(!isset($bk['tmp_path'])) 
     98    { 
     99      if(!isset($tmp_path)) 
     100      { 
     101        $tmp_path = sys_get_temp_dir(); 
     102      } 
     103       
     104      $bk['tmp_path'] = $tmp_path; 
     105    } 
     106             
     107    // The file will be formed from the "key id" 
     108    if(isset($bk['xinha-backend-key-id'])) 
     109    { 
     110      $key_id = $bk['xinha-backend-key-id']; 
     111    } 
     112    elseif(isset($_COOKIE['xinha-backend-key-id'])) 
     113    {       
     114      $key_id = $_COOKIE['xinha-backend-key-id'];       
     115      $bk['xinha-backend-key-id'] = $key_id; 
     116    } 
     117    else 
     118    { 
     119      $key_id = uniqid('xinha-', TRUE); 
     120      @setcookie('xinha-backend-key-id', $key_id, 0, '/'); // Not the end of the world if this fails       
     121      $bk['xinha-backend-key-id'] = $key_id; 
     122    } 
     123             
     124    // We don't trust the key-id itself to not be some naughty construct, so 
     125    // the filename is md5'd, we chunk_split it to ensure that we don't go using 
     126    // too many inodes in a single folder.  We create that split path in a sub folder 
     127    // of the tmp_path so that multiple Xinha installs on the same server don't trample 
     128    // each other.  So the final result is... 
     129    // [tmp_path]/xinha-[install-path-md5-hash]/a1/a1/a1/a1/a1/a1/a1...../xinha_key 
     130    $KeyFile = realpath($bk['tmp_path']) . "/xinha-".md5(__FILE__) . "/" . chunk_split(md5($key_id),2, "/") . "xinha_key"; 
     131     
     132    if(!file_exists($KeyFile)) 
     133    { 
     134      // Without a keyfile, this could mean 2 things 
     135      //  1. We have been asked to create a keyfile, in this case, $tmp_path MUST be set (by now, see default above) 
     136      //  2. The keyfile has disappeared 
     137       
     138      // Case 2 
     139      if(!isset($tmp_path)) 
     140      { 
     141        throw new Exception("Unable to locate security key, reload the page and try again."); 
     142      } 
     143       
     144      // Case 1, because we named the keyfile from the tmp_path in $bk, double check somebody isn't fiddling with that 
     145      if($tmp_path !== $bk['tmp_path']) 
     146      { 
     147        throw new Exception("Attempt to write new key with invalid tmp_path"); 
     148      } 
     149       
     150      // If we can't write to the path, then we are no good 
     151      if(!is_dir($bk['tmp_path']) || !is_writable($bk['tmp_path'])) 
     152      { 
     153        throw new Exception( "Xinha is unable to write to {$bk['tmp_path']} while trying to pass to backend without sessions." );      
     154      } 
     155         
     156      // Finally looks to be OK, so write a new key into the keyfile 
     157      mkdir(dirname($KeyFile), 0700, TRUE); 
     158      file_put_contents($KeyFile, uniqid('Key_')); 
     159       
     160      // Roll the dice to see if we should garbage collect 
     161      if(rand(0,100) >= 90)  
     162      { 
     163        xinha_garbage_collect(realpath($bk['tmp_path']) . "/xinha-".md5(__FILE__)); 
     164      } 
     165    } 
     166    else 
     167    { 
     168      // We have a keyfile, touch it to make sure the server knows it's been used recently 
     169      touch($KeyFile); 
     170    } 
     171         
     172    return file_get_contents($KeyFile); 
     173  } 
     174   
     175   
     176  /**  
     177   * Garbage collect old key files which are created by xinha_pass_to_php_backend_without_php_sessions() 
     178   * 
     179   * Key files which are 12 hours old or more are culled. 
     180   * 
     181   * This method is called randomly by xinha_get_backend_hash_key when creating a new key (10% of the time) 
     182   * 
     183   * @param  string path to start garbage collection on 
     184   * @param  string the maximum number of files to check (limits time taken) 
     185   * @return bool true = folder now empty, false = folder still contains data 
     186   * @access private  
     187   */ 
     188    
     189  function xinha_garbage_collect($path, &$maxcount = 100) 
     190  { 
     191    $d = opendir($path); 
     192    $empty = true; 
     193    while($f = readdir($d)) 
     194    { 
     195      // If this is the key file, check it's age, unlink and return true (dir empty) if older than 12 hours 
     196      // otherwise, return false (dir not empty) 
     197      if($f === 'xinha_key') 
     198      { 
     199        $maxcount--; 
     200         
     201        if(@filemtime($path . '/' . $f) < (time() - 60*60*12)) 
     202        {           
     203          if(@unlink($path . '/' . $f)) 
     204          { 
     205            return true; 
     206          } 
     207        } 
     208         
     209        return false; 
     210      } 
     211       
     212      // If this is a chunk directory recurse, if the recursion return false (not empty) 
     213      //  or it returns true but we can't delete for some reason, then set empty to false 
     214      elseif(preg_match('/^[0-9a-f]{2,2}$/', $f)) 
     215      { 
     216        if($maxcount <= 0) 
     217        {  
     218          // If we have already checked our maximum, don't do any more 
     219          $empty = false; 
     220        } 
     221        elseif(!xinha_garbage_collect($path . '/' . $f, $maxcount) || !rmdir($f)) 
     222        { 
     223          $empty = false; 
     224        } 
     225      } 
     226    } 
     227    closedir($d); 
     228         
     229    return $maxcount ? $empty : false; 
     230  } 
    2231  /** Write the appropriate xinha_config directives to pass data to a PHP (Plugin) backend file. 
    3232   * 
     
    26255  function xinha_pass_to_php_backend($Data, $KeyLocation = 'Xinha:BackendKey', $ReturnPHP = FALSE) 
    27256  { 
     257    // A non default KeyLocation which is an existing directory is treated as 
     258    // a request to not use sessions 
     259    if($KeyLocation != 'Xinha:BackendKey' && file_exists($KeyLocation) && is_dir($KeyLocation)) 
     260    { 
     261      return xinha_pass_to_php_backend_without_php_sessions($Data, $KeyLocation, $ReturnPHP); 
     262    } 
     263   
     264    // If we are using session based key passing, then make sure that suhosin isn't  
     265    // going to screw things up, fall back to no-sessions version 
     266    if(@ini_get('suhosin.session.cryptua')) 
     267    {       
     268      if($KeyLocation == 'Xinha:BackendKey') 
     269      { 
     270        // Really should throw up a warning here, because the file-based key storage might 
     271        // not be suitable out of the box for cluster type environments 
     272        return xinha_pass_to_php_backend_without_php_sessions($Data, NULL, $ReturnPHP);       
     273      } 
     274      else 
     275      { 
     276        throw new Exception("Use of the standard xinha_pass_to_php_backend() is not possible because this server uses suhosin.session.cryptua.  Use xinha_pass_to_php_backend_without_php_sessions() instead, or disable suhosin.session.cryptua."); 
     277      } 
     278    }  
    28279    
    29280    $bk = array(); 
     
    146397  function xinha_read_passed_data($KeyLocation = 'Xinha:BackendKey') 
    147398  { 
     399   if(isset($_REQUEST['backend_data']['xinha-backend-key-id'])) 
     400   { 
     401      // This is a without sessions passing,  
     402      return xinha_read_passed_data_without_php_sessions(); 
     403   } 
    148404   if(isset($_REQUEST['backend_data']) && is_array($_REQUEST['backend_data'])) 
    149405   { 
  • trunk/plugins/MootoolsFileManager/MootoolsFileManager.ImageManager.js

    r1324 r1327  
    4040        f_alt    : image.alt, 
    4141        f_border : image.style.borderWidth ? image.style.borderWidth : image.border, 
    42         f_align  : image.hasAttribute('align') ? image.align : null, 
     42        f_align  : Xinha.hasAttribute(image, 'align') ? image.align : null, 
    4343        f_padding: image.style.padding, 
    4444        f_margin : image.style.margin, 
    45         f_width  :  image.hasAttribute('width') ? image.width : null, 
    46         f_height  : image.hasAttribute('height') ? image.height : null, 
     45        f_width  :  Xinha.hasAttribute(image, 'width') ? image.width : null, 
     46        f_height  : Xinha.hasAttribute(image, 'height') ? image.height : null, 
    4747        f_backgroundColor: image.style.backgroundColor, 
    4848        f_borderColor: image.style.borderColor, 
  • trunk/plugins/MootoolsFileManager/MootoolsFileManager.js

    r1324 r1327  
    5656  if(typeof __MFM_USE_FLASH__ == 'undefined') 
    5757  { 
    58     __MFM_USE_FLASH__ = true; 
     58    __MFM_USE_FLASH__ = Browser.Plugins.Flash.version ? true : false; 
    5959  } 
    6060   
  • trunk/plugins/MootoolsFileManager/backend.php

    r1324 r1327  
    7575} 
    7676 
     77define('I_KNOW_ABOUT_SUHOSIN', TRUE); // /contrib/xinha-php.js does it's best to avoid this problem for us 
    7778require_once('config.php'); 
    7879 
  • trunk/plugins/MootoolsFileManager/config.php

    r1324 r1327  
    191191  $IMConfig = array_merge($IMConfig, $passed_data); 
    192192} 
    193 @session_write_close(); // Close session now so we don't lock. 
    194193 
    195194// Back Compat, Some of our config options have been renamed,  
  • trunk/plugins/MootoolsFileManager/mootools-filemanager/Assets/Connector/FileManager.php

    r1324 r1327  
    525525} 
    526526 
     527if(!defined("I_KNOW_ABOUT_SUHOSIN") && ini_get('suhosin.session.cryptua')) 
     528{ 
     529  header('HTTP/1.0 500 Developer must read https://github.com/sleemanj/mootools-filemanager/wiki/suhosin', true, 500); // Internal server error 
     530  throw Exception('suhosin.session.cryptua: https://github.com/sleemanj/mootools-filemanager/wiki/suhosin" }');   // this exception will most probably not be caught; that's our intent!   
     531  exit; 
     532} 
    527533//------------------------------------------------------------------------------------------------------------- 
    528534 
  • trunk/plugins/MootoolsFileManager/mootools-filemanager/Source/FileManager.js

    r1324 r1327  
    18051805        revert_drag_n_drop: function(el) { 
    18061806                el.fade(1).removeClass('drag').removeClass('move').setStyles({ 
    1807                         'z-index': 'auto', 
     1807                //      'z-index': 'auto', 
    18081808                        position: 'relative', 
    18091809                        width: 'auto', 
     
    18111811                        top: 0 
    18121812                }).inject(el.retrieve('parent')); 
     1813    try{ el.setStyle('z-index', 'auto'); } catch(e) { el.setStyle('z-index', ''); } // IE<8 Complains about 'auto' for z-index 
    18131814                // also dial down the opacity of the icons within this row (download, rename, delete): 
    18141815                var icons = el.getElements('img.browser-icon'); 
     
    32733274                var el = new Element('div', { 
    32743275                        'class': 'filemanager-button filemanager-' + name, 
    3275                         text: this.language[name], 
     3276                        text: this.language[name] 
    32763277                }).inject(this.menu, 'top'); 
    32773278 
     
    37833784                                // HTML5 support: see    http://diveintohtml5.org/detect.html 
    37843785                        autofocus_el.setProperty('autofocus', 'autofocus'); 
    3785       autofocus_el.focus(); 
     3786      try{autofocus_el.focus();}catch(e) { /* IE<8 Failes */ } 
    37863787                } 
    37873788                this.el.center().fade(1).get('tween').chain((function() { 
     
    39463947                } 
    39473948                else { 
    3948                         this.el.setStyles({ 
     3949                        document.id(this.el).setStyles({ // IE7 thinks this.el is no longer a mootools object, ^shrug^ 
    39493950                                width: document.getScrollWidth(), 
    39503951                                height: document.getScrollHeight() 
Note: See TracChangeset for help on using the changeset viewer.