owner
、group
、others
/etc/passwd
文件中。个人密码则是记录在/etc/shadow
文件下。群组名称记录在/etc/group
中su root
exit
ls -al
或者ll
第1列为权限
第2列为链接,表示有多少文件名链接到此节点(i-node)
第3列为owner
第4列为group
第5列为文件大小
弟6,7,8列为文件修改日期
第9列为文件名
d
则是目录-
则是文件l
则表示为链接文件b
则表示为设备文件里面的可供储存的周边设备(可随机存取设备);c
则表示为设备文件里面的序列埠设备,例如键盘、鼠标(一次性读取设备)。rwx
组合,r
代表可读,w
代表可写,x
表达可执行。 第一组代表owner
的权限,第二组代表group
的权限,第三组代表others
的权限。例如:
-rw-r--r-- 1 root root 6 May 6 10:38 test.txt
- 第1位为
-
,表示test.txt为一个文件- 第2-4位为
rw-
,表示test.txt的owner对该文件有读写权限,但是没有执行权限- 第5-7位为
r--
,表示test.txt的group成员对该文件只有读权限,没有写和执行权限- 第8-10位为
r--
,表示test.txt的除去owner和group之外的用户对该文件只有读权限,没有写和执行权限
chgrp [-R] [groupname] [dirname/filename]
-R
表示递归修改所属群组,可以在修改目录所属群组时使用,递归将目录下所有文件的所属群组修改。
groupname
必须是在/etc/group
文件中存在的群组名,否则会报错
chown [-R] [ownername] [dirname/filename]
chown [-R] [ownername]:[groupname] [dirname/filename]
ownername
必须在/etc/passwd
文件中存在的用户名,否则会报错
chmod [-R] xyz [dirname/filename]
r -> 4
、w -> 2
、x -> 1
。上述test.txt文件中owner权限为rw-
,其权值为6,group和others权限都为r--
,权值都为4,故用权值的形式表达test.txt文件为644
u
、g
、o
符号来代表owner、group、others上述用
chmod 777 test.txt
之后可以看到test.txt的文件权限变为了-rwxrwxrwx
+
、-
给对应用户添加、删除权限
- 使用
chmod u=rw,go=rw test.txt
后,可以看到test.txt文件权限变为-rw-rw-rw-
,说明可以直接使用u|g|o = r|w|x
的方式直接修改文件权限- 使用
chmod u+x,go-w test.txt
后,可以看到test.txt文件权限变为-rwxr--r--
,说明可以直接使用u|g|o +|- r|w|x
的方式直接给指定身份添加或删除文件权限- 使用
chomod a-x test.txt
后,可以看到test.txt文件权限变为-rw-r--r--
,这里a
代表的是所有用户的意思,所以直接将owner、group、others的权限都删去了x权限。
文件类型 | 内容 | r | w | x |
---|---|---|---|---|
文件 | 详细数据data | 读取文件内容 | 修改文件内容 | 执行文件 |
目录 | 文件名 | 读到文件名 | 修改文件名,以及目录中内容 | 进入目录 |
r
权限,则即使有x
权限进入了目录,使用ls
命令也是会报permission deny
错误上图中,我们为zean用户,对test目录权限为
--x
,所以执行cd test
成功,但是在目录中执行ls
失败
w
权限,则无法在目录中添加、删除文件上图中为zean用户,对test目录权限为
r-x
,没有写权限,所以执行cd test
和ls
成功,但是在用echo hello > b.txt
创建b.txt文件时失败,rm a.txt
删除a.txt时失败。
在目录中添加文件和删除文件,需要的是wx
权限
将test权限设置为
777
之后,zean用户就可以在目录中添加或删除文件
umask
命令查看文件的默认权限,文件默认权限的意思是:当前用户创建文件时,文件拥有的权限。umask
命令后,会输出4个数字,第一个数字是给特殊权限用的,后面三个数字分别是owner、group、others对应的权限。且是以减分的方式,数字0代表权值7,即7-7=0;数字2代表权值5,即7-5=2rwxr-xr-x
;zean普通用户创建文件的默认权限权值为775,即rwxrwxr-x
可以看到,通过root用户创建的目录,权限为
drwxr-xr-x
通过zean普通用户创建的目录,权限为drwxrwxr-x
umask -S
打印符号形式的默认权限umask xyz
修改文件默认权限chattr [+-=][ASacdistu] [dirname\filename]
来设置隐藏属性。其中+
表示添加,-
表示删除,=
表示直接设置,后面的[ASacdistu]
是想要设置的属性
- A :设置该属性后,当你有存取此文件(或目录)时,他的存取时间 atime将不会被修改, 可避免 I/O 较慢的机器过度的存取磁盘。(目前建议使用文件系统挂载参数处理这个项目) 可以从下图看到,在添加A属性后,使用
cat a.txt
读取文件,并不会修改它的存取时间。移除A属性后,再使用cat a.txt
读取文件,发现存取时间发生了改变。
- S :一般文件是非同步写入磁盘的,加上 S 这个属性后, 当你进行任何文件的修改,修改会“同步”写入磁盘中。
- a :当设置 a 之后,这个文件将只能增加数据,而不能删除也不能修改数据,只有root 才能设置这属性 。从下图看出,添加a属性后,使用
echo hello > a.txt
覆盖文件内容失败。但是使用echo hello >> a.txt
在文件末尾添加内容添加成功。在移除a属性后,使用echo hello > a.txt
覆盖文件内容成功
- c :这个属性设置之后,将会自动的将此文件“压缩”,在读取的时候将会自动解压缩, 但是在储存的时候,将会先进行压缩后再储存
- d :当 dump 程序被执行的时候,设置 d 属性的文件(或目录)不会被 dump 备份
- i :设置该属性后,可以让该文件“不能被删除、改名、设置链接也无法写入或新增数据!”只有 root 能设置此属性 。下图中,给a.txt添加i属性后,执行
echo hello > a.txt
、echo hello >> a.txt
、rm a.txt
均失败,即无法修改、添加、删除文件。移除i属性后,使用echo hello > a.txt
成功。
- s :当文件设置了 s 属性后,如果这个文件被删除,他将会被完全的移除出这个硬盘空间, 所以如果误删了,无法恢复
- u :与 s 相反的,当使用 u 来设置文件时,如果该文件被删除了,则数据内容其实还存在磁盘中, 故有办法恢复
注意:属性设置常见的是 a 与 i 的设置值,而且很多设置值必须要身为 root 才能设置
lsattr [-adR] [dirname\filename]
来查看隐藏属性
-a
:将隐藏文件的属性也显示出俩-d
:如果接的是目录,仅列出目录本身的属性而非目录内的文件名-R
:连同子目录的属性也一并列出来-rwsr-xr-x
,此时称为Set UID,简称为SUID特殊权限。它的限制和功能为:
举例:
/etc/shadow
文件中存放的是用户密码,权限为rw-r-----
,所以只有root用户才可以写。
- 但是作为zean这个普通用户来说,应该有权利修改自己的密码。而在linux中修改密码一般用
passwd
命令。来看看passwd
命令对应二进制文件的权限
- 可以看到
/usr/bin/passwd
权限为rwsr-xr-x
,zean用户对其有执行权限,owner中x标志位位置为s,所以zean在执行passwd
命令时,会获得和owner一样的权限,即提权为root。这样,zean普通用户就可以修改自己的密码了。几个关键点:
- zean 对于 /usr/bin/passwd 这个程序来说是具有 x 权限的,表示 zean 能执行 passwd
- passwd 的拥有者是 root 这个帐号;
- zean 执行 passwd 的过程中,会“暂时”获得 root 的权限;
- /etc/shadow 就可以被 zean 所执行的 passwd 所修改。
可以看到,tmp目录设置了SBIT,使用root用户创建a.txt后,修改a.txt的权限为777,切换到zean用户,执行rm a.txt
失败
可以看到,在没有设置SBIT权限的目录中,创建文件并设置为777权限之后,非创建者也可以删除该文件。
chmod xyz
既可,要设置特殊权限,只需要在这三个数字前面再加上一个数字既可。SUID -> 4
,SGID -> 2
,SBIT -> 1
因为所有用户都没有执行权限x,故对其设置SUID/SGID/SBIT是无效的
struct stat {
mode_t st_mode; // 文件模式,包含权限位和文件类型
ino_t st_ino; // inode节点号
dev_t st_dev; // 设备号
dev_t st_rdev; // 特殊设备号
nlink_t st_nlink; // 链接数
uid_t st_uid; // 文件owner的用户id
gid_t st_gid; // 文件所属群组的群组id
off_t st_size; // 文件大小,以Byte为单位
time_t st_atime; // 文件最近存取时间
time_t st_mtime; // 文件最近修改时间
time_t st_ctime; // 文件创建时间
blksize_t st_blksize; // 块大小
blkcnt_t st_blocks; // 分配的磁盘块数量
}
stat
、fstat
、lstat
函数获得#include
//通过文件路径pathname,获得该文件的stat,并将获得的stat结构体存入buf中
int stat(const char* restrict pathname, struct stat* restrict buf);
//通过文件描述符获取文件stat
int fstat(int filedes, struct stat* buf);
//通过文件路径pathname获取stat,但是该文件需是一个符号链接
int lstat(const char* restrict pathname, struct stat* restrict buf);
mode | 说明 |
---|---|
S_ISUID S_ISGID S_ISVTX |
set UID标志 set GID标志 sticky BIT标志 |
S_IRWXU S_IRUSR S_IWUSR S_IXUSR |
owner读、写、执行权限 owner读权限 owner写权限 owner执行权限 |
S_IRWXG S_IRGRP S_IWGRP S_IXGRP |
group读、写、执行权限 group读权限 group写权限 group执行权限 |
S_IRWXO S_IROTH S_IWOTH S_IXOTH |
others读、写、执行权限 others读权限 others写权限 others执行权限 |
&
运算符,例如:当st_mode & S_IRUSR
等于1时,说明该文件的owner具有读权限。实际用户ID 实际组ID |
实际上是谁 |
---|---|
有效用户ID 有效组ID 附加组ID |
用于文件访问权限检查 |
保存的设置用户ID 保存的设置组ID |
由exec函数保存 |
例如:
- 为打开
/usr/include/stdio.h
文件,需对目录/
、/usr
、/usr/include
具有执行权限。对于stdio.h
需要具有对文件本身适当权限,取决于以何种模式打开(只读、读-写等)- 若当前目录就是
/usr/include
,那么为打开stdio.h
,需要对当前目录有执行权限。
open
函数的O_RDONLY
和O_RDWR
标志相关。open
函数的O_WDONLY
和O_RDWR
标志相关open
函数指定O_TRUNC
标志时,进程对该文件需具有写权限open
或create
创建新文件时,新文件的owner ID设置为进程的有效用户IDmkdir
创建目录,新目录的所有权规则和创建新文件规则相同access
函数是按实际用户ID和实际组ID进行访问权限测试的。(和有效用户ID和有效组ID、保存用户ID和保存组ID区分开)#include
//成功返回0,失败返回-1
int access(const char* pathname, int mode);
mode | 说明 |
---|---|
R_OK | 测试读权限 |
W_OK | 测试写权限 |
X_OK | 测试执行权限 |
F_OK | 测试文件是否存在 |
#include
#include
#include
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("Usage: %s \n" , argv[0]);
return 0;
}
// 测试文件是否存在
if (access(argv[1], F_OK) < 0) {
printf("%s access F_OK fail\n", argv[1]);
}else {
printf("%s is exist\n", argv[1]);
}
// 测试进程对文件是否有读权限
if (access(argv[1], R_OK) < 0) {
printf("%s access R_OK fail\n", argv[1]);
}else {
printf("%s read access OK\n", argv[1]);
}
// 测试进程是否可以以读模式打开文件
if (open(argv[1], O_RDONLY) < 0) {
printf("%s open read fail\n", argv[1]);
}else {
printf("open for reading OK\n");
}
}
test.txt
的文件权限为rwxrwxrwx
,所以运行程序读取test.txt时是可以正确读取打印的。
/etc/shadow
文件权限是rw-r-----
,所以用zean用户运行程序对该文件没有读取权限,故会显示access fail
、open fail
umask
函数为进程设置创建文件时默认权限屏蔽字,并返回以前值#include
// 返回值:以前文件模式的默认权限屏蔽字
mode_t umask(mode_t cmask);
#include
#include
#include
#include
// rw-rw-rw-权限
#define RW_RW_RW_ (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
int main() {
// 设置默认权限屏蔽字为000
umask(0);
if (creat("foo", RW_RW_RW_) < 0) {
fprintf(stderr, "create error for foo\n");
}else {
fprintf(stdout, "create foo success\n");
}
// 设置默认权限屏蔽字为066
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (creat("bar", RW_RW_RW_) < 0) {
fprintf(stderr, "create error for bar\n");
}else {
fprintf(stdout, "create bar success\n");
}
}
可以看到用户一开始的umask为002;使用
umask
函数将默认权限屏蔽字设置为0,即不屏蔽任何权限,所以以rw-rw-rw-
权限设置创建foo
,使用ls -l
查看其权限也是rw-rw-rw-
使用umask
函数将默认权限屏蔽字设置为066后,屏蔽group和others的读写权限。所以以rw-rw-rw-
权限设置创建bar
,使用ls -l
查看其权限变为rw-------
,group和others的读写权限被屏蔽。
从运行umasktest程序的前后两次调用
umask
命令可以看出:更改进程的默认权限屏蔽字,并不会影响父进程(这里是shell)的默认权限屏蔽字。
#include
// 根据文件名
int chmod(const char* pathname, mode_t mode);
// 根据文件描述符
int fchmod(int filedes, mode_t mode);
#include
#include
int main() {
struct stat statbuf;
// 获取foo文件的stat结构体
if (stat("foo", &statbuf) < 0){
fprintf(stderr, "stat error for foo\n");
return 0;
}
// 将foo文件的group执行权限取消,并设置Set GID权限
// st_mode中包含了文件原来的权限信息
if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0) {
fprintf(stderr, "chmod error for foo\n");
}else {
fprintf(stdout, "chmod foo success\n");
}
// 将bar文件权限设置为rw-r--r--
if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
fprintf(stderr, "chmod error for bar\n");
}else {
fprintf(stdout, "chmod bar success\n");
}
}
可以注意到,ls命令列出的时间和日期并没有改变。因为chmod函数更新的是i节点最近一次被更改时间,系统默认
ls -l
显示的是最后修改文件内容时间
#include
// 以文件名设置
int chown(const char* pathname, uid_t owner, gid_t group);
// 以文件描述符设置
int fchown(int filedes, uid_t owner, gid_t group);
// 指定文件需是链接文件,只改变符号链接本身,不改变符号链接所指向文件
int lchown(const char* pathname, uid_t owner, gid_t group);
若两个参数owner或group中任意一个是-1,则对应ID不变
_POSIX_CHOWN_RESTRICTED
定义在头文件
中,其作用:
chown
函数参数owner
等于-1或文件用户ID,并且参数group等于进程的有效组ID或进程的附加组ID之一时才可以更改文件组ID
_POSIX_CHOWN_RESTRICTED
是否有作用,由文件系统决定。当_POSIX_CHOWN_RESTRICTED
起作用时,不能更改其他用户文件的用户ID。可以更改你所拥有的文件组ID,但只能改到当前进程用户所属的组。
参考资料:
《UNIX环境高级编程》
《鸟哥 Linux 私房菜:基础版》