惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
博客园_首页
博客园 - 【当耐特】
V
Visual Studio Blog
博客园 - 叶小钗
月光博客
月光博客
美团技术团队
J
Java Code Geeks
小众软件
小众软件
Y
Y Combinator Blog
博客园 - Franky
Martin Fowler
Martin Fowler
博客园 - 聂微东
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
人人都是产品经理
人人都是产品经理
Microsoft Security Blog
Microsoft Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG

卡瓦邦噶!

服务器高性能网络调优 | 卡瓦邦噶! 为何写作 | 卡瓦邦噶! 读《金阁寺》 | 卡瓦邦噶! 雨季又来 | 卡瓦邦噶! MTU Probe 引起的初始延迟 | 卡瓦邦噶! 3.5 秒的固定延迟问题 | 卡瓦邦噶! 学习网络的一点经验 | 卡瓦邦噶! ARP 问题诊断 | 卡瓦邦噶! 网络断断续续…… | 卡瓦邦噶! Piccolo P2P 镜像分发 | 卡瓦邦噶! 一起看电影 | 卡瓦邦噶! 《征服C指针》 | 卡瓦邦噶! 我的姥姥 | 卡瓦邦噶! Python的哲学 Python 3.5的新特性 学校不教的计算机课 垃圾回收(GC)的三种基本方式 在编程中体验纯粹的快乐 从《美丽新世界》谈自由 在快钱实习 迷人的嗓音和迷人的故事——《Sleepyhead》 Python 的十个自然语言处理工具 记一个愚蠢的bug 一年炉石传说的游戏体验 《以撒的结合:重生》网页版图鉴 分清 C++的指针、引用和数组 笑话三则 自由比皇帝更伟大——《悲惨世界》笔记 Git 10 周年访谈:Linus 讲述背后故事 用 0x3f3f3f3f 设定最大int值的优点
Linux的用户与管理
laixintao · 2017-12-10 · via 卡瓦邦噶!

很久以来,我对Linux用户的概念都很模糊,只知道如果碰到“Permission Denied”就用sudo来执行,甚至在服务器上跑的很多东西都是用root来跑的。今天花时间学习了一下Linux用户有关的知识,记一下笔记。

本文所有代码都是在virtualbox虚拟机中进行,环境:Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-87-generic x86_64),用户名vagrant,密码vagrant。

一、用户与用户组

1.Linux是如何分辨每一个用户的

Linux并不是通过用户名来分辨每一个用户的,而是通过UID(计算机认识数字比较容易,而人类认识单词比较容易),我们平时所说的用户名只是便于人类操作和记忆。

Shell

1

2

3

4

5

vagrant@saltmaster:~$ ls -l

total 256

-rw-r--r-- 1 root    root    256191 Nov 13 06:26 bootstrap-salt.sh

-rw-rw-r-- 1 vagrant vagrant      0 Nov 26 08:44 filea

-rw-r--r-- 1 root    root       100 Nov 20 06:30 nettools.sls

对于每个文件,记录的其实是一个UID,之所以显示成用户名“vagrant”、“root”,是因为在/etc/passwd中存储了有关的用户信息,ls程序在显示的时候,会根据此文件将对应的UID显示成用户名。如果我们在/etc/passwd这个文件中将UID修改,那么ls将显示的是一个UID,而不是用户名。

用户登录Linux的流程如下:

  1. 寻找/etc/passwd是否有这个用户名,如果有,读出对象的UID和GID(group ID),以及主目录和配置
  2. 读取/etc/shadow,核对密码
  3. 进入shell

2. passwd文件和shadow文件

Linux所有的用户都保存在/etc/passwd文件中,格式如下:

Shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

vagrant@saltmaster:~$ cat /etc/passwd

root:x:0:0:root:/root:/bin/bash

daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin

bin:x:2:2:bin:/bin:/usr/sbin/nologin

sys:x:3:3:sys:/dev:/usr/sbin/nologin

sync:x:4:65534:sync:/bin:/bin/sync

games:x:5:60:games:/usr/games:/usr/sbin/nologin

man:x:6:12:man:/var/cache/man:/usr/sbin/nologin

lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin

mail:x:8:8:mail:/var/mail:/usr/sbin/nologin

news:x:9:9:news:/var/spool/news:/usr/sbin/nologin

uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin

proxy:x:13:13:proxy:/bin:/usr/sbin/nologin

www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin

backup:x:34:34:backup:/var/backups:/usr/sbin/nologin

