目录
1 文件属主
1.1 文件属主概念
1.2 如何查看文件属主
1.3 有效用户 ID 和有效组 ID
2 chown 函数
2.1 chown命令
2.2 chown函数
2.3 getuid 和 getgid函数
3 fchown函数
3.1 fchown函数简介
3.2 示例代码
4 lchown函数
1 文件属主
1.1 文件属主概念
Linux 是一个支持多用户操作的系统,它允许多个用户在同一台机器上工作,而每个文件都与特定的用户和用户组相关联,通过这个信息可以判断文件的所有者和所属组。
文件所有者指的是文件的拥有者,即文件属于哪个用户。通常,文件在创建时,其所有者就是创建它的用户。例如,如果当前登录用户为 ***,通过 touch
命令创建了文件,那么文件的所有者就是 ***。同样,当程序通过 open
函数创建新文件时,文件的所有者将是执行该程序的用户。
文件所属组则指明了文件属于哪个用户组。Linux 系统通过用户 ID(UID)和组 ID(GID)来识别用户和用户组,而不是通过用户名或组名。每个用户和用户组都被分配了一个唯一的 ID,系统通过这些 ID 来管理权限和访问控制。
用户 ID 简称 UID、用户组 ID 简称 GID, 这些都是 Linux 操作系统的基础知识,
1.2 如何查看文件属主
可以使用 ls 命令或 stat 命令便可以查看到文件的所有者和所属组,如下所示:
文件的用户 ID 和组 ID 分别由 struct stat 结构体中的 st_uid 和 st_gid 所指定。 既然 Linux 下的每一个文件都有与之相关联的用户 ID 和组 ID,那么对于一个进程来说亦是如此,与一个进程相关联的 ID 有很多:
- 实际用户 ID 和实际组 ID 标识该进程的用户是谁、以及该用户对应的所属组; 实际用户 ID 和实际组 ID 确定了进程所属的用户和组。
- 进程的有效用户 ID、有效组 ID 以及附属组 ID 用于文件访问权限检查。
1.3 有效用户 ID 和有效组 ID
首先对于有效用户 ID 和有效组 ID 来说,这是进程里面的概念,文件来并无此属性!有效用户 ID 和有效组 ID 是操作系统层面,用于给操作系统判断当前执行该进程的用户在当前环境下对某个文件是否拥有相应的权限。
在 Linux 系统中,当进程对文件进行读写操作时,系统首先会判断该进程是否具有对该文件的读写权限,那如何判断呢?自然是通过该文件的权限位来判断, struct stat 结构体中的 st_mode 字段中就记录了该文件的权限位以及文件类型。
当进行权限检查时,并不是通过进程的实际用户和实际组来参与权限检查的,而是通过有效用户和有效组来参与文件权限检查。 通常, 绝大部分情况下,进程的有效用户等于实际用户(有效用户 ID 等于实际用户 ID) ,有效组等于实际组(有效组 ID 等于实际组 ID) 。
2 chown 函数
2.1 chown命令
chown 是一个系统调用,该系统调用可用于改变文件的所有者(用户 ID)和所属组(组 ID) 。其实在Linux 系统下也有一个 chown 命令,该命令的作用也是用于改变文件的所有者和所属组,例如将文件的所有者和所属组修改为 root:
通过chown 该命令确实可以改变文件的所有者和所属组,这个命令内部其实就是调用了chown 函
数来实现功能的, chown 函数原理如下所示。
2.2 chown函数
chown
函数在编程中使用的一个系统调用,用于改变文件或目录的用户和组所有权,chown
函数的原型如下:
#include <sys/types.h>
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
path
: 要改变所有权的文件或目录的路径。owner
: 新的所有者的用户 ID (UID)。group
: 新的组的组 ID (GID)。
虽然该函数用法很简单,但是有以下两个限制条件:
- 只有超级用户进程能更改文件的用户 ID;
- 普通用户进程可以将文件的组 ID 修改为其所从属的任意附属组 ID,前提条件是该进程的有效用户 ID 等于文件的用户 ID;而超级用户进程可以将文件的组 ID 修改为任意值。
所以,由此可知,文件的用户 ID 和组 ID 并不是随随便便就可以更改的,其实这种设计是为系统安全着想,如果系统中的任何普通用户进程都可以随便更改系统文件的用户 ID 和组 ID,那么也就意味着任何普通用户对系统文件都有任意权限了,这对于操作系统来说将是非常不安全的。
下面是一个简单的 C 语言示例程序,演示如何使用 chown
函数来改变文件的所有者和组。这个示例程序尝试将指定文件的所有者和组更改为特定的用户 ID 和组 ID。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc, char *argv[]) {
// 检查命令行参数数量
if (argc != 4) {
fprintf(stderr, "Usage: %s <file> <owner> <group>\n", argv[0]);
return 1;
}
const char *file = argv[1]; // 文件路径
uid_t owner = atoi(argv[2]); // 新的所有者用户 ID
gid_t group = atoi(argv[3]); // 新的组 ID
// 使用 chown 函数改变文件的所有者和组
if (chown(file, owner, group) == -1) {
// 如果 chown 失败,打印错误消息
perror("chown failed");
return 1;
}
printf("Ownership of '%s' changed to owner %d, group %d\n", file, owner, group);
return 0;
}
程序接收三个命令行参数:要改变所有权的文件的路径,新的所有者的用户 ID,以及新的组 ID。使用 atoi
函数将用户和组 ID 的字符串转换为整数。使用 chown
函数尝试改变文件的所有权。如果 chown
函数调用失败,perror
函数将打印错误消息,程序返回 1。如果成功,程序将打印一条消息,表明所有权已更改。运行结果如下:
2.3 getuid 和 getgid函数
在 Linux 系统下,可以使用 getuid 和 getgid 两个系统调用分别用于获取当前进程的用户 ID 和用户组ID,这里说的进程的用户 ID 和用户组 ID 指的就是进程的实际用户 ID 和实际组 ID,这两个系统调用函数原型如下所示:
#include <unistd.h>
uid_t getuid(void);
- 返回值:返回当前进程的实际用户 ID。如果发生错误,返回 -1 并设置
errno
。
#include <unistd.h> gid_t getgid(void);
- 返回值:返回当前进程的实际组 ID。如果发生错误,返回 -1 并设置
errno
。
下面是一个简单的示例,展示如何使用 getuid
和 getgid
函数:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
uid_t my_uid = getuid();
gid_t my_gid = getgid();
printf("Current User ID: %d\n", my_uid);
printf("Current Group ID: %d\n", my_gid);
return 0;
}
程序运行结果如下:
3 fchown函数
3.1 fchown函数简介
fchown
用于改变一个打开文件描述符的所有权。这个函数允许你更改文件的用户 ID (owner) 和组 ID (group),而不需要知道文件的路径名。fchown
函数的原型如下:
#include <unistd.h>
int fchown(int fd, uid_t owner, gid_t group);
fd
: 要改变所有权的文件的文件描述符。owner
: 新的所有者的用户 ID (UID)。group
: 新的组的组 ID (GID)。
3.2 示例代码
下面是一个使用 fchown
函数的示例程序:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
int main() {
int fd = open("example.txt", O_RDONLY); // 打开文件以读取模式
if (fd == -1) {
perror("open");
return 1;
}
uid_t new_uid = 1000; // 新用户 ID
gid_t new_gid = 1000; // 新组 ID
if (fchown(fd, new_uid, new_gid) == -1) {
perror("fchown");
close(fd);
return 1;
}
printf("Changed ownership of file descriptor %d to owner %d, group %d\n", fd, new_uid, new_gid);
close(fd); // 关闭文件描述符
return 0;
}
程序首先打开一个名为 "example.txt" 的文件,然后尝试使用 fchown
函数改变该文件的所有权。运行结果如下:
4 lchown函数
lchown
函数用于改变一个符号链接的所有者和组。与 chown
不同,lchown
专门用于符号链接,即使符号链接指向的目标文件的所有权被更改,lchown
也会更改符号链接本身的所有者和组。lchown
函数的原型如下:
#include <unistd.h>
int lchown(const char *path, uid_t owner, gid_t group);
path
: 符号链接的路径。owner
: 新的所有者的用户 ID (UID)。group
: 新的组的组 ID (GID)。