mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-21 23:43:17 +01:00
fix filesystem stream-wrapper mounted inside other users home-directory would allow access
This commit is contained in:
parent
fd178ddd73
commit
7cc46f04e1
@ -182,9 +182,9 @@ class Base
|
|||||||
* @param string $fullurl full url returned by resolve_url
|
* @param string $fullurl full url returned by resolve_url
|
||||||
* @return string|NULL mount url or null if not found
|
* @return string|NULL mount url or null if not found
|
||||||
*/
|
*/
|
||||||
static function mount_url($fullurl)
|
static function mount_url($fullurl, &$mounted=null)
|
||||||
{
|
{
|
||||||
foreach(array_reverse(self::$fstab) as $url)
|
foreach(array_reverse(self::$fstab) as $mounted => $url)
|
||||||
{
|
{
|
||||||
list($url_no_query) = explode('?',$url);
|
list($url_no_query) = explode('?',$url);
|
||||||
if (substr($fullurl,0,1+strlen($url_no_query)) === $url_no_query.'/')
|
if (substr($fullurl,0,1+strlen($url_no_query)) === $url_no_query.'/')
|
||||||
@ -212,9 +212,10 @@ class Base
|
|||||||
* @param boolean $use_symlinkcache =true
|
* @param boolean $use_symlinkcache =true
|
||||||
* @param boolean $replace_user_pass_host =true replace $user,$pass,$host in url, default true, if false result is not cached
|
* @param boolean $replace_user_pass_host =true replace $user,$pass,$host in url, default true, if false result is not cached
|
||||||
* @param boolean $fix_url_query =false true append relativ path to url query parameter, default not
|
* @param boolean $fix_url_query =false true append relativ path to url query parameter, default not
|
||||||
|
* @param ?string &$mounted =null on return mount-point of resolved url, IF $_path is a path or vfs-url, other urls return NULL!
|
||||||
* @return string|boolean false if the url cant be resolved, should not happen if fstab has a root entry
|
* @return string|boolean false if the url cant be resolved, should not happen if fstab has a root entry
|
||||||
*/
|
*/
|
||||||
static function resolve_url($_path,$do_symlink=true,$use_symlinkcache=true,$replace_user_pass_host=true,$fix_url_query=false)
|
static function resolve_url($_path,$do_symlink=true,$use_symlinkcache=true,$replace_user_pass_host=true,$fix_url_query=false, &$mounted=null)
|
||||||
{
|
{
|
||||||
$path = self::get_path($_path);
|
$path = self::get_path($_path);
|
||||||
|
|
||||||
@ -222,7 +223,8 @@ class Base
|
|||||||
if (isset(self::$resolve_url_cache[$path]) && $replace_user_pass_host)
|
if (isset(self::$resolve_url_cache[$path]) && $replace_user_pass_host)
|
||||||
{
|
{
|
||||||
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$path') = '".self::$resolve_url_cache[$path]."' (from cache)");
|
if (self::LOG_LEVEL > 1) error_log(__METHOD__."('$path') = '".self::$resolve_url_cache[$path]."' (from cache)");
|
||||||
return self::$resolve_url_cache[$path];
|
$mounted = self::$resolve_url_cache[$path]['mounted'];
|
||||||
|
return self::$resolve_url_cache[$path]['url'];
|
||||||
}
|
}
|
||||||
// check if we can already resolve path (or a part of it) with a known symlinks
|
// check if we can already resolve path (or a part of it) with a known symlinks
|
||||||
if ($use_symlinkcache)
|
if ($use_symlinkcache)
|
||||||
@ -283,7 +285,7 @@ class Base
|
|||||||
}
|
}
|
||||||
$url = $replace;
|
$url = $replace;
|
||||||
}
|
}
|
||||||
if ($replace_user_pass_host) self::$resolve_url_cache[$path] = $url;
|
if ($replace_user_pass_host) self::$resolve_url_cache[$path] = ['url' => $url, 'mounted' => $mounted];
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
@ -695,12 +695,22 @@ class StreamWrapper extends Base implements StreamWrapperIface
|
|||||||
// we have no context, but $path is a URL with a valid user --> set it
|
// we have no context, but $path is a URL with a valid user --> set it
|
||||||
$this->check_set_context($path, true);
|
$this->check_set_context($path, true);
|
||||||
|
|
||||||
if (!($url = static::resolve_url($path,!($flags & STREAM_URL_STAT_LINK), $check_symlink_components)))
|
if (!($url = static::resolve_url($path, !($flags & STREAM_URL_STAT_LINK), $check_symlink_components, true, false, $mount_point)))
|
||||||
{
|
{
|
||||||
if (self::LOG_LEVEL > 0) error_log(__METHOD__."('$path',$flags) can NOT resolve path!");
|
if (self::LOG_LEVEL > 0) error_log(__METHOD__."('$path',$flags) can NOT resolve path!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we need to make sure the mount-point is readable eg. if something is mounted into an other users home-directory
|
||||||
|
if (!isset($mount_point)) Vfs::mount_url($url, $mount_point); // resolve_url only returns mount-point for pathes or vfs urls
|
||||||
|
if (!in_array($mount_point, ['/', '/apps', '/home']) && // they all are public readable
|
||||||
|
($class = self::scheme2class(Vfs::parse_url($url, PHP_URL_SCHEME))) &&
|
||||||
|
!is_a($class, Vfs\Sqlfs\StreamWrapper::class) && // decendents of SqlFS stream-wrapper always check traversal right to /
|
||||||
|
!$this->check_access(Vfs::dirname($mount_point), Vfs::READABLE))
|
||||||
|
{
|
||||||
|
return false; // mount-point is not reachable
|
||||||
|
}
|
||||||
|
|
||||||
if (empty(parse_url($url, PHP_URL_USER)))
|
if (empty(parse_url($url, PHP_URL_USER)))
|
||||||
{
|
{
|
||||||
$url = str_replace('://', '://'.Api\Accounts::id2name($this->context ? stream_context_get_options($this->context)[self::SCHEME]['user'] : Vfs::$user).'@', $url);
|
$url = str_replace('://', '://'.Api\Accounts::id2name($this->context ? stream_context_get_options($this->context)[self::SCHEME]['user'] : Vfs::$user).'@', $url);
|
||||||
|
@ -25,6 +25,11 @@ var_dump(Vfs::scandir('/home'));
|
|||||||
var_dump(Vfs::find('/home', ['maxdepth' => 1]));
|
var_dump(Vfs::find('/home', ['maxdepth' => 1]));
|
||||||
//var_dump(Vfs::scandir("/home/$sysop"));
|
//var_dump(Vfs::scandir("/home/$sysop"));
|
||||||
|
|
||||||
|
Vfs::$is_root = true;
|
||||||
|
Vfs::mount('filesystem://default/var/lib/egroupware', "/home/$other/something", false, false);
|
||||||
|
Vfs::$is_root = false;
|
||||||
|
var_dump(Vfs::stat("/home/$other/something"));
|
||||||
|
|
||||||
var_dump(file_put_contents("vfs://default/home/$sysop/test.txt", "Just a test ;)\n"));
|
var_dump(file_put_contents("vfs://default/home/$sysop/test.txt", "Just a test ;)\n"));
|
||||||
var_dump("Vfs::proppatch('/home/$sysop/test.txt', [['ns' => Vfs::DEFAULT_PROP_NAMESPACE, 'name' => 'test', 'val' => 'something']])=".array2string(Vfs::proppatch("/home/$sysop/test.txt", [['ns' => Vfs::DEFAULT_PROP_NAMESPACE, 'name' => 'test', 'val' => 'something']])),
|
var_dump("Vfs::proppatch('/home/$sysop/test.txt', [['ns' => Vfs::DEFAULT_PROP_NAMESPACE, 'name' => 'test', 'val' => 'something']])=".array2string(Vfs::proppatch("/home/$sysop/test.txt", [['ns' => Vfs::DEFAULT_PROP_NAMESPACE, 'name' => 'test', 'val' => 'something']])),
|
||||||
"Vfs::propfind('/home/$sysop/test.txt')=".json_encode(Vfs::propfind("/home/$sysop/test.txt"), JSON_UNESCAPED_SLASHES));
|
"Vfs::propfind('/home/$sysop/test.txt')=".json_encode(Vfs::propfind("/home/$sysop/test.txt"), JSON_UNESCAPED_SLASHES));
|
||||||
|
Loading…
Reference in New Issue
Block a user