PHP glob/scandir and Linux softlinks/permissions - php

I'm trying to write a simple online music player to improve my programming.
I have a server running CentOS 6.5, with an external hard disk containing all my files. I mounted my storage partition to /mnt/storage and my music is in /mnt/storage/cascornelissen/Muziek, which has the following permissions:
drwxrwxr-x 19 cascornelissen ftpusers 4096 Nov 4 14:43 Muziek
Then I have a simple httpd webserver, hosting the project in /var/www/html/melodi, which constains a softlink to the Muziek directory mentioned earlier:
lrwxrwxrwx 1 root ftpusers 34 Jan 26 22:31 music -> /mnt/storage/cascornelissen/Muziek
I want to use PHP's glob to list all the files but that returned an empty array. So I tried scandir("music") but it returns the following error:
Warning: scandir(music): failed to open dir: Permission denied in /var/www/html/melodi/index.php on line 42
Any ideas on how to fix this permissions issue?

Try this:
chmod ugo+x /mnt /mnt/storage /mnt/storage/cascornelissen
Probably some part of your path will not allow entry for your Apache user. Allowing entry to a directory means adding x or execute permissions to the directory.
Explanation
# create path a/b
mkdir -p a/b
ls a/b # this works
# now remove all permissions for a
chmod 000 a
ls a/b # ls: cannot access a/b: Permission denied
# but why, we should still have permission for b??
# Now, lets add x permission for a:
chmod ugo+x a
ls a/b # works again
ls a # ls: cannot open directory a: Permission denied
# So, we cannot list contents of a, but we can
# access a/b *through* a
So, execute permission or x for a directory means we can access the path below it, even if we cannot read the contents of the directory itself. In your case, Apache needs permission to "walk through" /mnt/storage/cascornelissen even though it will not read any files until it reaches Muziek.

Related

Permissions problems with proc_open

I'm having permissions problems when running the following PHP script as root:
#!/usr/bin/php
<?php
$ph = proc_open('whoami', [['pipe','r'],['pipe','w'],['file','/tmp/foo.bar', 'w']], $fds);
if ($ph) {
echo 'command output: ' . stream_get_contents($fds[1]);
proc_close($ph);
} else {
echo 'proc_open failed' . PHP_EOL;
}
The script itself runs fine if /tmp/foo.bar doesn't exist, or is owned by root. But if ownership is changed to another user, proc_open will fail regardless of permissions on the file.
SELinux is disabled, and we are not using ACLs. I'm using PHP 7.4.33 (I know it's old and unsupported, but it's a requirement for FreePBX) on Alma Linux 9.1.
Output:
$ ./test.php
command output: root
$ ls -lah /tmp/
total 12K
drwxrwxrwt. 18 root root 4.0K Dec 14 16:57 .
dr-xr-xr-x. 18 root root 4.0K Dec 14 16:48 ..
-rw-r--r-- 1 root root 0 Dec 14 16:57 foo.bar
$ chown admin /tmp/foo.bar
$ ./test.php
proc_open failed
$ chmod 777 /tmp/foo.bar
$ ./test.php
proc_open failed
$ ls -lah /tmp/
total 12K
drwxrwxrwt. 18 root root 4.0K Dec 14 16:57 .
dr-xr-xr-x. 18 root root 4.0K Dec 14 16:48 ..
-rwxrwxrwx 1 admin root 0 Dec 14 16:57 foo.bar
$ tail -2 /var/log/php.log
[14-Dec-2022 16:57:17 America/Toronto] PHP Warning: proc_open(/tmp/foo.bar): failed to open stream: Permission denied in /test.php on line 3
[14-Dec-2022 16:57:28 America/Toronto] PHP Warning: proc_open(/tmp/foo.bar): failed to open stream: Permission denied in /test.php on line 3
Even disregarding the fact that I'm root, group permissions should allow me full access to the file. So what's going on?
This is due to the permissions on the /tmp directory. When PHP tries to open the file for writing, it gets the EACCES error. From the documentation of open(2):
EACCES
Where O_CREAT is specified, the protected_fifos or protected_regular sysctl is enabled, the file already exists and is a FIFO or regular file, the owner of the file is neither the current user nor the owner of the containing directory, and the containing directory is both world- or group-writable and sticky. For details, see the descriptions of /proc/sys/fs/protected_fifos and /proc/sys/fs/protected_regular in proc(5).
/tmp has the sticky bit set so that anyone can create files there, but users can only delete their own files. Although root can bypass this deletion restriction, it can't bypass the above check in open().
Ok I tried this in a different directory than /tmp, as suggested in comments, and it worked as expected. Using that to hone my search terms I was able pretty quickly to find this U&L answer. Beginning with kernel 4.19 the fs.protected_regular kernel parameter was made available. This parameter:
Disallows open of FIFOs or regular files not owned by the user in world writable sticky directories, unless the owner is the same as that of the directory or the file is opened without the O_CREAT flag. The purpose is to make data spoofing attacks harder.
Apparently it's enabled by default. So because /tmp is world-writable and sticky, I can't touch files that aren't mine – even if I'm root. For the record, if I have to disable this feature:
sysctl fs.protected_regular=0
echo 'fs.protected_regular=0' > /etc/sysctl.d/90-writabletemp.conf
But I'll be better off trying to work around it in the code somehow.