每一行代表一个账户,通过:来分割信息。数一数会发现一共有7个字段,这7个字段分别代表:

  1. 账户名称
  2. 密码,可以看到所有的密码都是x,这是因为很多程序会读/etc/passwd,将用户名和密码放在一起很不安全,后来密码移动到 /etc/shadow文件中了,/etc/passwd文件只留一个x占位。
  3. UID
  4. GID
  5. 用户信息说明
  6. 主目录(即登录之后立即所在的位置)
  7. shell 登录之后启动的shell,这里有一个特殊的shell就是nologin,上面的例子中,像是backup这种账户是无法登录shell的。所以当我们新建一些系统服务的账号,类似apache,Jenkins等都可以让它们不要登录系统

/etc/shadow文件的格式如下:

Shell

1

2

3

4

5

6

vagrant@saltmaster:~$ clear

vagrant@saltmaster:~$ sudo head -n 4 /etc/shadow

root:!:17466:0:99999:7:::

daemon:*:17379:0:99999:7:::

bin:*:17379:0:99999:7:::

sys:*:17379:0:99999:7:::

可以看到,这也是用:来分割的,一共有9列,每一列代表的意思如下:

  1. 账户名称
  2. 密码
  3. 最近改动密码的日期(相对于第0天,也就是1970年1月1日的偏移天数)
  4. 密码不可改动的日期,如果是0则可以随时修改
  5. 密码需要重新更改的日期,如果不改账户将会变为过期。可以看到默认设置是99999=273年
  6. 字段5前几天进行提醒
  7. 密码过期后的宽限时间,字段5+本字段天数之后依然没有更改才算过期。宽限时间内用户登录会被强制要求修改密码
  8. 账户失效日期,到期无法使用
  9. 保留字段

3.有效用户组与初始用户组

每一个用户都有一个用户组,和UID一样,Linux分辨用户组也是通过GID的,而不是通过名字。和/etc/passwd /etc/shadow一样,对于用户组有 /etc/group /etc/gshadow

先来看/etc/group

Shell

1

2

3

4

5

vagrant@saltmaster:~$ sudo head -n 4 /etc/group

root:x:0:

daemon:x:1:

bin:x:2:

sys:x:3:

一共四个字段:

  1. 用户组名字
  2. 用户组密码,其实很少用,和passwd一样,用x占位了
  3. GID
  4. 此用户组的用户列表,逗号分搁,没有空格(一个用户组可以有多个用户,一个用户可以在多个用户组)

/etc/gshadow的内容几乎和/etc/group一样:

Shell

1

2

3

4

5

6

vagrant@saltmaster:~$ sudo head -n 4 /etc/gshadow

root:*::

daemon:*::

bin:*::

sys:*::

systemd-timesync:!::

要注意的事第二个字段,是密码,如果第二个字段是!,表明该用户组没有用户组管理员。不过由于sudo的存在,其实用户组管理员的功能很少使用了。

  1. 用户组名字
  2. 密码列
  3. 用户组管理员的账号
  4. 该用户组的所属账号

仔细观察你可能发现这样一个问题:在/etc/passwd里面说某一个用户的用户组ID是a,但是在/etc/group的a用户组ID下并没有看到这个账户的名字啊?

这是因为,passwd里面的用户组叫做“初始化用户组”,就是你登录到shell的用户组。这个用户组不需要写到groups里面。

如果一个用户属于很多用户组,这么这些用户组的权限,该用户都会有。那么创建一个文件,默认的用户组应该是哪个呢?

答案是“有效用户组”,通过groups命令,可以查看当前用户的所在用户组,其中,排在第一个的是有效用户组,如果创建文件就会模式使用这个用户组。

下面的命令演示了有效用户组以及用户组的切换:

Shell

1

2

3

4

5

6

7

8

vagrant@saltmaster:~$ groups

adm cdrom sudo dip plugdev lxd lpadmin sambashare vagrant

vagrant@saltmaster:~$ touch test_a

vagrant@saltmaster:~$ newgrp sudo

vagrant@saltmaster:~$ touch test_b

vagrant@saltmaster:~$ ll test_*

-rw-rw-r-- 1 vagrant adm  0 Nov 26 15:46 test_a

-rw-rw-r-- 1 vagrant sudo 0 Nov 26 15:47 test_b

需要注意的是,newgrp是通过新开一个shell来赋予用户新的用户组的权限,通过exit可以回到之前的用户组。

Shell

1

2

3

4

5

6

7

vagrant@saltmaster:~$ exit

exit

vagrant@saltmaster:~$ touch test_c

vagrant@saltmaster:~$ ll test_*

-rw-rw-r-- 1 vagrant adm  0 Nov 26 15:46 test_a

