Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sys_get_temp_dir in shared hosting environment

Tags:

Note: This could also fit in superuser.

I am setting up PHP 5.3.10 on a shared host with apache2 mpm itk and open_basedir in a way, that each user may not see or change the files of another user. In the apache2 vhost settings, I add the appropriate entries to restrict the user:

    AssignUserId     userA userA     php_admin_value  open_basedir      /home/userA/www/     php_admin_value  upload_tmp_dir    /home/userA/www/tmp/     php_admin_value  session.save_path /home/userA/www/tmp/     SetEnv           TMPDIR            /home/userA/www/tmp/ 

Now, the first line sets the linux user to use for apache2, the next three lines define the basedir, upload directory and session savepath to be in the user directory. I'll get back to the last line in a sec.

Now for the problem: sys_get_temp_dir() should give back the temporary directory for php, which is /tmp be default on a linux system. For security reasons, this directory should reside in the open_basedir of userA. According to the php-source of 5.3.10, the sys_get_temp_dir()-function uses the environment variable TMPDIR to get this directory:

     // php-src/main/php_open_temporary_file.c:217-219      /* On Unix use the (usual) TMPDIR environment variable. */      {              char* s = getenv("TMPDIR"); 

This is what the fifth line in the configuration above should do. However, sys_get_temp_dir() simply returns the global system directory, ignoring the environmental variable (which is perfectly set in $_SERVER, also viewable via phpinfo()).

This results in some nasty bugs with various software relying on sys_get_temp_dir(), as that directory is outside of the open_basedir setting. I've tried to set the variable directly into $_ENV and $_SERVER without a change in behaviour. I've tried a putenv('TMPDIR=/home/userA/www/tmp') without change.

However, I am able to change the output by defining the variable into /etc/apache2/envvars - which is useless for me, as I want each VHOST to have its own temporary folder.

The only solution I have found so far is overwriting the internal sys_get_temp_dir() through an extension like runkit and enforcing its inclusion via auto_prepend_file. But that solution is so dirty, I simply can't believe, that there is no better solution around.

So, my question: Is there any way to change the result of sys_get_temp_dir() to be set in an apache2 vhost setting, without reimplementing the function with runkit?

Edit: The apache version is 2.2.22, and I currently use mod_php. As I will have to add all users manually, an fcgi or similar setup would also be possible.

like image 477
Lars Avatar asked Nov 01 '12 21:11

Lars


People also ask

What is Sys_get_temp_dir?

sys_get_temp_dir(): string. Returns the path of the directory PHP stores temporary files in by default.

What is Upload_tmp_dir?

Overview. The temporary directory is used for storing files when a file is uploaded. This directory must be writable by whichever user PHP is running as. If not specified, PHP will use the system's default.

Where is temp file located in PHP?

We can get the temporary file path by displaying the tempnam() function with echo . For example, create a variable $temp_path and assign it with the tempnam() function. Write the sys_get_temp_dir() function as the first parameter to the function and php as the prefix.


2 Answers

Running a putenv('TMPDIR=/foo/bar') inside PHP seems to be able to affect the result of sys_get_temp_dir(). You could have an auto_prepend_file directive arranged to run a piece of PHP to set up the TMPDIR and avoid messing with a redefinition of sys_get_temp_dir().

Edit: Also, you could easily use putenv('TMPDIR='.ini_get('open_basedir').'/tmp') to set the temporary directory to the directory structure you laid out in the question.

Funny enough, this turns out to also work (given that you keep the SetEnv TMPDIR /foo/bar in your Apache configuration):

putenv('TMPDIR='.getenv('TMPDIR')); 

Seems like a no-op, but actually does have effect on sys_get_temp_dir(). I'm starting to suspect this has to be some environment-handling bug in PHP.

like image 69
lanzz Avatar answered Sep 22 '22 14:09

lanzz


You have tagged your question cgi, however you are making use of

 php_admin_value  open_basedir      /home/userA/www/  ^^^^^^^^^^^^^^^ 

which is a setting for the apache module version of PHP, Mod_PHP. In that case PHP is loaded once the webserver starts.

Then you make use of SetEnv:

 SetEnv           TMPDIR            /home/userA/www/tmp/ 

this is setting an internal environment variable. It is passed to other apache modules, however I think you need it with the request, not with the virtual server. I don't know it specifically, but I would assume according to your description that this environment variable is getting reset before the PHP script is invoked.

So more a comment than a real answer, but hopefully it helps you clarify some things.

I normally use FCGI for multi-user environments so that I can better separate the users. I never had problems with setting environment variables per each user. But that's just another comment, I don't want to say you have to use it, too. Just to highlight that you need to find out the right place within apache to set the environment variable so it is (still) set when the script is executed.


Also you might not be setting the right environment variable. According to Apache Documentation about environment variables:

Although these variables are referred to as environment variables, they are not the same as the environment variables controlled by the underlying operating system. Instead, these variables are stored and manipulated in an internal Apache structure. They only become actual operating system environment variables when they are provided to CGI scripts and Server Side Include scripts. If you wish to manipulate the operating system environment under which the server itself runs, you must use the standard environment manipulation mechanisms provided by your operating system shell.

You want to set the operating system environment variable for PHP. But you are setting the internal environment variable only.

Mod_PHP might import them to the script, so if you use getenv('TMPDIR') the PHP SAPI specific implementation is used - which does allow you to see those internal environment variables - however the php_get_temporary_directory function is not using it - it looks like.

Please add your Apache and PHP version to your question.

like image 26
hakre Avatar answered Sep 19 '22 14:09

hakre