553 Could not create file

Latest response


Please forgive me if this is a stupid question .... but I'm more of a Windows guy than Linux.
Trying to get FTP to work and having trouble with permissions, I think. 
The user is userx.  It is in the userx group as well as the root group.  I even set root as the primary group for userx.
I can connect fine, but when I try to transfer a file I get "553 Could not create file.
The directory I'm trying to write to (/opt/installs/) is owned by root.  Shouldn't userx be able to write to this directory?  If I open up a terminal window and su userx, I can write fine.  But I can't FTP.
Thanks for any help.


Just because they share a name doesn't mean they're the same thing.  The "root" user and "root" group are two very different things.

If a directory's ownership is root:root and the directory's permissions are set to mode 755 (rwxr-xr-x), the "userx" user, even if a member of the "root" group, is not going to be able to write to the directory. You'd need to either:

  • change the directory's permissions to 775 (rwxrwxr-x)
  • set an ACL on the directory that either explicitly gives the "userx" user write permissions to the directory or gives all members of group "root" write permissions to that directory.

Separate from the above, depending which FTP service you're using and how that FTP service is configured, "userx" may be getting mapped (to a security context) differently within the FTP service context than it does from an interactive shell.


Looks like the directory has the correct permissions

drwxrwxr-x.  3 root root 4096 Feb 12 17:02 installs

The FTP service I'm using is vsftpd.  How do I tell if the user is being mapped differently?


Did you try some simple tests such as an ftp to the userx home directory or to /tmp? If you can't 'write' files to either of those locations it may not be a permission problem at all so much as an ftp configuration problem.


Have you looked at the config files in /etc/vsftpd, especially vsftpd.conf? Entries such as write_enable, etc?

Is SELinux enabled?  Run the following:

# getenforce

If it is, you will need to update a few booleans, and you may have to create a new policy (due to using that non-standard directory for your share).  I don't believe there is a similar Windows functionality to compare to, unfortunately.  I guess SElinux is sort of similar to the User Access Control, whereas if you try to do something that is tecnically possible, it will stop you for further validation.  In this case, the validation is a bit more involved than putting in the Administrator password ;-)


Unfortunately the only page I could find specific to SElinux is external to Red Hat.


I can ftp to /tmp

I can't cd to /home.  I get: 550 Failed to change directory.

Below is the vsftpd.conf.  Is is the default.  I have not made any changes.


# Example config file /etc/vsftpd/vsftpd.conf
# The default compiled in settings are fairly paranoid. This sample file
# loosens things up a bit, to make the ftp daemon more usable.
# Please see vsftpd.conf.5 for all compiled in defaults.
# READ THIS: This example file is NOT an exhaustive list of vsftpd options.
# Please read the vsftpd.conf.5 manual page to get a full idea of vsftpd's
# capabilities.
# Allow anonymous FTP? (Beware - allowed by default if you comment this out).
# Uncomment this to allow local users to log in.
# Uncomment this to enable any form of FTP write command.
# Default umask for local users is 077. You may wish to change this to 022,
# if your users expect that (022 is used by most other ftpd's)
# Uncomment this to allow the anonymous FTP user to upload files. This only
# has an effect if the above global write enable is activated. Also, you will
# obviously need to create a directory writable by the FTP user.
# Uncomment this if you want the anonymous FTP user to be able to create
# new directories.
# Activate directory messages - messages given to remote users when they
# go into a certain directory.
# The target log file can be vsftpd_log_file or xferlog_file.
# This depends on setting xferlog_std_format parameter
# Make sure PORT transfer connections originate from port 20 (ftp-data).
# If you want, you can arrange for uploaded anonymous files to be owned by
# a different user. Note! Using "root" for uploaded files is not
# recommended!
# The name of log file when xferlog_enable=YES and xferlog_std_format=YES
# WARNING - changing this filename affects /etc/logrotate.d/vsftpd.log
# Switches between logging into vsftpd_log_file and xferlog_file files.
# NO writes to vsftpd_log_file, YES to xferlog_file
# You may change the default value for timing out an idle session.
# You may change the default value for timing out a data connection.
# It is recommended that you define on your system a unique user which the
# ftp server can use as a totally isolated and unprivileged user.
# Enable this and the server will recognise asynchronous ABOR requests. Not
# recommended for security (the code is non-trivial). Not enabling it,
# however, may confuse older FTP clients.
# By default the server will pretend to allow ASCII mode but in fact ignore
# the request. Turn on the below options to have the server actually do ASCII
# mangling on files when in ASCII mode.
# Beware that on some FTP servers, ASCII support allows a denial of service
# attack (DoS) via the command "SIZE /big/file" in ASCII mode. vsftpd
# predicted this attack and has always been safe, reporting the size of the
# raw file.
# ASCII mangling is a horrible feature of the protocol.
# You may fully customise the login banner string:
#ftpd_banner=Welcome to blah FTP service.
# You may specify a file of disallowed anonymous e-mail addresses. Apparently
# useful for combatting certain DoS attacks.
# (default follows)
# You may specify an explicit list of local users to chroot() to their home
# directory. If chroot_local_user is YES, then this list becomes a list of
# users to NOT chroot().
# (default follows)
# You may activate the "-R" option to the builtin ls. This is disabled by
# default to avoid remote users being able to cause excessive I/O on large
# sites. However, some broken FTP clients such as "ncftp" and "mirror" assume
# the presence of the "-R" option, so there is a strong case for enabling it.
# When "listen" directive is enabled, vsftpd runs in standalone mode and
# listens on IPv4 sockets. This directive cannot be used in conjunction
# with the listen_ipv6 directive.
# This directive enables listening on IPv6 sockets. To listen on IPv4 and IPv6
# sockets, you must run two copies of vsftpd with two configuration files.
# Make sure, that one of the listen options is commented !!