-rw-rw-r-- 1 vagrant sudo 0 Nov 26 15:47 test_b

-rw-rw-r-- 1 vagrant adm  0 Nov 26 15:48 test_c

二、创建与管理用户

1.useradd

了解了用户和用户组的概念,接下来开始讲用户的管理。

创建一个新的账户的命令是useradd,执行这个命令需要读写/etc/passwd等文件,所以一般需要root账户来执行。

Shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

vagrant@saltmaster:/home$ useradd tom

useradd: Permission denied.

useradd: cannot lock /etc/passwd; try again later.

vagrant@saltmaster:/home$ sudo -s

root@saltmaster:/home# useradd tom

root@saltmaster:/home# ls

vagrant

root@saltmaster:/home# grep tom /etc/passwd /etc/shadow /etc/group

/etc/passwd:tom:x:1001:1001::/home/tom:

/etc/shadow:tom:!:17496:0:99999:7:::

/etc/group:tom:x:1001:

root@saltmaster:/home# ls

vagrant

root@saltmaster:/home# su - tom

No directory, logging in with HOME=/

$ pwd

/

$ touch tom_file

touch: cannot touch 'tom_file': Permission denied

上面的代码新建了一个tom账户,可以看到,系统并没有默认为tom创建一个home目录。在CentOS中,使用useradd,系统一般会默认帮你做这几件事:

  1. /etc/passwd中创建一行与账号相关的数据
  2. /etc/shadow创建相关数据,但是密码为空
  3. /etc/group创建一个与用户名一模一样的名称
  4. /home下创建一个和用户名一样的目录,权限700

我们简单的使用useradd命令,Linux会帮我们自动配置一些参数,这些参数是参考的哪里呢?见下面两条命令的输出就明白了:

Shell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

vagrant@saltmaster:~$ useradd -D

GROUP=100

HOME=/home

INACTIVE=-1

EXPIRE=

SHELL=/bin/sh

SKEL=/etc/skel

CREATE_MAIL_SPOOL=no

vagrant@saltmaster:~$ cat /etc/default/useradd

# Default values for useradd(8)

#

# The SHELL variable specifies the default login shell on your

# system.

# Similar to DHSELL in adduser. However, we use "sh" here because

# useradd is a low level utility and should be as general

# as possible

SHELL=/bin/sh

#

# The default group for users

# 100=users on Debian systems

# Same as USERS_GID in adduser

# This argument is used when the -n flag is specified.

# The default behavior (when -n and -g are not specified) is to create a

# primary user group with the same name as the user being added to the

# system.

# GROUP=100

#

# The default home directory. Same as DHOME for adduser

# HOME=/home

#

# The number of days after a password expires until the account

# is permanently disabled

# INACTIVE=-1

#

# The default expire date

# EXPIRE=

#

# The SKEL variable specifies the directory containing "skeletal" user

# files; in other words, files such as a sample .profile that will be

# copied to the new user's home directory when it is created.

# SKEL=/etc/skel

#

# Defines whether the mail spool should be created while

# creating the account

# CREATE_MAIL_SPOOL=yes

vagrant@saltmaster:~$

2.passwd

创建用户用useradd,然后需要为用户创建密码,使用passwd命令。需要注意的有以下几点:

  1. passwd修改自己账户的密码,普通用户需要输入旧密码,root用户不需要
  2. root用户可以修改其他用户的密码而不需要输入旧密码
  3. 普通用户在创建密码时会经过PAM模块检查密码的强度,而root无需遵守强度检查

3.其他一些修改账户的命令(sudo)

chage命令可以修改密码参数有关的信息。

Shell

1

2

3

4

5

6

7

8

vagrant@saltmaster:~$ chage -l vagrant

Last password change : Oct 27, 2017

Password expires : never

Password inactive : never

Account expires : never

Minimum number of days between password change : 0

Maximum number of days between password change : 99999

Number of days of warning before password expires : 7

usermod可以修改有效用户组、初始用户组、主目录等与用户有关的信息。

userdel可以删除用户。这个命令非常危险,将会从/etc/passwd/etc/shadow,中删除用户,也会删除/home/user用户目录。一般情况下,我们暂停某个账户可以只将账户的状态设置为不可用,例如/etc/shadow第八个字段(账号失效日期)设置为0即可。如果确实需要删除用户,也可以用userdel -r username,这样会先删除find / -user username,然后再删除用户。

4.用户可以使用的一些命令

