文章来源 https://www.starduster.me/2014/12/29/use-umask-to-config-sftp-upload-files/

最近遇到一点事,需要开放工作室服务器的网站目录上传文件权限,要求静态网站上传可以即传即用,考虑到简单起见我想到的办法是新建一个用户加入 www-data 组,登录目录设在网站所在目录下,要传网站直接把文件丢上去就行(前提是这些网站都在同一个域名下,不然还需要另外配置 Server)。可是 SFTP 上传的文件都是默认755,原本 vsftpd 可以用户 local_umask 控制上传文件权限,但是坑爹的硬件防火墙封了 FTP 端口,只能通过22端口。但是 SFTP 虽然名字里带 FTP ,但是实际上 SFTP不是由 vsftpd 控制而是由 openssh 控制,SFTP 没有专门的守护进程,也没有独立的配置文件(我在查了半天 vsftpd 相关问题之后才发现这一事实,晕死)

查看 openssh 的配置没发现有 umask 的相关配置,应该只能改 bash 的环境配置了。

那么问题又来了,我在 /etc/passwd 中设置的登陆地址是网站所在地址,系统没有自动生成 bash 的配置文件,于是乎我在手动建立了一个 .bash_profile ,里面填了一行 umask 002,重启 sshd ,惊奇地发现没有效果——原本权限777的文件上传之后还是755。

仔细一想,bash 的配置文件好像不止一个,大概是 SFTP 读取的配置不对?于是又去查了一下关于 bash 的配置,一查吓一跳,还有这么多细节问题以前没注意的。其中最大的问题就是 login shell 和 non-login shell 的区别:

举例来说,同tty1~tty6登入时, 需要输入用户名和密码,此时取得的bash就称为login shell,通过 SSH 登陆启动的 shell、或者使用 su -l 切换账户的时候调用的都是 login shell。
而以X window登入linux后,再以X 的图形化介面启动虚拟终端,此时不需要输入用户名和密码,那个 bash 的环境就称为non-login shell 。或者在原本的 bash 环境中使用bash 启动新 shell,同样没有要求输入用户名和密码,那个第二个 bash 也是 non-login shell。另外 su 命令执行时不指定 -l 参数、使用 bash -c 唤醒的新 shell 也是 non-login shell。

那么,由此可知 ,SSH 登陆和 SFTP 登陆所使用的 shell 应该是 login shell ,那么我们据此设置 bash 配置文件。

总之对于 login shell ,系统读取的只有/etc/profile 一个文件,但是他会调用个人配置如~/.bash_profile,按顺序依次是读取,优先读取第一个配置,后面的配置不会生效,bash  之所以会读取这么多配置,主要是出于对其他 shell 的兼容:

  1. ~/.bash_profile
  2. ~/.bash_login
  3. ~/.profile

而且 ~/.bash_profile 会调用 ~/.bashrc ,也就是说最终 Login shell 读取的是~/.bashrc

而对于 non-login shell , 只会直接读取~/.bashrc,但是 bashrc 会调用/etc/bashrc(Debian 下是 /etc/bash.bashrc)

而这个/etc/bashrc主要有三个作用:

  1. 根据不同的UID,规范出UMASK的值
  2. 依据不同的UID ,规范出PS1, 也就是提示符的内容
  3. 呼叫/etc/profile.d/*sh目录中的内容

顺便一提 PS1  这玩意呢,是 interactive shell 具有的环境变量,用于确定提示符的样式。

bash 默认引用个人配置使用的就是 source 命令,因此我们每次修改 bash 配置,可以使用

点击展开代码

 

命令立刻使之生效.

对于 login shell 和 non-login shell 的区别,有个很简单的办法实践,那就是在自己家目录下建立一个.bash_profile 文件,写上 umask 002,保存退出shell 重新登录,随便新建一个文件,查看属性,bash 调出新的 shell ,再新建一个文件,对比他们的属性。

 
 
 
 
 

Shell

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
stardust@Chaos:~$ touch 1 #建立新文件1
stardust@Chaos:~$ ls -al 1   #查看属性是644,因为默认umask是022
-rw-r--r-- 1 stardust stardust 0 Dec 29 16:50 1
stardust@Chaos:~$ bash    #采用 non-login 方式启动新 shell
stardust@Chaos:~$ touch 2
stardust@Chaos:~$ ls -al 2    #权限属性是644,因为目前没有修改
-rw-r--r-- 1 stardust stardust 0 Dec 29 16:50 2
stardust@Chaos:~$ nano ./.bash_profile   #编辑bash_profile
stardust@Chaos:~$ bash    #采用 non-login 方式启动新 shell
stardust@Chaos:~$ touch 3
stardust@Chaos:~$ ls -al 3  
-rw-r--r-- 1 stardust stardust 0 Dec 29 16:51 3
#权限还是644,因为non-login shell没有读取 bash_profie
stardust@Chaos:~$ su -l stardust
Password:    #su 加 -l 参数之后是 login shell
stardust@Chaos:~$ touch 4
stardust@Chaos:~$ ls -al 4   #权限已经变为664,自定义的 umask 生效
-rw-rw-r-- 1 stardust stardust 0 Dec 29 16:51 4

更多关于 login shell 的测试参见login-shell和non login-shell区别 & bash配置文件实验报告

我本想通过简单测试验证这些加载顺序,但是没成功,那么就只能放一个别人的验证了:理解 bashrc 和 profile

另外附部分 bash man 手册对这几个配置文件的解释:

最后我在/etc/passwd 中登陆目录下手动建立了一个 .bashrc 加了一句 umask 002,目的达到

05-06 20:04