Setting the umask for SFTP transactions

I ran into this problem when was setting up a web server for usage by a team setting up our company web site. There were two developers and they both would be uploading files to the machine, and they both were going to want to modify each others files if need-be. I made a common group and set the sgid bit on the parent directory. I didn’t want to open up straight FTP access to the box so I told them to use SFTP or SCP. This worked great until I found that each users umask was not being applied to new files and directories. The two developers could see each others files but not modify them. I found that the sftp process is spawned by the root user and its umask is applied to the transaction. I wasn’t in favor or modifying the root umask so I came up with another solution.

The only thing I could find to work was to create a wrapper script around the sftp process that would temporarily set the umask for the transaction.

First I created the wrapper script:

umask 0002
# The path to your sftp-server binary may differ
exec /usr/libexec/openssh/sftp-server

Then I pointed the Subsystem directive in the sshd_config file to my script:

Subsystem       sftp    /opt/

A quick restart/reload of the sshd configuration and I was in business. Both users could see and edit each others files. Email or comment with questions.

—Edit (20090619)
Or even simpler still as @Gilles pointed out in the comments you can do away with the wrapper script entirely and simply change the Subsystem line in your sshd_config to this:

Subsystem sftp /bin/sh -cumask 0002; /usr/libexec/openssh/sftp-server’

Thanks Gilles!

—Edit (20110525)
Or simplest yet, as @Larry and @simingol pointed out in the comments, there is a new flag for the sftp-server, ‘-u’, that allows you to directly set the umask, overriding the user umask. So to use it, just do this:

