By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
448,571 Members | 1,209 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 448,571 IT Pros & Developers. It's quick & easy.

file:// streams: writing a custom wrapper

P: n/a
Hi!

Here is the problem: I'd like to restrict local filesystem stream
operations to one directory just like a root jail.

fopen('/file.bin') would actually open /some/path/file.bin.

One goal of this behavior is to prevent Xinclude instructions to point
to "out of application directory" files when processed by the XSLT
processor, among other things.

I've been reading all I can about streams and wrappers and came to the
conclusion that one have no possibility of rewriting a stream wrapper
for the file:// scheme. Even if we can unregister the built-in wrapper
and register a custom one, we have no way to do the actual on-disk
stream operations within that wrapper.

My idea was to:

1. register a custom scheme that would use the built-in wrapper used to
handle the file:// wrapper. That could even be something dynamic to
prevent 3rd-party XML documents to use that unrestricted scheme. let's
say we give it a static name and call it "file.full://".

2. write a wrapper rejecting operations on files outside of the allowed
jailed directory. that wrapper would use the file.full:// scheme to
actually write/read data, after having mapped jailed paths to real
filesystem paths.

Here is an example:

1. An XML document needs "/dir/file.xml" to be xinclude'd by the XSLT
processor.

2. The custom file:// wrapper receives the request and maps
"/dir/file.xml" to "/var/www/data-jail/dir/file.xml". It then uses the
file.full:// scheme to pass the request to the real wrapper. This means
that what I wanted was a situation where "file:///dir/file.xml" is
equivalent to "file.full:///var/www/data-jail/dir/file.xml".

As already said, file.full could be dynamic to prevent the XML document
from using the unrestricted wrapper.

Ideally, PHP would provide the classes that handle the built-in schemes.
Imagine that 'BuiltInFileWrapper' is the class that handle file://
streams by default:

<?php
stream_wrapper_unregister('file');
stream_wrapper_register('file', 'CustomRestrictedFileWrapper');
stream_wrapper_register('file.full', 'BuiltInFileWrapper');
?>

In this example my CustomRestrictedFileWrapper class may still actually
handle the read/write operations through the file.full scheme.

Is there any solution to simulate this? How can I get that behavior?

Another less important question is: is it possible to register another
default scheme than file://?

Thank you very much for your help,

Julien.
May 19 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Julien Biezemans wrote:
Hi!

Here is the problem: I'd like to restrict local filesystem stream
operations to one directory just like a root jail.

fopen('/file.bin') would actually open /some/path/file.bin.

One goal of this behavior is to prevent Xinclude instructions to point
to "out of application directory" files when processed by the XSLT
processor, among other things.

I've been reading all I can about streams and wrappers and came to the
conclusion that one have no possibility of rewriting a stream wrapper
for the file:// scheme. Even if we can unregister the built-in wrapper
and register a custom one, we have no way to do the actual on-disk
stream operations within that wrapper.

My idea was to:

1. register a custom scheme that would use the built-in wrapper used to
handle the file:// wrapper. That could even be something dynamic to
prevent 3rd-party XML documents to use that unrestricted scheme. let's
say we give it a static name and call it "file.full://".

2. write a wrapper rejecting operations on files outside of the allowed
jailed directory. that wrapper would use the file.full:// scheme to
actually write/read data, after having mapped jailed paths to real
filesystem paths.

Here is an example:

1. An XML document needs "/dir/file.xml" to be xinclude'd by the XSLT
processor.

2. The custom file:// wrapper receives the request and maps
"/dir/file.xml" to "/var/www/data-jail/dir/file.xml". It then uses the
file.full:// scheme to pass the request to the real wrapper. This means
that what I wanted was a situation where "file:///dir/file.xml" is
equivalent to "file.full:///var/www/data-jail/dir/file.xml".

As already said, file.full could be dynamic to prevent the XML document
from using the unrestricted wrapper.

Ideally, PHP would provide the classes that handle the built-in schemes.
Imagine that 'BuiltInFileWrapper' is the class that handle file://
streams by default:

<?php
stream_wrapper_unregister('file');
stream_wrapper_register('file', 'CustomRestrictedFileWrapper');
stream_wrapper_register('file.full', 'BuiltInFileWrapper');
?>

In this example my CustomRestrictedFileWrapper class may still actually
handle the read/write operations through the file.full scheme.

Is there any solution to simulate this? How can I get that behavior?

Another less important question is: is it possible to register another
default scheme than file://?

Thank you very much for your help,

Julien.


Actually, I think this is a job better suited for the Apache configuration. Try
alt.apache.configuration

You may also be able to do some of it at the OS (assuming you're using a version
of Unix/Linux).

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
May 19 '06 #2

P: n/a
Jerry Stuckle wrote:

Actually, I think this is a job better suited for the Apache
configuration. Try alt.apache.configuration

You may also be able to do some of it at the OS (assuming you're using a
version of Unix/Linux).


How can apache help me there? I don't see the point. Please note that I
need full local filesystem access in some internal parts of the
application. The "jailed" wrapper is meant to be used as the default
file:// scheme handler but internal stuffs will need the unrestricted
wrapper (accessed under a different scheme than the default one, for
example).

Someone pointed me to open_basedir ini instruction, but this also causes
_any_ stream function to be restricted to the specified directory, which
is not acceptable.

