I've set up vsftpd on my Fedora 12 server, and I'd like to have the following configuration. Each user should have access to:

  • his home directory (/home/USER);
  • the web directory I created for him (/web/USER).

To achieve this, I first configured vsftpd to chroot each user to his home directory. Then, I created /web/USER with the correct permissions, and used mount --bind /web/USER /home/USER/Web so that the user may have access to /web/USER through /home/USER/Web.

I also turned on the SELinux boolean ftp_home_dir so that vsftpd is allowed to write in users' home directories.

This works very well, except that when a user tries to upload or rename a file in /home/USER/Web, SELinux forbids it because the change must also be done to /web/USER, and SELinux doesn't give vsftpd permission to write anything to that directory.

I know that I could solve the problem by turning on the SELinux boolean allow_ftpd_full_access, or ftpd_disable_trans. I also tried to use audit2allow to generate a policy, but what it does is generate a policy that gives ftpd write access to directories of type public_content_t; this is equivalent to turning on allow_ftpd_full_access, if I understood it correctly.

I'd like to know if it's possible to configure SELinux to allow FTP write access to the specific directory /web/USER and its contents, instead of disabling SELinux's FTP controls entirely.

# semanage fcontext -a -t public_content_rw_t "/myftp/pub(/.*)?"

Be sure to include the (/.*)? at the end of the directory name.

I also tried to use audit2allow to generate a policy, but what it does is generate a policy that gives ftpd write access to directories of type public_content_t; this is equivalent to turning on allow_ftpd_full_access, if I understood it correctly

Essentially, yes; since SELinux allows directories/files labeled with public_content_t to be shared between different services. However, further access control is in place through the use of sebooleans (or sebool, more precisely).

Giving "ftpd full access", doesn't mean giving it the rights to do/read/write what and where it wants. SELinux has designated policies in place for the services on your system; meaning, ftpd is allowed to read files if the directory's file context (fcontext) is public_content_t. SELinux gives write permissions to the ftp server if the directory's fcontext is public_content_rw_t; other services such as samba, apache, etc. have to be allowed write permissions to those directories through the booleans, according to the pertaining RedHat Documentation. If your "local policy" gives ftpd write access in directories labelled public_content_t, it essentially strips away a layer of security. Therefore, I suggest labeling the directory with the public_content_rw_t context, and removing your custom generated local policy.

For further information and details, please see the SELinux wiki pages.

| improve this answer | |
  • Shouldn't it be enough to just chcon the directory to the right context? – Pavel Šimerda Mar 29 '14 at 10:01
  • chcon is for temporary changes, semanage is persistent; also, there's a difference between the two in that chcon changes the file on the FS, while semanage updates the policy itself with the new info, as mentioned in this mailing list entry – ILMostro_7 Mar 30 '14 at 1:50
  • I'm afraid this information not precise, at the least. The fact that chcon works on the filesystem also means it is permanent, not temporary, and lasts until the context is changed again (e.g. by chcon or by restorecon). On the other hand, semanage IMO just updates the database and doesn't change the file context which would render this answer incomplete. According to the mailing list, you have to use semanage and restorecon as a replacement for chcon, not only semanage. – Pavel Šimerda Mar 30 '14 at 14:51
  • 1
    right...since SELinux is guided by the database, any changes to SELinux's policy would render the chcon incompatible. DAC is used before SELinux to check for rwx permissions, after which SELinux's MAC policy decides whether the process is allowed access within the scope/context of the FS directories/files. – ILMostro_7 Mar 30 '14 at 18:04
  • Take a look at SELinux's Wiki page for further explanation and details. – ILMostro_7 Mar 30 '14 at 18:08

Try this:

setsebool -P allow_ftpd_full_access on

If SELinux is to blame, there's a few SELinux booleans worth looking at.

Best start is: getsebool -a | grep ftp

You'll see something like

allow_ftpd_anon_write --> off allow_ftpd_full_access --> on allow_ftpd_use_cifs --> off allow_ftpd_use_nfs --> off ftp_home_dir --> on ftpd_connect_db --> off httpd_enable_ftp_server --> off tftp_anon_write --> off

Not all of these are relevant to vsftpd, for example the >httpd_enable_ftp_server is for Apache running FTP, and tftp_anon_write is for >tftpd. I'd start with:

setsebool -P allow_ftpd_full_access on setsebool -P ftp_home_dir on

Source: https://www.centos.org/forums/viewtopic.php?t=8129

| improve this answer | |

Let's summarize the known information into a better answer. You have already stated a solution using particular selinux booleans or allowing write access to any directories with public_content_t which are both suboptimal for you.

What you need is to ensure that the directories have proper selinux context. You have paths /home/$USER/Web and /web/$USER, the former used for mounting the latter via --bind option.

The first idea that comes to my mind is to try it without the mount --bind. I guess that would work for FTP access for your first testing and maybe you already tried that. You need to check whether those files are now accessible via HTTP. If not, it means your Apache Userdir doesn't work and should be fixed before playing with mount --bind. You probably want to have those directories in /web because of external storage, right?

I guess the only problem here is that the /web/$USER directory isn't configured in the same way as would work automatically for /home/$USER/Web. You can create another directory like /home/$USER/Test and compare the results of ls -lZ on them. You would clearly see the difference.

You can use chcon to change the context and then check what happens. It's a low level tool and it's not a systematic solution but it helps you test things quickly. You can also do a little bit of black magic here and just run restorecon on the /home/$USER/Web and I believe it will set the context correctly.

The final solution would be to use semanage fcontext to alter the path database to use the correct context also to /web as well as any /web/$USER and especially to have the context of /home/$USER/Web the same as for /web/$USER as the mount --bind is a bit of black magic itself.

After altering the path database, don't forget to run restorecon -r /web on and it might be good to also test that restorecone -r /home doesn't break that. Also check whether new /web/$USER directories are created with the right context or restorecon is required. If you're not happy with the situation, you can configure restorecond to monitor those directories and fix the context immediately but that should be a last resort.

Always remember that selinux itself doesn't know the path database but works solely with the security contexts of the respective files.

I don't have a selinux-enabled distribution at hand right now, otherwise I would give you more command line examples and the solution would be more precise. I can fix it up later with a centos/fedora virtual if necessary. Now I see that the question is rather old. I was tricked by the insufficient answer, but I hope it will still help someone.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.