Sorry, this interface is horrible.  The conf file text pasted in with no breaks.

Great idea to check for SELinux. Have you looked in the /var/log/messages file for any errors when you're trying to ftp?


You can do a "tail -F /var/log/messages" in one window to watch the messages log "live" and then try your ftp tests (successful and unsuccessful) from another window. Do you see any interesting output from the messages log when the ftp's fail?

When I run that it replied back with:


No worries Neil - we all go through the formatting "fun" (they are looking at a remedy to make it better).

For now - click on "Source" above the text entry window and then try to post the config.



The next logical step is to run the following command:

setenforce 0

This put SELinux into 'permissive' mode. Try FTPing after that. If it works, we gotta sort out your SELinux! I don't imagine the FTP Daemon can write to that directory you mentioned under SELinux defaults.

So - that basically means that the UAC is enabled.  Now - SElinux is no trivial thing to review.

However (and this is a good "troubleshooting measure") you can temporarily disable SElinux, by doing the following

# setenforce 0

You may find people recommending that you change the value in /etc/sysconfig/selinux and reboot, which works - however... and I stress... if you go that route and decide to enable SElinux again, the system has to reapply all of the file context/rules which can take a while.

Also - you can follow what is going on by reviewing /var/log/audit/audit.log - a beautiful thing with the Linux shell is the ability to follow the log as it is being written.

So, I recommend - open 2 termina windows (at least - as the tail -f will consume the window it is run in)

# setenforce 0

# tail -f /var/log/audit/audit.log

-- then, attempt to ftp to your system and watch the terminal with the tail -f in it.

That worked.  I can FTP now.

What's the downside of leaving it at permissive?   In Windows, I turn off UAC because it is an annoying pain in the a**.


Try this five step approach now:

1. Find out which package provides the utility we need:

yum provides "*bin/semanage"

2. Install that package:

yum install policycoreutils-python

3. Find out what kind of security contexts were applicable to the usual location:

semanage fcontext --list | grep --color 'var/ftp'

A note here: The audit.log file mentioned by James above is a better indicator of which policy was keeping you. But to fall in-line with best practices or the usual, just take it from a well-known directory on the file system.

4. Add the policy to the system:

semanage fcontext --add --type public_content_t "/opt/installs(/.*)?"

5. Apply the policy:

restorecon -r /opt/installs

6. Enable SELinux:

setenforce 1

man ftpd_selinux


Should tell you a lot more information about how SELinux is controlling ftpd.

Which directory are you trying to use.

man ftpd_selinux



      If you want to determine whether ftpd can login to local users and  can
       read  and write all files on the system, governed by DAC, you must turn
       on the ftpd_full_access boolean. Disabled by default.

       setsebool -P ftpd_full_access 1


       If you want to determine whether ftpd can read and write files in  user
       home  directories,  you must turn on the ftp_home_dir boolean. Disabled
       by default.

       setsebool -P ftp_home_dir 1

If you only want to allow ftpd to write to a particular directory we can set a label for this.


Any turning on one of the booleans would be better then running in permissive mode.

FYI .... When I turn SELinux back on and try FTP, I get the below in the log.

If I keep this enforced, I will need to create a policy for every directory I want to FTP to??   That's kind of nuts!

I assume this SELinux was different in RHEL 3?  I never had to do this in ver 3.



type=AVC msg=audit(1360854149.099:59129): avc:  denied  { write } for  pid=4513 comm="vsftpd" name="installs" dev=dm-0 ino=2229328 scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:usr_t:s0 tclass=dir

type=SYSCALL msg=audit(1360854149.099:59129): arch=c000003e syscall=2 success=no exit=-13 a0=7f541efbb980 a1=c41 a2=1b6 a3=0 items=0 ppid=4508 pid=4513 auid=4294967295 uid=500 gid=0 euid=500 suid=500 fsuid=500 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="vsftpd" exe="/usr/sbin/vsftpd" subj=system_u:system_r:ftpd_t:s0-s0:c0.c1023 key=(null)

I think as Daniel Walsh said, this may be my best option:

setsebool -P allow_ftpd_full_access 1

This should be more acceptable than keeping SELinux in permissive mode, right?

yes.. UAC is exactly that.. but, and this is a good example, it -could- potentially save your behind from malicious stuff.  Like I mentioned previously, SElinux is by no means trivial.  So, don't be discouraged that it made your life difficult.

