file:// streams: writing a custom wrapper

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Julien Biezemans

    file:// streams: writing a custom wrapper

    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 'BuiltInFileWra pper' is the class that handle file://
    streams by default:

    <?php
    stream_wrapper_ unregister('fil e');
    stream_wrapper_ register('file' , 'CustomRestrict edFileWrapper') ;
    stream_wrapper_ register('file. full', 'BuiltInFileWra pper');
    ?>

    In this example my CustomRestricte dFileWrapper 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.
  • Jerry Stuckle

    #2
    Re: file:// streams: writing a custom wrapper

    Julien Biezemans wrote:[color=blue]
    > 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 'BuiltInFileWra pper' is the class that handle file://
    > streams by default:
    >
    > <?php
    > stream_wrapper_ unregister('fil e');
    > stream_wrapper_ register('file' , 'CustomRestrict edFileWrapper') ;
    > stream_wrapper_ register('file. full', 'BuiltInFileWra pper');
    > ?>
    >
    > In this example my CustomRestricte dFileWrapper 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.[/color]

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

    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.
    jstucklex@attgl obal.net
    =============== ===

    Comment

    • Julien Biezemans

      #3
      Re: file:// streams: writing a custom wrapper

      Jerry Stuckle wrote:[color=blue]
      >
      > Actually, I think this is a job better suited for the Apache
      > configuration. Try alt.apache.conf iguration
      >
      > You may also be able to do some of it at the OS (assuming you're using a
      > version of Unix/Linux).
      >[/color]

      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.

      Comment

      • Jerry Stuckle

        #4
        Re: file:// streams: writing a custom wrapper

        Julien Biezemans wrote:[color=blue]
        > Jerry Stuckle wrote:
        >[color=green]
        >>Actually, I think this is a job better suited for the Apache
        >>configuration . Try alt.apache.conf iguration
        >>
        >>You may also be able to do some of it at the OS (assuming you're using a
        >>version of Unix/Linux).
        >>[/color]
        >
        >
        > 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.[/color]

        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.conf iguration.

        --
        =============== ===
        Remove the "x" from my email address
        Jerry Stuckle
        JDS Computer Training Corp.
        jstucklex@attgl obal.net
        =============== ===

        Comment

        • Chung Leong

          #5
          Re: file:// streams: writing a custom wrapper

          Julien Biezemans wrote:[color=blue]
          > 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.[/color]

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

          Comment

          • Julien Biezemans

            #6
            Re: file:// streams: writing a custom wrapper

            Jerry Stuckle wrote:[color=blue]
            >
            > 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.conf iguration.
            >[/color]

            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.

            Comment

            • Julien Biezemans

              #7
              Re: file:// streams: writing a custom wrapper

              Chung Leong wrote:[color=blue]
              > Julien Biezemans wrote:[color=green]
              >> 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.[/color]
              >
              > Have you try stream_wrapper_ restore()? The idea is to restore the
              > original wrapper, open the file, then unregister it again.
              >[/color]

              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.

              Comment

              • Julien Biezemans

                #8
                Re: file:// streams: writing a custom wrapper

                Julien Biezemans wrote:[color=blue]
                >
                > 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.[/color]

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

                What a pity.

                Comment

                • Julien Biezemans

                  #9
                  Re: file:// streams: writing a custom wrapper

                  Julien Biezemans wrote:[color=blue]
                  > Julien Biezemans wrote:[color=green]
                  >> 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.[/color]
                  >
                  > Segfaults, segfaults, segfaults. The first stream being read by my
                  > encapsulating wrapper does work but following streams just make PHP crash.
                  >
                  > What a pity.[/color]

                  Upgraded from 5.1.2 to 5.1.4 and the segfaults disappeared :D

                  Comment

                  • Julien Biezemans

                    #10
                    Re: file:// streams: writing a custom wrapper

                    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::lo ad('/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.

                    Comment

                    Working...