上面介绍的都是sudo用户对账户的管理,还有一些命令普通用户就可以使用:

  1. finger查阅用户有关的信息
  2. chfn change finger,修改用户的详细信息
  3. chsh 改变默认登录的shell
  4. id可以用来查询用户的id

5.用户组的管理

在上面我们已经认识了用户和用户组,以及用户的管理。其实用户组的管理也是类似,只不过是/etc/group/etc/gshadow而已。要注意的是,newgrp是新开启一个shell,用新的环境来登录用户和用户组的。仔细想想, 这是一个很有趣的问题。正好我在写这篇文章的第三天(本文估计要写一个周),Julia写了一篇博客:How do groups work on Linux? 这篇博客正好说明了newgrp的行为:Linux运行的进程都保存着有效组GID的属性,当进程想要通过组权限(这里略去了UID检查过程)读一个文件的时候,当看一个文件是否可以读的时候,Linux检查一下此进程的有效组里面是否有等于文件的组的,如果有那么就可以读。Julia之前误认为是:Linux检查一下此进程的用户是否可以读文件,如果不可以,就看一下用户所在的组,是否有等于文件所属的组的。——这样的话,就要每次去读/etc/passwd了!

另外有关用户组还要知道的一个命令是gpasswd,这个命令可以分配组管理员。组管理员可以添加或删除用户到某一个用户组。有点像论坛的版主的意思。

三、精确的权限控制ACL

我们知道,Linux的文件系统有三组权限,分别是“owner group other”,这样无法做到对同一group的成员,或对都是others的成员控制权限。所以就有了ACL(Access Control List)。ACL可以针对单一用户、单一文件或目录进行rwx的权限设置。这是一个UNIX-Like操作系统权限外的支持项目,需要文件系统的支持(mount | grep acl)。

这里没有啥需求所以没有仔细研究,更多的资料读者可以自行搜索,推荐IBM Linux ACL 体验

四、用户切换su, su – 和sudo

su用来切换用户,使用方法是 su - username-的意思是环境变量。比如说su - vagrant那么会以vagrant来登录shell,所有的环境变量都会变成vagrant的。如果不加-那么就只是id变成vagrant,进去之后如果收MAIL,还会是原来的用户的。

su - root就可以登录root账户了!其实root可以省略,su - 就是登录root账户的意思。使用某个账户临时运行一下命令:su - root -c command,这里的root也可以省略。注意如果root账户没有密码的话,会出现 Authentication failure。

su是简单的切换命令。现在有一个问题,如果每个人都有用root账户权限的需求,那么就要有很多人知道root账户的密码,这很不安全,所以就有了sudo命令。sudo可以让你用其他用户(通常是root账户)来执行命令。使用sudo的账户必须在/etc/sudoers里面。系统验证sudo的过程如下:

  1. 当用户执行sudo命令时,系统先从/etc/sudoers文件中检查用户是否有执行权限
  2. 如果有,让用户输入自己的密码
  3. 执行sudo后面的命令

sudoers文件支持对用户组授权(以%开头)。格式如下:

Shell

1

2

用户账号     登陆者的来源主机名=可切换的身份    可执行的命令(绝对路径)

root        ALL=(ALL)                     ALL

其中,可以修改最后一列为NOPASSWD:ALL来免除每次运行sudo都需要的密码操作。(设置之后简直每天可以多好几秒呢!)

好了,基本的管理和操作到这里差不多了,上面的学习过程都是参考的鸟哥的Linux私房菜第三版(这本书讲的挺细的但是有点啰嗦,让人摸不透重点)。其余还提到了一些内容,下面就只列一下,有需要的可以去了解:

  1. PAM模块,对密码强度的的检查就是这个模块实现的,基本上就是个API
  2. 查询在线用户与登录日志: w, who, last, lastlog
  3. 用户之间发送消息: write, mesg, wall
  4. 发送mail:MAIL
  5. 一些用户有关的检查工具:pwck, pwconv, pwunconv, chpasswd
  6. 如何批量创建账号? passwd --stdin

本文完结!(接下来是废话了)写这篇博客花了三个星期!好吧,虽然中间有各种各样别的事情来分心。之前有人在论坛上说,《鸟哥私房菜》这本书草草看了一遍但是不想再看了,又没学到什么东西。我也有差不多类似的感受,这本书好是好,但是太详细,实践又比较少,写的比较像手册(很多书都写的像手册)。学习的过程中不要怕慢,自己多试试就好了,多记笔记。感慨一下,人家制作出来的东西,我们竟然要花这么多时间去学习,差距啊。另外Linux的东西还是要扎扎实实学,多少年过去了,这些知识都没怎么变!