Subsystem sftp /usr/libexec/openssh/sftp-server -u 0002
  1. #1 by Simon on September 12, 2011 - 10:32 am

    I tried all of the above methods on RHEL 5 ,and none worked. I restarted ssh each time.

  2. #2 by Simon on September 13, 2011 - 10:40 am

    Tried this on RHEL 5.5 kernel 2.6.18-194.17.4.el5PAE

    TEST 1:
    Subsystem sftp /bin/sh -c ‘umask 0002; /usr/libexec/openssh/sftp-server’

    Restarted ssh.
    Result: Ignored umask, and instead put file with rw-r–r–

    Subsystem sftp /usr/libexec/openssh/sftp-server -u 0002

    Restarted ssh.
    Result: Unable to log in via SFTP. Authenication works, but Connection closed

    Subsystem sftp /usr/libexec/openssh/sftp-server
    Restarted ssh.
    Removed .bashrc and .bash_profile from user home directory.
    Added only this line into .bash_profile: umask 0002
    Result: File put as -rw-r–r–

    Subsystem sftp /usr/libexec/openssh/sftp-server
    Restarted ssh.
    Removed .bashrc and .bash_profile from user home directory.
    Set umask locally as: umask 0002 and then ran sftp command.
    Result: File put as -rw-r–r–

    Same as TEST4, but set umask within SFTP client e.g:
    sftp> lumask 0002
    Local umask: 002
    Result: File put as -rw-r–r–

    Conclusion: Umask setting over SFTP on RHEL 5.5 is unimplemented. What a load of cr*p.

  3. #3 by Simon on September 13, 2011 - 10:50 am

    Note that RHEL 5.5 uses an old OpenSSH version:
    # ssh -V
    OpenSSH_4.3p2, OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008
    The RPM package is : openssh-server-4.3p2-41.el5_5.1

    This is quite old. The latest version is 5.9.
    Version 4.3 was released on February 1, 2006

  4. #4 by jeffro on September 13, 2011 - 11:06 am

    I have seen in the past that RHEL uses very old versions of certain services. Very stable, but very old. I rarely ever use Red Hat based distro’s on my servers, so I don’t encounter this much.

    Thanks for the posts @simon

  5. #5 by Simon on September 14, 2011 - 3:54 am

    Sadly, we are in the process of migrating from SLES to RHEL. Most systems are v6, but in the case of the above one it is v5.5.
    RHEL v6.1 comes with OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010, so reasonably recent.

    I would have preferred Debian or Solaris, but non-IT folk made the decision…

  6. #6 by Glitch Hop on September 27, 2011 - 4:32 pm

    Interesting! I finally realized why the -u flag wasn’t allowing the SFTP session to launch. That flag is only available in OpenSSH_5.4p1 and above, and i was running OpenSSH_5.3p1 🙁

  7. #7 by Malcolm on November 28, 2011 - 4:40 pm

    I hope this can save someone else hours of frustration…

    If you’re using a GUI SFTP application, check its preferences for setting permissions on upload.

    I had tried all the solutions above, and it turns out the application was just overriding them.

  8. #8 by Bryan on December 19, 2011 - 1:13 pm

    try adding umask command to .bashrc
    (.bash_profile is for interactive)

    ~]$ cat .bashrc
    # .bashrc

    # Source global definitions
    if [ -f /etc/bashrc ]; then
    . /etc/bashrc

    # User specific aliases and functions

    # Friendly file creation mask
    umask u=rwx,g=rwx,o=r

  9. #9 by jeffro on December 19, 2011 - 8:24 pm

    HI Bryan, this unfortunately doesn’t work. The sftp subsystem doesn’t spin up a bash shell to complete the command. Thus, your.bashrc file is never read. This was one of the first things I tried when I initially encountered this issue.

  10. #10 by Steven on March 16, 2012 - 9:33 am

    If you use chroot-jails and therefore are forced to use the internal-sftp subsystem, you can also pass the -u parameter to it:

    Subsystem sftp internal-sftp -u 0002

    This also works for the ForceCommand directive:
    ForceCommand internal-sftp -u 0002

  11. #11 by jeffro on March 16, 2012 - 10:04 am

    Thanks Steve, pretty close to my last edit on the article, but worth mentioning anyway. The new ‘u’ flag does make life a bit easier.

  12. #12 by Heather on June 12, 2012 - 12:46 am

    Alternatively, if you don’t want this to extend to all users you can set it per user/group like this:
    Match User localuser
    ForceCommand /bin/sh -c ‘umask 0002; ${SSH_ORIGINAL_COMMAND:-$SHELL}’

  13. #13 by jeffro on June 12, 2012 - 10:27 am

    Thanks for the tip Heather. I haven’t tried this but being able to apply this per user/group is definitely preferred to forcing a universal umask. Generally the only people that have access to my systems are the ones that need this applied though, I will give this a shot in the future.

  14. #14 by birger on June 15, 2012 - 6:18 am

    at least for some sftp implementations it seems to work if you put it in the users .profile

  15. #15 by Paul on September 5, 2012 - 11:01 am

    Not sure if it’s Filezilla’s fault, but all newly created files/folders do not have the group writeable bit set. Even after trying above instructions.
    How can I force that bit on all newly uploaded files?

  16. #16 by jeffro on September 13, 2012 - 9:50 am

    The umask enforces r/w permissions, its just WHOSE umask is being applied when you create a file is the kicker . Yes, Filezilla can reset r/w permissions on upload, so you are going to want to check those first. If the above instructions aren’t working then you are going to want to check whose umask IS being used

  17. #17 by William Murat on February 18, 2013 - 1:07 pm

    Thanks a lot, Jeff!

    I have this problem and finally I found a solution.


  18. #18 by Alex Jurado on May 13, 2013 - 8:46 am

    Thanks, Jeff.

    Following your steps, I created in my server the wrapper /usr/local/sbin/

    Then, I’ve edited /etc/passwd, there are user which I do not want to have ssh , interactive access, so they have: /usr/local/sbin/ instead of the usual /bin/bash

  19. #19 by Gagandeep on October 2, 2013 - 1:29 am

    Hi Jeff,

    I am using solaris 10, and I want to change umask for sftp from default to 0002. After following instructions above I am still unable to get the required result.
    Solaris 10 has its default sftp server (internal-sftp). when i changed Subsystem in my default sftp server to accept “-u 0002” and i restarted ssh service but still unable to get the files with required permissions.

    Than I installed openSSH and changed the sshd_config there and stopeed my default ssh but still unable to resolve.

    Can you please help.

  20. #20 by Dave on January 6, 2014 - 12:46 am

    Steven :
    If you use chroot-jails and therefore are forced to use the internal-sftp subsystem, you can also pass the -u parameter to it:
    Subsystem sftp internal-sftp -u 0002
    This also works for the ForceCommand directive:
    ForceCommand internal-sftp -u 0002

    By the way folks this one works for all users, and Heathers solution works for individual users when you need to implement scponly users on FreeNAS boxen.
    Thanks guys and gals. Keep up the good fight Jeff. 🙂

  21. #21 by Jon on January 9, 2014 - 1:59 pm

    This is such a good article it has spawned a (very errily similar) child! All the best stuff gets ripped off..

  22. #22 by jeffro on January 9, 2014 - 2:05 pm

    Thanks for the heads-up Jon. Odd, the guy didn’t even change most of the text from my site, including a call out to one of the comments 😉

  23. #23 by Karn on January 13, 2014 - 9:23 am

    Hello Jeff, I just went thro the stuff discussed above and discussion looks hot & intresting…

    I would like to Know how we can setup sftp in solaris 10 host. I see the config on ssh_config file ..
    # override default of no subsystems
    Subsystem sftp /usr/libexec/openssh/sftp-server

    what this really mean .. any opinion will be great in help

  24. #24 by Russ Sanderlin on January 17, 2014 - 3:36 pm

    I just ran into a similar issue. Thank you for posting this.

  25. #25 by Andrew Taylor on January 21, 2014 - 4:29 am

    Alternatively, if you don’t want this to extend to all users you can set it per user/group like this:
    Match User localuser
    ForceCommand /bin/sh -c ‘umask 0002; ${SSH_ORIGINAL_COMMAND:-$SHELL}’

  26. #26 by César on January 27, 2014 - 7:19 am

    Thanks Jeff, this helped me with my SFTP issues.

  27. #27 by Adam Smith on March 28, 2014 - 3:40 am

    Hello Jeff,
    Really thanks a lot for this . it really takes me out from a trouble. it is really useful. Thanks again 🙂

  28. #28 by Nethan on September 17, 2014 - 9:51 am

    Hello Jeff,

    Iam using Redhat Linux if i wish to do umask for particular set of sftp users how can do it.

    Suppose 4-5 users.

  29. #29 by jeffro on September 17, 2014 - 9:58 am

    Create all the users on the box and add them to a common group. Then you could chmod 2775 the parent directory and set it to be owned by some user and the common group. Make sure you set your umask so the users can view and modify each other files.

  30. #30 by drkzs on October 21, 2014 - 5:29 am

    Hello Jeff,

    I’m struggling at the moment with my chrooted configuration… It seems to me that the openssh server (at least for sftp transfer) set back the permissions of original files, even if umask is specified ? I can see some “set mode ” in my internal-sftp logs.
    What is the expected behaviour, should the umask option (i use currently the -u) override the original permissions ?

  31. #31 by AFA Med on September 13, 2016 - 9:19 am

    Thanks for the tutorial, I followed your guidelines, however, it was impossible to force a specific starting CHMOD for files, because the UMASK is hardcoded within some shell commands and utilities.

    In other hand, I used the more performant SFTP system, namely internal-sftp. It was easy to setup and tweak, especially when it comes to creating a Chroot Jail. Then, I created an sftp_users group and added apache user to it, in order to allow it getting access to the files uploaded by the webmasters.

(will not be published)