To answer your question: permissive is certainly not the end of the world, and there is obviously a reason you can turn it off.   In a nutshell SElinux prevents us (users/admins) from allowing certain files/ports from being used incorrectly.  (I.e. you could not share your /etc via nfs, without putting some serious effort into making it work).

One thing to note about SElinux also.  Generally there is already a rule to accomplish what you are trying to do, but.. you have to do it the way SElinux expects.  So, if you were make your FTP share use the default location, you would not know that SElinux was enabled.  The same goes with HTTP.  If you use /var/www/html - then everything works.  Else, you have to adjust rules.

Clear as mud? ;-)

I would agree with Daniel and the response Dhruv Ahuja posted is a detailed approach that I would consider a best practice.

Welcome to Linux! ;-)

Not a nice welcome to RHEL 6!  :)

But thanks so so much to you all for your help and advice!  I'm sure I'll be back with more questions/issues!

Downside is it becomes a lot easier for the system to get thoroughly-owned (under SEL, a given context might get rifled, but the rifling is contained). That said, depending on how remote access to the system is governed, that may essentially be a non-risk (e.g., if you're running on a private network or have network access rules that only permit access from trusted hosts).

Every directory, "no". Every unique directory-root, "probably".

The thing to realize about SELinux is that it is a labeling system, every process and every file/directory has labels on it, and the Kernel has rules about the way process labeles interact with file/directory labels, as well as other process labels.  We attempt to write these rules in the most common ways a user uses the confined process.  SELinux would then prevent a hacked process (vsftpd) from doing anything on your system then be an ftp server.  IE It could not be able to steal credit card data out of a database or read you secrets in your home directory.  But the problem is if you change the default way the system works you need to tell SELinux about it.

Lets look at the AVC message you recieved

type=AVC msg=audit(1360854149.099:59129): avc:  denied  { write } for  pid=4513 comm="vsftpd" name="installs" dev=dm-0 ino=2229328 scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:usr_t:s0 tclass=dir

This avc says that the vsftpd (labeled as ftpd_t) program tried to write to the installs directory.

usr_t is the default labels of content under /usr and /srv.  Out of the box we do  not expect confined services to write to those directories, so it is blocked.   As a matter of fact since most people setup ftp servers to only to share data, we block ftp server from writing to almost everything.    With SELinux you have three options for this type of problem.

1.  You could set labels like public_content_rw_t on the installs directory.

Setup default label for the /src/installs directory.  SELinux uses regex for labels, so this says label everything under /src/installs including the installs directory as public_content_rw_t.

# semanage fcontext -a -t public_content_rw_t '/src/installs(/.*)?'

The semanage command tells SElinux to change the default labels, restorecon actually puts the default labels on files.

# restorecon -R -v /src/installs

Then you can set the SELinux boolean to allow ftpd servers to write to public_content_rw_t files/directories.

# setsebool -P allow_ftpd_anon_write 1

2.  A second option would be to turn on a bigger SELinux boolean that would allow ftpd to read and write any file label on your system

# setsebool -P ftpd_full_access 1

This boolean effectively allows a hacked ftp server to be able to take over your system, but at least the rest of the confined processes would be controled.

3.  You can also add your own custom rules to policy by using a tool called audit2allow which will translate the AVC messages into allow rules.

# grep ftpd /var/log/audit/audit.log | audit2allow -M mypol

# semodule -i mypol.pp

You can read more about SELinux on my blog.


Especially read up on some of the concepts I have brought forth here.



Daniel .... thanks so much for this.  You've been a great help!

Sorry about that, Neil. The current text editor leaves a lot to be desired. As James mentioned, a replacement is on the way.

Hey Daniel/Guru, I have gone through above comments, it was really nice explaining for allowing right setting for selinux. On the related topic I have a scenario.

I have confgure vsftpd with pam_krb5 authentication, when user authenticate its ticket from KDC is stored in /tmp/krb5_xxxx file, as SELINUX in enforcing what context can be applied on /tmp/ in regex way to allow vsftpd to create/access token in /tmp/ .

I get these in sealert ## type=AVC msg=audit(1627838848.189:3590): avc: denied { setattr } for pid=27662 comm="vsftpd" name="pam_krb5_tmp_Y2Kr27" dev="dm-3" ino=71 scontext=system_u:system_r:ftpd_t:s0-s0:c0.c1023 tcontext=system_u:object_r:tmp_t:s0 tclass=file permissive=0

and vsftpd gives error:

Aug 01 23:14:46 cloudplatform-mrghaproxy-3003 vsftpd[31732]: pam_krb5[31732]: authentication succeeds for 'maaz.01' (maaz.01@JASPERINDIA.LOCAL) Aug 01 23:14:46 cloudplatform-mrghaproxy-3003 vsftpd[31732]: pam_krb5[31732]: error writing to credential cache file "/tmp/pam_krb5_tmp_H6Nqm7" Aug 01 23:14:46 cloudplatform-mrghaproxy-3003 vsftpd[31732]: pam_krb5[31732]: error creating ccache for user "maaz.01"

I have tried this way as well but not luck..

grep ftpd /var/log/audit/audit.log | audit2allow -M mypol semodule -i mypol.pp

Thanks in advance.