PHP - Why do you need 'x' permissions on a directory to read file stats?

I'm trying to work out why I need x permissions for others on a directory to read the stats of the files within it.
this is my folder:
4 drw-r--r-x 2 root root 4.0k Dec 7 17:40 file_host
When the permissions are set so x is assigned to others I can read the files filemtime etc without issue. If I remove the x then I get:
Warning: filemtime(): Stat failed for /file_host/file1234.zip (errno=13 - Permission denied)
The permission on the files in the directory are:
9684 -rw-r--r-- 1 root root 9.4M Dec 7 17:40 file1234.zip
As soon as I add x to the folder it all works. The web user isn't root and doesn't have any root privileges.
Why do you need x to execute the file to read it's values ?
Any way around this ?
Thanks
The execute x bit is what allows a user to descend into a directory. The way your folder is owned, you require execute bit on the other portion of the permissions to allow the www-data / apache user to descend into the directory. If you run chown root:www-data and then remove the x bit on the other portion you will notice this will continue to work without giving all other users on the OS access to the directory.

PHP: "failed to open stream: Permission denied"

I am getting some interesting results on my server when i try to access any Directory or File via some Function.I have set all my file & directory permissions to 777 and have changed the content owner to Apache but i still get error messages.Code:
move_uploaded_file($_FILES['file']['tmp_name'], '/var/www/html/fileContent_Site/userData/'.$_SESSION['username'].DIRECTORY_SEPARATOR.$_FILES['file']['name']);
Or
file_put_contents('userData/userData.txt', $result,FILE_APPEND);
mkdir("userData/".$register['username']);
For 'move_uploaded_file()' i get:
move_uploaded_file(/var/www/php/Site/userData/radi/110729.png):failed to open stream: Permission denied in /var/www/php/Site/upload.php
move_uploaded_file(): Unable to move '/tmp/phpUFvMcn' to '/var/www/php/Site/userData/radi/110729.png' in /var/www/php/Site/upload.php
And for 'file_put_content()' and 'mkdir()'
file_put_contents(userData/userData.txt): failed to open stream: Permission denied in /var/www/php/Site/register.php
mkdir(): Permission denied in /var/www/php/Site/register.php
Check owners that runs PHP. To check - simply add these strings near your "file_put_contents" in your PHP file
echo "current user: ".get_current_user();
echo "script was executed under user: ".exec('whoami');
If you see the difference between current user and "script user", then you've found the issue.
Output example:
current user: root
script was executed under user: www-data
Just set the appropriate user to your PHP files directory/directory you want to write from your PHP script:
In Linux terminal execute:
chown -R www-data:www-data /path/to/the/folder
please, note, that "www-data" user is only for example. You should use your user you get from the "script was executed under user" output.
P.S:
To check folder owner, you could use this linux command:
ls -ltr
P.P.S:
check if your folder has the right access permission: 755
The folder php files should have "644" access permission.
To check permission, use the same command as for the owner check:
ls -ltr
You'll see something like:
drwxr-xr-x 10 www-data www-data 4096 Aug 5 15:18 api
Where "drwxr-xr-x" is access permission. Google it, to get more info about.
Open http.conf (in /opt/lampp/etc/httpd.conf) file.
Edit this part:
<IfModule unixd_module>
#
# If you wish httpd to run as a different user or group, you must run
# httpd as root initially and it will switch.
#
# User/Group: The name (or #number) of the user/group to run httpd as.
# It is usually good practice to create a dedicated user and group for
# running httpd, as with most system services.
#
User hostname
Group hostname
</IfModule>
See, if that works.
use
$_SERVER["DOCUMENT_ROOT"]."/myFolder/path to upload folder".
and check once