For example, I have a class autoload function that needs to access a
directory outside the jail.

I know, that's tricky. But I'm convinced that PHP could improve its
stream wrappers support by supplying built-in wrapper classes. At the
moment, being able to register a custom file:// scheme handler is almost
of no use at all as there is now way to actually read and write the
files within the custom wrapper.

Julien.
May 19 '06 #3

P: n/a
Julien Biezemans wrote:
Jerry Stuckle wrote:
Actually, I think this is a job better suited for the Apache
configuration. Try alt.apache.configuration

You may also be able to do some of it at the OS (assuming you're using a
version of Unix/Linux).

How can apache help me there? I don't see the point. Please note that I
need full local filesystem access in some internal parts of the
application. The "jailed" wrapper is meant to be used as the default
file:// scheme handler but internal stuffs will need the unrestricted
wrapper (accessed under a different scheme than the default one, for
example).

Someone pointed me to open_basedir ini instruction, but this also causes
_any_ stream function to be restricted to the specified directory, which
is not acceptable.

For example, I have a class autoload function that needs to access a
directory outside the jail.

I know, that's tricky. But I'm convinced that PHP could improve its
stream wrappers support by supplying built-in wrapper classes. At the
moment, being able to register a custom file:// scheme handler is almost
of no use at all as there is now way to actually read and write the
files within the custom wrapper.

Julien.


Julien,

The Apache configuration can help because Apache is handling the file:// schema
- and you can use it to restrict access, redirect from one directory to another,
etc. However, fopen() does not use Apache - it goes straight to the OS, so
Apache configuration restrictions will not affect it.

Again, try alt.apache.configuration.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
js*******@attglobal.net
==================
May 19 '06 #4

P: n/a
Julien Biezemans wrote:
I know, that's tricky. But I'm convinced that PHP could improve its
stream wrappers support by supplying built-in wrapper classes. At the
moment, being able to register a custom file:// scheme handler is almost
of no use at all as there is now way to actually read and write the
files within the custom wrapper.


Have you try stream_wrapper_restore()? The idea is to restore the
original wrapper, open the file, then unregister it again.

May 19 '06 #5

P: n/a
Jerry Stuckle wrote:

Julien,

The Apache configuration can help because Apache is handling the file://
schema - and you can use it to restrict access, redirect from one
directory to another, etc. However, fopen() does not use Apache - it
goes straight to the OS, so Apache configuration restrictions will not
affect it.

Again, try alt.apache.configuration.


Thank you.

However I'm still not convinced that it will be of any help. In what
parts oh PHP does apache file:// scheme handling apply? I guess it
concerns includes/requires, stuffs like that? One of the main purposes
of what I'm asking is to restrict file accesses within the built-in PHP
XSLT processor and it makes use of the PHP stream system which is, like
you said, independent of apache.

I'm going to dig the apache docs though. But I doubt it will be my answer.

Thanks again,

Julien.
May 19 '06 #6

P: n/a
Chung Leong wrote:
Julien Biezemans wrote:
I know, that's tricky. But I'm convinced that PHP could improve its
stream wrappers support by supplying built-in wrapper classes. At the
moment, being able to register a custom file:// scheme handler is almost
of no use at all as there is now way to actually read and write the
files within the custom wrapper.


Have you try stream_wrapper_restore()? The idea is to restore the
original wrapper, open the file, then unregister it again.


EurÍka! Am I an idiot or what? Sometimes we look for complex solutions
while there is an easy one :)

I guess it will work. I'm going to try this tonight.

Thank you !

Julien.
May 19 '06 #7

P: n/a
Julien Biezemans wrote:

EurÍka! Am I an idiot or what? Sometimes we look for complex solutions
while there is an easy one :)

I guess it will work. I'm going to try this tonight.

Thank you !

Julien.


Segfaults, segfaults, segfaults. The first stream being read by my
encapsulating wrapper does work but following streams just make PHP crash.

What a pity.
May 21 '06 #8

P: n/a
Julien Biezemans wrote:
Julien Biezemans wrote:
EurÍka! Am I an idiot or what? Sometimes we look for complex solutions
while there is an easy one :)

I guess it will work. I'm going to try this tonight.

Thank you !

Julien.


Segfaults, segfaults, segfaults. The first stream being read by my
encapsulating wrapper does work but following streams just make PHP crash.

What a pity.


Upgraded from 5.1.2 to 5.1.4 and the segfaults disappeared :D
May 21 '06 #9

P: n/a
I just wanted to share my experience: the wrappers do the job very well.

I have built a wrapper which jails local file streams to a specific
directory. This allows the following behavior:

<?php
$fh = fopen('/catalog/main.xml', 'r');
?>

Actually opens up '/srv/app_root/catalog/main.xml'. Internal functions
are authorized to open non jailed files by using the dynamic
free.file-XX:// stream scheme (where XX are changing figures). This
prevents XML document to refer to out-of-jail documents within Xinclude
elements or other proprietary stuffs.

As libxml PHP extension makes use of streams:

<?php
DOMDocument::load('/catalog/main.xml');
?>

Does work too, that's really nice.

Remember that I had to upgrade from PHP 5.1.2 to 5.1.4 to prevent
strange segfaults in the wrappers.

Maybe this can inspire someone.

Julien.
May 22 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.