RHEL6 – How to Setup an Anonymous Download Only FTP Server

Sticker,375x360A while back I spit out a post on how to configure an anonymous ftp server that allowed uploads and downloads, which you can find here.

Its a very exciting read and will tell you everything that you need to know to get you up and running with an anonymous ftp server. However those instructions are specifically for a server that allows anonymous uploads as well as downloads. So today we are going to go over only the steps for anonymous download, which is actually much easier.

Basic Install & Configuration

So first lets install vsftp.

# yum -y install vsftpd && service vsftpd start && chkconfig vsftpd on

Then edit /etc/vsftp/vsftpd.conf and make sure that the following line is uncommented.


You should also be aware of the following configuration directive. By setting local enable to no in /etc/vsftp/vsftpd.conf, you disallow local Unix users access to ftp, which ensures that your ftp server is truly anonymous only.


Now restart vsftpd and you should be in business

Testing Anonymous Download

To test ftp you need an ftp client, which can be installed via yum as seen below.

yum -y install ftp

Then you should be able to ftp to localhost like as seen below and get a file. Note that an anonymous login does not a password

# ftp localhost
Connected to localhost (
220 (vsFTPd 2.2.2)
Name (localhost:root): anonymous
331 Please specify the password.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (127,0,0,1,170,125).
150 Here comes the directory listing.
drwxr-xr-x    2 0        0            4096 Aug 30 15:37 pub
-rw-r–r–    1 0        0               0 Aug 30 15:39 test2
-rw-r–r–    1 0        0               0 Aug 30 15:38 testfile
226 Directory send OK.
ftp> get test2

The same test executed as root ( a local user) should fail as seen below.

# ftp localhost
Connected to localhost (
220 (vsFTPd 2.2.2)
Name (localhost:root): root
530 This FTP server is anonymous only.
Login failed.

Unix File Permissions and SELinux

One of the things that can ruin your day when it comes to getting and ftp server up and running is SELinux. However when setting up an anonymous download ftp server using the default ftp root directory you don’t actually need to change anything.

By default your ftp root directory is going to be /var/ftp/, and its SELinux context and default perms are going to be as seen below.

drwxr-xr-x. root root system_u:object_r:public_content_t:s0 /var/ftp

Here the default context is public_content_t which by allows reads but not writes, and the default Unix perms allow reads and not writes.

Changing Default FTP Root Directory

If you wanted to change anonymous vsftp to use a different root directory (other than /var/ftp) you would need to add the following line to /etc/vsftpd/vsftpd.conf. In the example below I am setting my new ftp root to /shared/ftp


You are also going to need to asign the correct SELinux file context (public_content_t) to your new directory.

# semanage fcontext -a -t public_content_t “/shared/ftp(/.*)?”

# restorecon -vvFR /shared/ftp

Configuration Differences Between Anon Upload and Download

So as I stated above its actually a bit easier to configure an anonymous download only ftp server, than it is to configure it to allow uploads as well.  This section for reference only, my post on configuring anonymous upload and download ftp server can be reference here.

First you will need to assign a different SELinux context. Its public_content_rw_t not public_content_t.

# semanage fcontext -a -t public_content_rw_t ‘/var/ftp(/.*)’

# restorecon -vvFR /var/ftp

You will also need to fiddle with SELinux booleans

# setsebool -P allow_ftpd_anon_write=1

And we are also going to want to change the Unix permissions on our ftp root directory. Here we are changing group ownership to ftp and setting the setgid bit.

# chgrp ftp /var/ftp/
# chmod 2760 /var/ftp

Good luck and try not to break anything.


RHEL6 – SELinux Troubleshooting II: Electric Boogaloo

Little_Miss_Trouble_by_Percyfan94So a good while back I posted an article on how to troubleshoot SELinux violations and after reviewing that article as part of a troubleshooting exercise, I realized that I left out a few details. Needless to say my original article was not as clear as it should be. Anyway I wanted to use up a few more bytes of the internet to clarify.

When the package setroubleshoot-server is installed, SELinux violations will be sent to /var/log/messages, which makes it fairly easy to troubleshoot SELinux issues.

So first lets install setroubleshoot and all its parts

# yum install setroubleshoot*

In my case on RHEL6, the following packages were installed


Note that the setroubleshoot-server is the one that you need to troubleshoot via the command line.

Now lets generate a violation. In this case I am just dropping a file with the wrong selinux context into /var/www/html and am trying to access it.

# touch /root/file3 && cp /root/index.html /var/www/html/file3

Check the context if you must to make sure that its not correct for httpd content. In this case you can see that it is not.

# ls -lZ /var/www/html/file3
-rwxrwxrwx. root root system_u:object_r:admin_home_t:s0 /var/www/html/file3

Now start Apache and try to access the file via elinks or a browser. You will get a Forbidden error, which I have omitted below.

# elinks -dump http://localhost/file3

Note that you may need to restart auditd if your message does not show up in the messages file.

Aug 11 17:08:39 vfatmin01 setroubleshoot: SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/file3. For complete SELinux messages. run sealert -l 5a413022-af89-4222-b055-0cc1edc4bbad

Note: You will also find a the same error in /var/log/audit/audit.log, albeit in a bit less friendly format.

type=AVC msg=audit(1344719319.890:7196): avc:  denied  { getattr } for  pid=6765 comm=”httpd” path=”/var/www/html/file3″ dev=dm-1 ino=656718 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file

Anyway back to the error from the messages file. At the end of the error you are shown the UUID of the error and the sealert command to run to get more information on the error.

# sealert -l 5a413022-af89-4222-b055-0cc1edc4bbad

Output below:

SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/file3.

*****  Plugin restorecon (99.5 confidence) suggests  *************************

If you want to fix the label.
/var/www/html/file3 default label should be httpd_sys_content_t.
Then you can run restorecon.
# /sbin/restorecon -v /var/www/html/file3

Wow, sealert actually tells you why the file is being blocked and the commands that you should run to fix the problem. Nice!

SELinux – Invalid Regex in /etc/selinux/targeted/contexts/files/file_context

EnikSo I have been doing my best to better understand SELinux as of late, and last night when I was practicing I ran into an issue that had me banging my head against by desk.

Specifically I was playing around with the semanage command and working on defining a particular context to a directory that I had just created. However I was not exactly quite sure of the exact regex to use (or even if I needed to use a regex)

The specific command that I ran was…

#semanage fcontext -a -t httpd_sys_content_t /var/www2

Now my concern was that this was not the correct command for me to run since www2 was a directory and I wanted to make sure that appropriate SELinux contexts were applied recursively as new files/directories were created. So I ran the following command that I found in my RHEL book.

#semanage fcontext -a -t httpd_sys_content_t ‘/var/www2/html(*,/)’

which spits out this….

/etc/selinux/targeted/contexts/files/file_contexts.local:  line 13 has invalid regex /var/www2/html(*,/):  Invalid preceding regular expression

Oops, wait I entered the command wrong. Its a period and the end not a comma, so I run the command again with a period this time and get the following error.

# semanage fcontext -a -t httpd_sys_content_t ‘/var/www2/html(*./)’
/etc/selinux/targeted/contexts/files/file_contexts.local:  line 13 has invalid regex /var/www2/html(*,/):  Invalid preceding regular expression
/etc/selinux/targeted/contexts/files/file_contexts.local:  line 14 has invalid regex /var/www2/html(*./):  Invalid preceding regular expression

Well crap, its still not correct. So I enter this command and get another error.

#semanage fcontext -a -t httpd_sys_content_t “/var/www2/html(/.*)?

So at this point I start running all sorts of variations of the command with minor syntax changes each time, each time getting an error and each time getting more and more frustrated thinking that I am still not running the command correctly.

However this is not actually the case.

After I take a step back and cool off I actually take the time to read the error message which is pointing me t the file, file_contexts.local. Which upon further inspection actually contains each and every regex that I just ran regardless of the fact that the regex was correct.

# cat /etc/selinux/targeted/contexts/files/file_contexts.local | grep www2
/var/www2    system_u:object_r:httpd_sys_content_t:s0
/var/www2/html(/,*)?    system_u:object_r:httpd_sys_content_t:s0
/var/www2/html(/,*)    system_u:object_r:httpd_sys_content_t:s0
/var/www2/html    system_u:object_r:httpd_sys_content_t:s0
/var/www2(/.*)?    system_u:object_r:httpd_sys_content_t:s0
/var/www2/html(*,/)    system_u:object_r:httpd_sys_content_t:s0
/var/www2/html(*./)    system_u:object_r:httpd_sys_content_t:s0
/var/www2/html(/.*)?    system_u:object_r:httpd_sys_content_t:s0

In a nutshell.. the semanage command added each and context to file/directory mapping despite the fact that my regex was not correct, and then it gave me an error. So each time I ran the command with the an invalid regex, another entry was added and the error message grew. One would think that it would detect the regex error first and not add it to the file.

Anwyway the fix was to identify all the bad lines in the file from the error message and run the following command against each entry.

#semanage fcontext -d “/var/www2/html(*,/)?”

Once I cleaned out the file of the offending entries I was able to run the command one last time, this time using the correct syntax and was error free

RHEL6 – Using Semanage and Restorecon to Modify SELinux File Contexts

Potty TrainingOk, how to keep this simple? Lets see…


Ok, semanage, when used with the fcontext argument, is used to define SELinux file contexts for file. It basically adds the new definition to the file,  /etc/selinux/targeted/contexts/files/file_contexts.

For example lets say that I create a new file called /root/foobar.

Using the command below I can see the default context that is assigned to a file created in /root

# ls -lZ foobar
-rw-r–r–. root root unconfined_u:object_r:admin_home_t:s0 foobar

Now lets say that I want to change the context of this file to public_content_t.  The first step to accomplish this is to define its new context.

# semanage fcontext -a -t public_content_t /root/foobar


Now that the context type is defined we need to actually modify the current context of our file. So now you run restorecon against the file to actually make the change. Note: use -v for verbose.

# restorecon -v /root/foobar

restorecon reset /root/foobar context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:public_content_t:s0


There is also a command called chcon, that can also be used to change the defined context for a file. However I advise against using it as changes made using chcon will not survive a filesystem relabel. What is a filesystem relabel? Well according to wiki.centos.org, a relabel is defined below.

“Sometimes it is necessary to relabel the complete filesystem although this should only be necessary when enabling SELinux after it has been disabled or when changing the SELinux policy from the default targeted policy to strict.”


RHEL6 — Troubleshooting SELinux Violations

Sad_face1Dear Reader: Welcome to my third and not final installment on SELinux. The first two can be read here and here. They are exciting reads and are sure to have you on the edge of your seat.

Anyway, the best way to implement SELinux sucessfully is to know how to troubleshoot when things aren’t going your way. If you panic at the first sign of trouble, you are just going to end up turning off SELinux and not reap the rich rewards that it will bring you in life. Now that I have convinced you to run SELinux lets get started.

First install the package setroubleshoot, which will send SELinux messages to our messages file.

yum -y install setroubleshoot-server.x86_64

Now you can search the messages file for SELinux Violations. Use sealert -l UUID to find information on a specific incident, or sealert -a  /var/log/audit.log to search an entire log file for violations.

In this specfic example, I created a test file and dropped it in /var/www/html, however I did not set the context to httpd_sys_content_t, then i attempted to view the file in a browser. Obviously access was denied. The output of sealert shows me the error and then tells me how to fix it.


SELinux is preventing /usr/sbin/httpd “getattr” access to /var/www/html/file3.

Detailed Description:

SELinux denied access requested by httpd. /var/www/html/file3 may be a
mislabeled. /var/www/html/file3 default SELinux type is httpd_sys_content_t, but
its current type is admin_home_t. Changing this file back to the default type,
may fix your problem.


Allowing Access:

You can restore the default system context to this file by executing the
restorecon command. restorecon ‘/var/www/html/file3’, if this file is a
directory, you can recursively restore using restorecon -R

Fix Command:

/sbin/restorecon ‘/var/www/html/file3’

Boom goes the dynomite! Problem solved.

RHEL6 – SELinux Modes and Contexts

Anime,art,cartoon,chibi,darth,vader,darthvader-26d94e794e11142d417a277b8fbdc0eb_hSELinux, or Security-Enhanced Linux as its known by the guy who invented it, is a Linux feature that provides an additional level of security by setting rules for which processes can access which files, directories, ports, etc.

Display and Modify SELinux Modes:

You can use /etc/sysconfig/selinux to change the default SELinux mode at boot, and the setenforce command can be used to change the default level on the fly. Getenforce can be used to determine the current SELinux mode. 

# getenforce

Display SELinux Contexts:

Under SELinux, every file, process, directory, or port is assigned a special security label called a context.

To view the contexts assigned to a file or directory use the '-Z' option. Coupled with and 'ls" or a 'ps" this is a formidable command.

To view a list of all possible assigned contexts use semanage.

# semanage fcontext -l

Modify SELinux Contexts:

For example, lets create two test files in /tmp called testfile1 and testfile2, and then lets check their contexts.

# ls -lZ test*
-rw-r–r–. root root unconfined_u:object_r:user_tmp_t:s0 testfile1
-rw-r–r–. root root unconfined_u:object_r:user_tmp_t:s0 testfile2

Now compare this to the default context assigned to apache content

# ls -ldZ /var/www/html
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html

So lets say that I want to move testfile1 to /var/www/html and make it accessable via a webbrowser; in order to do this I must assign the correct context to the file using the restorecon command.

# restorecon -Rv /var/www/html

The command above restores or even better, allows the testfiles to inherit the contexts assigned to the parent directory, which in this case is /var/www/html/

Add SELinux Contexts:

Now lets say that you need to add a directory and apply a context directly to that directory, instead of allowing a context to be inheritted. For example, lets say that I need to setup an apache virtual server under /virtual_server2, so lets first create the directory and a simple index.html

# mkdir /virtual_server2
# vi /virtual_server2/index.html
# ls -Zd /virtual_server2
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /virtual_server2

# ls -Zd /virtual_server2/index.html
-rw-r–r–. root root unconfined_u:object_r:default_t:s0 /virtual_server2/index.html

Now we need to set and apply the correct http content context to /virtual_server2 and its contents (say that 5 times fast)

# semanage fcontext -a -f "" -t httpd_sys_content_t '/virtual_server2(/.*)?'

# restorecon -RFvvv /virtual_server2/

restorecon reset /virtual_server2 context unconfined_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /virtual_server2/index.html context unconfined_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0

Now that our context is correct apache should have no issue serving up our new content (once configured on the apache side)

# ls -Zd /virtual_server2/
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /virtual_server2/