Linux用户信息详解
Linux用户信息很丰富,存储在了多个文件中,其中包括/etc/passwd,/etc/shadow,/var/log/wtmp等文件中,因为在项目中用到了,所以有些了解。下面对这几个文件进行一个详细的介绍。
账户基本信息
文件各字段含有
/etc/passwd
存储了账户的基本信息,默认任何用户都可以读取,也是早期存储账户密码的文件,后因任何用户都可读取,造成安全问题,故后期不再用于存储。/etc/passwd
文件采用:
分割,共分为了7个字段,下面是文件中的一行。
1 | root:x:0:0:root:/root:/usr/bin/bash |
- 第一列:用户名;
- 第二列:为用户密码Flag,具体信息没有找到,根据个人推测是为了兼容早期版本,早期此字段用于存储用户密码,后期为了安全将密码放至
/etc/shadow
文件中。推测为了兼容,字段仍然保留。大部分用户此字段值为x
,表示密码保存在/etc/shadow
文件中,不是x
则就是加密后的密码; - 第三列:用户ID,这个好理解,每个用户对应一个唯一的ID,就像身份证号一样;
- 第四列:组ID,也就是用户所属组的ID了。Linux中每个用户只能在一个组中,但可以有多个附加组;
- 第五列:用户的一些描述,可能是姓名等,可以为空;
- 第六列:用户的Home目录,用于设置环境变量
$HOME
; - 第七列:用户的默认终端,如果用户被禁止登录了此字段为
/usr/bin/nologin
,只要登录就会得到This account is currently not available.
的提示。
C 语言通过函数读取
在头文件pwd.h
中的函数可以获取到/etc/passwd
文件中的账户信息。
在pwd.h
中定义了结构体passwd
,结构体内容如下:
1 | struct passwd { |
结构体中的内容与/etc/passwd
文件中的内容对应,就不详细介绍了。
头文件中也定义了一些相关的函数。
1 | struct passwd *getpwuid(uid_t); |
下面将介绍几个函数的作用:getpwuid
通过UID查找用户信息,返回passwd
的结构体;getpwnam_r
和getpwuid_r
不知道是做啥的。setpwent
、getpwent
和endpwent
是一套函数,getpwent
是用来获取一行数据,每调用一次读取指针就向下走一行,直至读完返回NULL,setpwent
将读取指针返回文件头,endpwent
将文件指针返回尾部。
账户密码信息
文件各字段含有
/etc/shadow
文件存储了账户的密码相关信息,内容还是很丰富的,与passwd
相同,使用:
分隔字段,/etc/shadow
共分成了9个字段,其中一个为保留字段。/etc/shadow
中储存了用户的密码,只用拥有root权限的用户才可以读写。
1 | root:$6$K9DgMAqih5hXEJgh$fK3s53mo/YqeZe8v1NKuKHpUPdyuHjFT/d9pM0u2xFxMVAOwjX51cCr5BEqmMaAoISd35PA/cow1q.YoiOLTH0:18193:0:99999:7::: |
上面就是/etc/shadow
文件的一行,下面我将详细介绍各个字段的含义:
- 第一列:用户名;
- 第二列:加密后的密码,这里我的密码是1。貌似没有办法破解,但是可以通过字典的方式获得;
1
2
3
4
5
6星号代表帐号被锁定,但是还是可以通过其他方式切换进去的,不同理解到底有啥用
双叹号表示这个密码已经过期了。
$6$ 开头的,表明是用SHA-512加密的,
$1$ 表明是用MD5加密的
$2$ 是用Blowfish加密的
$5$ 是用SHA-256加密的。 - 第三列:账户最后一次修改密码的时间,是自1970年1月1日以来天数;
- 第四列:自上次密码修改以来多少天内不能修改;
- 第五列:口令保持有效的最大天数,自上次密码修改以来多少天之后必须修改密码的时间;
- 第六列:警告时间,密码过期前几天提醒用户修改;
- 第七列:密码无效期,自过期以来的数天之内,密码仍然有效;
- 第八列:账户过期时间;
- 第九列:保留字段。
C 语言通过函数读取
在头文件shadow.h
中的函数可以获取到/etc/shadow
文件中的账户信息。
在shadow.h
中定义了结构体spwd
,结构体内容如下:
1 | struct spwd { |
结构体中的内容与/etc/shadow
文件中的内容对应,就不详细介绍了。
头文件中也定义了一些相关的函数。
1 | struct spwd *getspnam(const char *name); |
getspnam
函数返回一个指向结构的指针,该结构包含影子密码数据库中与用户名匹配的记录的细分字段。getspent
函数返回一个指向影子密码数据库中下一个条目的指针。输入流中的位置由setspent
初始化。完成阅读后,程序可以调用endsend
,以便可以释放资源。fgetspent
函数类似于getspent
,但使用提供的流,而不是由setpent
隐式打开的流。sgetspent
函数将提供的字符串s
解析为结构spwd
。putspent
函数以阴影密码文件格式将提供的struct spwd * p
的内容作为文本行写入流中。值为NULL的字符串条目和值为-1的数字条目被写为空字符串。lckpwdf
函数旨在防止影子密码数据库同时访问。它尝试获取锁,并在成功时返回0,或在失败时返回-1(在15秒内未获得锁)。ulckpwdf
函数再次释放锁定。请注意,没有针对直接访问影子密码文件的保护措施。只有使用lckpwdf
的程序才会注意到该锁定。
账户登录信息
账户登录信息保存在/var/log/wtmp
和/var/log/btmp
文件中,这个文件是一二进制文件,直接通过cat
打印,无过的有用信息,通过命令last
可以获取登录,通过lastb
可以获取未成功登录的信息。
C 语言通过函数读取
同样C语言也可以获取此信息。在utmp.h
文件中,定义了以下结构体吗,和一些常量:
1 | struct utmp { |
这个函数我也还有很多参数不了解,后面有机会再补上。