forked from extern/egroupware
* Sharing: fixed not accessible share, if user already logged into same EGroupware instance, also fixed WebDAV problems using a share URL
This commit is contained in:
parent
b4671c6460
commit
9c569a8c1e
93
api/src/Vfs/Dav/Directory.php
Normal file
93
api/src/Vfs/Dav/Directory.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API: VFS directory for use with SabreDAV
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <rb@stylitede>
|
||||
* @copyright (c) 2015 by Ralf Becker <rb@stylite.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Vfs\Dav;
|
||||
|
||||
use Sabre\DAV;
|
||||
use EGroupware\Api\Vfs;
|
||||
|
||||
/**
|
||||
* VFS directory for use with SabreDAV
|
||||
*/
|
||||
class Directory extends DAV\FS\Directory
|
||||
{
|
||||
/**
|
||||
* VFS path without prefix / vfs schema
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $vfs_path;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $path vfs path without prefix
|
||||
*/
|
||||
function __construct($path)
|
||||
{
|
||||
//error_log(__METHOD__."('$path')");
|
||||
$this->vfs_path = rtrim($path, '/');
|
||||
|
||||
parent::__construct(Vfs::PREFIX.$path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the node
|
||||
*
|
||||
* We override this method to remove url-decoding required by EGroupware VFS
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getName()
|
||||
{
|
||||
return Vfs::decodePath(parent::getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a specific child node, referenced by its name
|
||||
*
|
||||
* This method must throw DAV\Exception\NotFound if the node does not
|
||||
* exist.
|
||||
*
|
||||
* @param string $name
|
||||
* @throws DAV\Exception\NotFound
|
||||
* @return DAV\INode
|
||||
*/
|
||||
function getChild($name)
|
||||
{
|
||||
//error_log(__METHOD__."('$name') this->path=$this->path, this->vfs_path=$this->vfs_path");
|
||||
$path = $this->vfs_path . '/' . $name;
|
||||
$vfs_path = $this->vfs_path . '/' . Vfs::encodePathComponent($name);
|
||||
|
||||
if (!Vfs::file_exists($vfs_path)) throw new DAV\Exception\NotFound('File with name ' . $path . ' could not be located');
|
||||
|
||||
if (Vfs::is_dir($vfs_path))
|
||||
{
|
||||
return new Directory($vfs_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new File($vfs_path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns available diskspace information
|
||||
*
|
||||
* @return array [ available-space, free-space ]
|
||||
*/
|
||||
function getQuotaInfo()
|
||||
{
|
||||
return [ false, false ];
|
||||
}
|
||||
}
|
87
api/src/Vfs/Dav/File.php
Normal file
87
api/src/Vfs/Dav/File.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* EGroupware API: VFS file for use with SabreDAV
|
||||
*
|
||||
* @link http://www.egroupware.org
|
||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||
* @package api
|
||||
* @subpackage vfs
|
||||
* @author Ralf Becker <rb@stylitede>
|
||||
* @copyright (c) 2015 by Ralf Becker <rb@stylite.de>
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
namespace EGroupware\Api\Vfs\Dav;
|
||||
|
||||
use Sabre\DAV;
|
||||
use EGroupware\Api\Vfs;
|
||||
|
||||
|
||||
/**
|
||||
* VFS file for use with SabreDAV
|
||||
*/
|
||||
class File extends DAV\FS\File
|
||||
{
|
||||
/**
|
||||
* VFS path without prefix / vfs schema
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $vfs_path;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $path vfs path without prefix
|
||||
*/
|
||||
function __construct($path)
|
||||
{
|
||||
//error_log(__METHOD__."('$path')");
|
||||
$this->vfs_path = $path;
|
||||
|
||||
parent::__construct(Vfs::PREFIX.$path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the node
|
||||
*
|
||||
* We override this method to remove url-decoding required by EGroupware VFS
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function getName()
|
||||
{
|
||||
return Vfs::decodePath(parent::getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ETag for a file
|
||||
*
|
||||
* An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change.
|
||||
* The ETag is an arbitrary string, but MUST be surrounded by double-quotes.
|
||||
*
|
||||
* Return null if the ETag can not effectively be determined
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getETag()
|
||||
{
|
||||
if (($stat = Vfs::url_stat($this->vfs_path, STREAM_URL_STAT_QUIET)))
|
||||
{
|
||||
return '"'.$stat['ino'].':'.$stat['mtime'].':'.$stat['size'].'"';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime-type for a file
|
||||
*
|
||||
* If null is returned, we'll assume application/octet-stream
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function getContentType()
|
||||
{
|
||||
return Vfs::mime_content_type($this->vfs_path);
|
||||
}
|
||||
}
|
@ -562,7 +562,11 @@ class StreamWrapper implements Vfs\StreamWrapperIface
|
||||
|
||||
$path = Vfs::parse_url($url,PHP_URL_PATH);
|
||||
|
||||
if (!($stat = self::url_stat($path,STREAM_URL_STAT_LINK)) || !Vfs::check_access(Vfs::dirname($path),Vfs::WRITABLE, $parent_stat))
|
||||
// need to get parent stat from Sqlfs, not Vfs
|
||||
if (!isset($parent_stat)) $parent_stat = static::url_stat(Vfs::dirname($path), STREAM_URL_STAT_LINK);
|
||||
|
||||
if (!$parent_stat || !($stat = self::url_stat($path,STREAM_URL_STAT_LINK)) ||
|
||||
!Vfs::check_access(Vfs::dirname($path),Vfs::WRITABLE, $parent_stat))
|
||||
{
|
||||
self::_remove_password($url);
|
||||
if (self::LOG_LEVEL) error_log(__METHOD__."($url) permission denied!");
|
||||
@ -793,7 +797,7 @@ class StreamWrapper implements Vfs\StreamWrapperIface
|
||||
$parent = Vfs::dirname($path);
|
||||
|
||||
if (!($stat = self::url_stat($path,0)) || $stat['mime'] != self::DIR_MIME_TYPE ||
|
||||
!Vfs::check_access($parent,Vfs::WRITABLE))
|
||||
!Vfs::check_access($parent, Vfs::WRITABLE, static::url_stat($parent,0)))
|
||||
{
|
||||
self::_remove_password($url);
|
||||
$err_msg = __METHOD__."($url,$options) ".(!$stat ? 'not found!' :
|
||||
|
@ -132,10 +132,22 @@ class egw_sharing
|
||||
/**
|
||||
* Create sharing session
|
||||
*
|
||||
* @param boolean $keep_session =false false: create a new session, true: try mounting it into existing (already verified) session
|
||||
* Certain cases:
|
||||
* a) there is not session $keep_session === null
|
||||
* --> create new anon session with just filemanager rights and share as fstab
|
||||
* b) there is a session $keep_session === true
|
||||
* b1) current user is share owner (eg. checking the link)
|
||||
* --> mount share under token additionally
|
||||
* b2) current user not share owner
|
||||
* b2a) need/use filemanager UI (eg. directory)
|
||||
* --> destroy current session and continue with a)
|
||||
* b2b) single file or WebDAV
|
||||
* --> modify EGroupware enviroment for that request only, no change in session
|
||||
*
|
||||
* @param boolean $keep_session =null null: create a new session, true: try mounting it into existing (already verified) session
|
||||
* @return string with sessionid, does NOT return if no session created
|
||||
*/
|
||||
public static function create_session($keep_session=false)
|
||||
public static function create_session($keep_session=null)
|
||||
{
|
||||
self::$db = $GLOBALS['egw']->db;
|
||||
|
||||
@ -197,39 +209,14 @@ class egw_sharing
|
||||
{
|
||||
$share['share_root'] = '/'.$share['share_token'];
|
||||
|
||||
// if current user is not the share owner, we need to give him access to mounted share
|
||||
// if current user is not the share owner, we cant just mount share
|
||||
if (egw_vfs::$user != $share['share_owner'])
|
||||
{
|
||||
// check if sharing user has owner rights for shared path
|
||||
egw_vfs::$user = $share['share_owner'];
|
||||
egw_vfs::clearstatcache();
|
||||
if (egw_vfs::has_owner_rights($share['share_path']))
|
||||
{
|
||||
$rights = $share['share_writable'] && egw_vfs::is_writable($share['share_path']) ? 7 : 5;
|
||||
egw_vfs::$user = $GLOBALS['egw']->session->account_id;
|
||||
egw_vfs::eacl($share['share_root'], $rights, egw_vfs::$user, true); // true = session-only, not permanent
|
||||
}
|
||||
// if not, we must not use an eacl, as it grants recursive rights!
|
||||
// (one could eg. create a writable share for / and use it to escalate his own rights)
|
||||
// --> create a new session with propper rights (loosing current session)
|
||||
else
|
||||
{
|
||||
$keep_session = false;
|
||||
}
|
||||
$keep_session = false;
|
||||
}
|
||||
}
|
||||
if (!$keep_session) // do NOT change to else, as we might have set $keep_session=false!
|
||||
{
|
||||
// create session without checking auth: create(..., false, false)
|
||||
if (!($sessionid = $GLOBALS['egw']->session->create('anonymous', '', 'text', false, false)))
|
||||
{
|
||||
sleep(1);
|
||||
$status = '500 Internal Server Error';
|
||||
header("HTTP/1.1 $status");
|
||||
header("X-WebDAV-Status: $status", true);
|
||||
echo "Failed to create session: ".$GLOBALS['egw']->session->reason."\n";
|
||||
common::egw_exit();
|
||||
}
|
||||
// only allow filemanager app
|
||||
$GLOBALS['egw_info']['user']['apps'] = array(
|
||||
'filemanager' => $GLOBALS['egw_info']['apps']['filemanager']
|
||||
@ -266,8 +253,34 @@ class egw_sharing
|
||||
// store sharing object in egw object and therefore in session
|
||||
$GLOBALS['egw']->sharing = new egw_sharing($share);
|
||||
|
||||
// for an existing session we need to store modified egw and egw_info again in session
|
||||
if ($keep_session)
|
||||
// we have a session we want to keep, but share owner is different from current user and we need filemanager UI, or no session
|
||||
// --> create a new anon session
|
||||
if ($keep_session === false && $GLOBALS['egw']->sharing->use_filemanager() || is_null($keep_session))
|
||||
{
|
||||
// create session without checking auth: create(..., false, false)
|
||||
if (!($sessionid = $GLOBALS['egw']->session->create('anonymous', '', 'text', false, false)))
|
||||
{
|
||||
sleep(1);
|
||||
$status = '500 Internal Server Error';
|
||||
header("HTTP/1.1 $status");
|
||||
header("X-WebDAV-Status: $status", true);
|
||||
echo "Failed to create session: ".$GLOBALS['egw']->session->reason."\n";
|
||||
common::egw_exit();
|
||||
}
|
||||
// only allow filemanager app (gets overwritten by session::create)
|
||||
$GLOBALS['egw_info']['user']['apps'] = array(
|
||||
'filemanager' => $GLOBALS['egw_info']['apps']['filemanager']
|
||||
);
|
||||
}
|
||||
// we have a session we want to keep, but share owner is different from current user and we dont need filemanager UI
|
||||
// --> we dont need session and close it, to not modifiy it
|
||||
elseif ($keep_session === false)
|
||||
{
|
||||
$GLOBALS['egw']->session->commit_session();
|
||||
}
|
||||
|
||||
// update modified egw and egw_info again in session, if neccessary
|
||||
if ($keep_session || $sessionid)
|
||||
{
|
||||
$_SESSION[egw_session::EGW_INFO_CACHE] = $GLOBALS['egw_info'];
|
||||
unset($_SESSION[egw_session::EGW_INFO_CACHE]['flags']); // dont save the flags, they change on each request
|
||||
@ -278,6 +291,22 @@ class egw_sharing
|
||||
return $sessionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we use filemanager UI
|
||||
*
|
||||
* Only for directories, if browser supports it and filemanager is installed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function use_filemanager()
|
||||
{
|
||||
return !(!egw_vfs::is_dir($this->share['share_root']) || $_SERVER['REQUEST_METHOD'] != 'GET' ||
|
||||
// or unsupported browsers like ie < 10
|
||||
html::$user_agent == 'msie' && html::$ua_version < 10.0 ||
|
||||
// or if no filemanager installed (WebDAV has own autoindex)
|
||||
!file_exists(__DIR__.'/../../filemanager/inc/class.filemanager_ui.inc.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Server a request on a share specified in REQUEST_URI
|
||||
*/
|
||||
@ -291,11 +320,7 @@ class egw_sharing
|
||||
return $GLOBALS['egw']->sharing->ServeRequest();
|
||||
}
|
||||
// use pure WebDAV for everything but GET requests to directories
|
||||
if (!egw_vfs::is_dir($this->share['share_root']) || $_SERVER['REQUEST_METHOD'] != 'GET' ||
|
||||
// or unsupported browsers like ie < 10
|
||||
html::$user_agent == 'msie' && html::$ua_version < 10.0 ||
|
||||
// or if no filemanager installed (WebDAV has own autoindex)
|
||||
!file_exists(__DIR__.'/../../filemanager/inc/class.filemanager_ui.inc.php'))
|
||||
if (!$this->use_filemanager())
|
||||
{
|
||||
// send a content-disposition header, so browser knows how to name downloaded file
|
||||
if (!egw_vfs::is_dir($this->share['share_root']))
|
||||
|
@ -90,7 +90,9 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
{
|
||||
// recursive delete the directory
|
||||
try {
|
||||
$ret = egw_vfs::remove($options['path']) && !file_exists($path);
|
||||
$deleted = egw_vfs::remove($options['path']);
|
||||
$ret = !empty($deleted[$options['path']]);
|
||||
//error_log(__METHOD__."() egw_vfs::remove($options[path]) returned ".array2string($deleted)." --> ".array2string($ret));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
return '403 Forbidden: '.$e->getMessage();
|
||||
@ -129,7 +131,7 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
return "403 Forbidden";
|
||||
}
|
||||
|
||||
if ( file_exists($parent."/".$name) ) {
|
||||
if ( file_exists($path) ) {
|
||||
return "405 Method not allowed";
|
||||
}
|
||||
|
||||
@ -137,7 +139,7 @@ class vfs_webdav_server extends HTTP_WebDAV_Server_Filesystem
|
||||
return "415 Unsupported media type";
|
||||
}
|
||||
|
||||
$stat = mkdir($parent."/".$name, 0777);
|
||||
$stat = mkdir($path, 0777);
|
||||
if (!$stat) {
|
||||
return "403 Forbidden";
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user