Allowing web server to delete uploaded files, how?

I'm implementing a file upload in symfony2. My File entity is owned by a User, and represents the uploaded file. The uploaded files should not be accessible for anyone except admins and the owner. For addressing this (apart from securing the controller), I save them in a directory which is not under /web/. I called this directory /private_files/ (and is located at the root of the project).
To allow the web server to write to that directory I ran this (I'm on Mac OS X Mavericks):
$ sudo chmod +a "`whoami` allow delete,write,append,file_inherit,directory_inherit" private_files/
$ sudo chmod +a "www allow delete,write,append,file_inherit,directory_inherit" private_files/
The uploading works fine. However when trying to delete the files through the controller, with
unlink($path)
I get the error "Warning: unlink(path/to/file): Permission denied".
When listing the files on the terminal with ls -al, I get
drwxr-xr-x+ 3 myuser staff 204 Mar 23 11:59 .
drwxr-xr-x 24 myuser staff 816 Mar 21 19:51 ..
-rw-r--r-- 1 _www wheel 7395585 Mar 23 11:59 uploaded_file_1
where I notice that the uploaded files lack the executable permission and the "+" which represents the ACLs.
What's the correct approach to allow these files to be deleted with the unlink method? Should the files inherit the ACLs (and if so, how)? Or should a chmod be applied on the directory? Thanks a lot.
I think it is because your folder is not owned by apache user which handle php.
because you created the folder /private_files/ with another user not with apache user, for the app/cache is created programically so he own it and can create/delete. i will update it as answer

PHP mkdir and apache ownership

Is there a way to set php running under apache to create folders with the folder owned by the owner of the program that creates it instead of being owned by apache?
Using word press it creates new folders to upload into but these are owned by apache.apache and not by the site that they are running in. This also happens using ostickets. For now we have to SSH into the server and chmod the folder, but it would seem there would be a setting somewhere to override the ownership outside of any program that does it.
Safe_mode is turn on on your server. The function mkdir() creates folder with owner ("apache", "none", ..) that different of the current script owner. And scripts couldn't upload (move, copy) files into that folder with another owner (that is not like current script owner).
Disable safe_mode and that would be work.
See http://php.net/manual/en/features.safe-mode.php for details.
P.S. With enable safe_mode you can't use chmod() function in php.
Another way is to put the apache user and the "customer users" in a new group. Additional the directory should use the sticky bit SGID so each new file got the group assignment to this new group. This way the webserver and the "customer users" can work with the files without any problems
[17:57] progman#proglap /tmp/test $ ls -al /tmp/test
total 9
drwxrwsr-x 2 root users 48 Apr 1 17:55 .
drwxrwxrwt 36 root root 9264 Apr 1 17:53 ..
As you see the directory got the stick bit SGID and the owner is the "users" group in which I (progman) am. No if another user adds a file the group automatically get set to this group
[17:55] proglap ~ # touch /tmp/test/x
This is executed from root. Now we get:
[17:57] progman#proglap /tmp/test $ ls -la /tmp/test
total 9
drwxrwsr-x 2 root users 72 Apr 1 17:59 .
drwxrwxrwt 36 root root 9264 Apr 1 17:53 ..
-rw-r--r-- 1 root users 0 Apr 1 17:59 x
As you see the added file is from root, but the group is set to users and this way I can remove it
[18:00] progman#proglap /tmp/test $ rm x
rm: remove write-protected regular empty file `x'? y
[18:01] progman#proglap /tmp/test $ ls -la /tmp/test
total 9
drwxrwsr-x 2 root users 48 Apr 1 18:01 .
drwxrwxrwt 36 root root 9264 Apr 1 17:53 ..
Keep in mind that you still need to change the chmod if you want to edit the file as rw-r--r-- is just group read access. But changing the chmod, maybe even working with umask, is better than dealing with root-access and using chown.
Not directly, no. You can't "give away" ownership of a file to another user, unless you're root. You could investigate using the "AssignUserID" apache directive to force that particular vhost to run as a particular user/group. With that Apache/PHP would create any files with the appropriate ownership
Check out PHP chown() function

Categories