当前位置: 首页 > news >正文

UNIX下C语言编程与实践21-UNIX 文件访问权限控制:st_mode 与权限宏的解析与应用

从 st_mode 位结构到 C 语言编程,掌握 UNIX 文件权限的判断与控制逻辑

一、核心基础:st_mode 中的权限位结构

在 UNIX 系统中,文件的访问权限存储在 struct stat 结构体的 st_mode 字段中。该字段是 32 位无符号整数,其中低 9 位专门用于标识文件的访问权限,对应“所有者(owner)、组用户(group)、其他用户(other)”三类主体,每类主体拥有“读(r)、写(w)、执行(x)”三种权限,形成“3类主体×3种权限”的 9 位权限体系。

1. st_mode 权限位的具体分布

st_mode 权限位分布

文件或目录的权限在 st_mode 中按位分布,具体如下:

所有者(Owner)权限

  • 读(r):第 8 位(值为 0400)
  • 写(w):第 7 位(值为 0200)
  • 执行(x):第 6 位(值为 0100)
    权限位范围:第 9-7 位(实际计算时,S_IRUSRS_IWUSRS_IXUSR 分别对应 0400、0200、0100)

组用户(Group)权限

  • 读(r):第 5 位(值为 0040)
  • 写(w):第 4 位(值为 0020)
  • 执行(x):第 3 位(值为 0010)
    权限位范围:第 6-4 位(S_IRGRPS_IWGRPS_IXGRP 分别对应 0040、0020、0010)

其他用户(Other)权限

  • 读(r):第 2 位(值为 0004)
  • 写(w):第 1 位(值为 0002)
  • 执行(x):第 0 位(值为 0001)
    权限位范围:第 3-1 位(S_IROTHS_IWOTHS_IXOTH 分别对应 0004、0002、0001)

特殊权限位

  • 粘滞位(sticky):第 9 位(S_ISVTX,值为 01000)
  • 设置组 ID(setgid):第 10 位(S_ISGID,值为 02000)
  • 设置用户 ID(setuid):第 11 位(S_ISUID,值为 04000)

示例(八进制表示)

  • 755(rwxr-xr-x):S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH(0400|0200|0100|0040|0010|0004|0001)
  • 644(rw-r--r--):S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH(0400|0200|0040|0004)

可通过位运算检查权限,如:

if (st.st_mode & S_IRUSR) {// 用户可读  
}

权限位标识规则:某一位为 1 表示拥有对应权限,为 0 表示无该权限。例如,所有者拥有读、写权限,无执行权限,对应的 3 位权限位为 110(二进制)。

2. 权限宏定义:判断权限的标准工具

UNIX 系统在 <sys/stat.h> 头文件中定义了 9 个基础权限宏,每个宏对应一个具体的权限位。通过“st_mode & 权限宏”的位与运算,可判断文件是否拥有对应权限(结果非 0 表示拥有权限,0 表示无权限)。

权限宏对应权限主体类型八进制值功能说明
S_IRUSR读(r)所有者(Owner)0400判断所有者是否拥有读权限
S_IWUSR写(w)所有者(Owner)0200判断所有者是否拥有写权限
S_IXUSR执行(x)所有者(Owner)0100判断所有者是否拥有执行权限(文件)或进入权限(目录)
S_IRGRP读(r)组用户(Group)0040判断组用户是否拥有读权限
S_IWGRP写(w)组用户(Group)0020判断组用户是否拥有写权限
S_IXGRP执行(x)组用户(Group)0010判断组用户是否拥有执行/进入权限
S_IROTH读(r)其他用户(Other)0004判断其他用户是否拥有读权限
S_IWOTH写(w)其他用户(Other)0002判断其他用户是否拥有写权限
S_IXOTH执行(x)其他用户(Other)0001判断其他用户是否拥有执行/进入权限
### 权限宏的使用逻辑判断文件是否对所有者开放写权限,可使用以下代码:
```c
if (st_mode & S_IWUSR) { ... }

若需同时判断所有者的读和写权限,可使用位或运算组合多个权限宏:

if (st_mode & (S_IRUSR | S_IWUSR)) { ... }

二、C 语言实战:实现文件权限解析函数

通过编写 C 语言程序,结合 lstat 函数(避免符号链接干扰)和权限宏,可实现类似 ls -l 命令的权限字符串生成功能(如 rw-r--r--)。以下以“GetFileMode 函数”为例,演示完整实现流程。

1. 完整程序实现:解析权限并生成权限字符串

程序功能:接收文件路径,调用 lstat 获取 st_mode,通过权限宏判断各类用户的权限,生成 10 位权限字符串(第 1 位为文件类型标识,后 9 位为权限标识)。

以下是对代码的整理和优化版本,修复了格式问题并增强了可读性:

文件权限查看工具代码整理

#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* 获取文件类型标识 */
char GetFileType(mode_t st_mode) {if (S_ISDIR(st_mode)) return 'd';if (S_ISCHR(st_mode)) return 'c';if (S_ISBLK(st_mode)) return 'b';if (S_ISREG(st_mode)) return '-';if (S_ISFIFO(st_mode)) return 'p';if (S_ISLNK(st_mode)) return 'l';if (S_ISSOCK(st_mode)) return 's';return '?';
}/* 解析 st_mode 生成权限字符串 */
void GetFileMode(mode_t st_mode, char *mode_str) {memset(mode_str, '-', 10);mode_str[10] = '\0';mode_str[0] = GetFileType(st_mode);if (st_mode & S_IRUSR) mode_str[1] = 'r';if (st_mode & S_IWUSR) mode_str[2] = 'w';if (st_mode & S_IXUSR) mode_str[3] = 'x';if (st_mode & S_IRGRP) mode_str[4] = 'r';if (st_mode & S_IWGRP) mode_str[5] = 'w';if (st_mode & S_IXGRP) mode_str[6] = 'x';if (st_mode & S_IROTH) mode_str[7] = 'r';if (st_mode & S_IWOTH) mode_str[8] = 'w';if (st_mode & S_IXOTH) mode_str[9] = 'x';
}int main(int argc, char *argv[]) {if (argc != 2) {fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);exit(EXIT_FAILURE);}struct stat file_stat;if (lstat(argv[1], &file_stat) == -1) {perror("lstat error");exit(EXIT_FAILURE);}char mode_str[11];GetFileMode(file_stat.st_mode, mode_str);printf("Custom Mode: %s %s\n", mode_str, argv[1]);printf("ls -l Mode: ");char cmd[256];snprintf(cmd, sizeof(cmd), "ls -l %s | awk '{print $1, $9}'", argv[1]);system(cmd);return EXIT_SUCCESS;
}

主要改进点

  1. 删除多余的分号和空行
  2. 规范化注释格式,使用/* */代替//
  3. 对齐代码块和条件语句
  4. 修复了命令字符串缓冲区的大小声明
  5. 保持了原有的功能逻辑不变

使用说明

编译并运行程序,传入文件路径作为参数:

gcc -o filemode filemode.c
./filemode /path/to/file

程序会输出自定义解析的文件权限字符串,并与系统ls -l命令的输出进行对比验证。

2. 程序编译与多场景测试

将代码保存为 fileperm.c,编译后对不同权限设置的文件进行测试,验证权限解析的正确性。测试前需准备不同权限的文件(通过 chmod 命令修改)。

步骤 1:编译程序

gcc fileperm.c -o fileperm

步骤 2:测试 1:普通文件(权限 644,即 rw-r--r--)
# 创建测试文件并设置权限 644
touch test644.txt
chmod 644 test644.txt# 运行程序
./fileperm test644.txt
Custom Mode: -rw-r--r-- test644.txt
ls -l Mode: -rw-r--r-- test644.txt

结果验证:程序生成的权限字符串与 ls -l 完全一致,正确识别所有者读/写、组用户读、其他用户读的权限。

步骤 3:测试 2:目录文件(权限 755,即 rwxr-xr-x)

创建测试目录并设置权限 755

mkdir testdir755
chmod 755 testdir755

运行程序

./fileperm testdir755

输出内容:

Custom Mode: drwxr-xr-x testdir755

验证权限

ls -l

输出内容:

Mode: drwxr-xr-x testdir755

结果验证:权限字符串首字符为 'd'(目录标识),权限位为 rwxr-xr-x,与 ls -l 一致,正确识别目录的执行权限(进入目录的权限)。

步骤 4:测试 3:无任何权限的文件(权限 000)

创建测试文件并设置权限 000

touch test000.txt
chmod 000 test000.txt

运行程序(需 root 权限,否则 lstat 可能因权限不足失败)

sudo ./fileperm test000.txt

Custom Mode

----------
test000.txt

ls -l Mode

----------
test000.txt

结果验证:权限字符串全为 '-',正确识别无任何权限的文件,验证了程序对极端权限场景的处理能力。

步骤 5:测试 4:符号链接文件(权限不生效,仅作展示)

# 创建符号链接(符号链接的权限位不实际生效,仅继承目标文件权限) ln -s test644.txt link.txt chmod 777 link.txt // 符号链接权限修改无效 # 运行程序 ./fileperm link.txt

Custom Mode: lrw-r--r-- link.txt ls -l Mode: lrwxrwxrwx link.txt -> test644.txt

结果分析:程序通过 lstat 获取符号链接本身的 st_mode,权限位为 rw-r--r--;而 ls -l 显示符号链接权限为 lrwxrwxrwx(默认显示),但实际访问权限由目标文件(test644.txt)决定。这一差异验证了“符号链接权限不生效”的特性,程序处理逻辑正确。

三、文件权限的作用与安全风险

UNIX 文件权限的核心作用是“控制不同用户对文件的操作范围”,通过精细化的权限设置,可实现数据的安全隔离。但权限设置不当会带来严重的安全风险,以下从权限作用和风险两方面展开。

1. 不同类型文件的权限含义

普通文件和目录文件的权限含义存在差异,需根据文件类型理解权限的实际作用:

权限类型普通文件(如 .txt、.c)目录文件(如 /home、/etc)
读(r)可读取文件内容(如 catless可列出目录内的文件/子目录(如 ls
写(w)可修改文件内容(如 vimecho)、删除文件可在目录内创建/删除文件/子目录(如 touchrm)、修改文件名
执行(x)可执行文件(如 ./a.out/bin/ls),仅对可执行文件有效可进入目录(如 cd),是访问目录内文件的前提(无 x 权限时,即使有 r 权限也无法访问文件)

目录权限的关键认知:对目录而言,“执行权限(x)”是基础——若用户对目录无 x 权限,即使拥有 r 权限,也无法通过 cd 进入目录,更无法访问目录内文件;若用户对目录有 x 权限但无 r 权限,可进入目录,但无法通过 ls 列出目录内容(需知道具体文件名才能访问)。

2. 权限设置不当的安全风险

风险场景权限设置可能后果安全建议
敏感文件开放写权限/etc/passwd 设置为 666(rw-rw-rw-)普通用户可修改密码文件,添加恶意用户或篡改账号信息,导致系统被入侵系统敏感文件(/etc/passwd、/etc/shadow)权限设为 644 或更严格(/etc/shadow 设为 000,仅 root 可访问)
目录开放过高写权限/home/user 设置为 777(rwxrwxrwx)其他用户可在目录内创建恶意文件(如后门程序)、删除用户数据,导致数据丢失或系统被控制个人目录权限设为 755(rwxr-xr-x),禁止其他用户写权限;公共目录(如 /tmp)可设为 1777(添加 Sticky Bit,见第五节)
可执行文件开放写权限/bin/bash 设置为 777(rwxrwxrwx)普通用户可篡改系统命令,植入恶意代码(如执行 bash 时触发后门),导致系统被劫持系统可执行文件(/bin、/sbin 下文件)权限设为 755,禁止普通用户写权限;用户自定义可执行文件设为 700 或 755
无执行权限的脚本文件shell 脚本 test.sh 设置为 644(rw-r--r--)用户无法通过 ./test.sh 执行脚本(需通过 bash test.sh 间接执行),影响使用效率可执行脚本文件权限设为 755(所有者可修改、执行,其他用户可执行)或 700(仅所有者可操作)

四、常见权限问题与解决方法

在使用文件权限的过程中,常因权限宏使用错误、权限继承不当等导致问题。以下是高频问题及对应的解决方法,覆盖开发和运维场景。

常见问题问题现象原因分析解决方法
权限宏使用错误(位运算逻辑错误)权限判断结果始终为假或始终为真,如“明明有读权限却判断为无权限”1. 误将“位与(&)”用成“等于(==)”,如 st_mode == S_IRUSR(仅当 st_mode 等于 0400 时成立,忽略其他权限位);
2. 遗漏头文件 <sys/stat.h>,权限宏未定义,编译时被当作普通变量(值为 0)
1. 严格使用“st_mode & 权限宏”判断权限,如 if (st_mode & S_IRUSR)
2. 确保包含 <sys/stat.h>,编译时添加 -Wall 选项(gcc -Wall fileperm.c -o fileperm),检测未定义宏的警告
权限不足导致无法读写文件执行 cat test.txt 提示“Permission denied”,或 vim test.txt 提示“无法打开文件进行写入”1. 当前用户对文件无对应权限(如读文件需 r 权限,写文件需 w 权限);
2. 当前用户对文件所在目录无 x 权限(无法进入目录,即使对文件有权限也无法访问)
1. 查看文件权限:ls -l test.txt,查看当前用户是否属于所有者/组用户;
2. 查看目录权限:ls -ld $(dirname test.txt),确保有 x 权限;
3. 修改权限:chmod u+r test.txt(给所有者加读权限),或 chmod o+x 目录名(给其他用户加目录进入权限)
chmod 命令修改权限不生效执行 chmod 777 link.txt 后,ls -l 显示符号链接权限仍为 lrwxrwxrwx,或修改普通文件权限后权限无变化1. 操作对象是符号链接:符号链接的权限位不实际生效,修改权限仅改变显示,实际权限由目标文件决定;
2. 文件设置了 immutable 属性:通过 chattr +i test.txt 设置后,无法修改权限(需 root 权限)
1. 符号链接:无需修改其权限,直接修改目标文件权限(chmod 777 test644.txt);
2. immutable 属性:执行 chattr -i test.txt 移除属性后,再修改权限
新建文件/目录的权限不符合预期执行 touch newfile.txt 后,权限为 600 而非预期的 644,或 mkdir newdir 权限为 700 而非 755用户的 umask 配置影响新建文件/目录的默认权限——默认权限 = 基础权限 - umask;
基础权限:普通文件 666,目录 777;若 umask 为 077,新建文件权限为 666-077=600,目录为 777-077=700
1. 查看当前 umask:umask
2. 临时修改 umask:umask 022(新建文件权限 644,目录 755);
3. 永久修改 umask:编辑 ~/.bashrc 或 /etc/profile,添加 umask 022,重启终端生效

五、拓展:SUID、SGID、Sticky Bit 特殊权限

除了 9 位基础权限,UNIX 还支持三种特殊权限:SUID(Set User ID)SGID(Set Group ID)Sticky Bit(粘滞位)。这些特殊权限存储在 st_mode 的高 3 位(14-12 位),用于实现特殊的权限控制逻辑,如“执行文件时临时获取所有者权限”。

1. 特殊权限的作用与设置

特殊权限st_mode 位符号标识作用说明设置命令(八进制/符号)典型应用场景
SUID14 位s(所有者 x 位替换为 s)用户执行该文件时,临时获取文件所有者的权限(仅对可执行文件有效)chmod 4755 file
chmod u+s file
/bin/passwd(普通用户执行时临时获取 root 权限,修改 /etc/shadow)
SGID13 位s(组用户 x 位替换为 s)1. 对可执行文件:用户执行时临时获取文件所属组的权限;
2. 对目录:目录内新建文件的所属组继承目录的所属组(而非用户的主组)
chmod 2755 file/dir
chmod g+s file/dir
共享目录(如 /var/www):确保新建文件属于 www 组,便于组内用户协作
Sticky Bit12 位t(其他用户 x 位替换为 t)仅对目录有效:用户仅能删除自己创建的文件,无法删除其他用户在该目录下的文件chmod 1777 dir
chmod o+t dir
/tmp(公共临时目录):防止普通用户删除其他用户的临时文件

2. 特殊权限的程序识别(拓展 GetFileMode 函数)

修改前文的 GetFileMode 函数,添加特殊权限的识别逻辑,使权限字符串能显示 s 和 t 标识:

整理后的代码格式

void GetFileMode(mode_t st_mode, char *mode_str) {memset(mode_str, '-', 10);mode_str[10] = '\0';mode_str[0] = GetFileType(st_mode);// 基础权限判断if (st_mode & S_IRUSR) mode_str[1] = 'r'; if (st_mode & S_IWUSR) mode_str[2] = 'w'; if (st_mode & S_IXUSR) mode_str[3] = 'x';// ... 其他基础权限判断 ...// 新增:特殊权限判断// 1. SUID:所有者 x 位为 s,无 x 权限则为 Sif (st_mode & S_ISUID) {mode_str[3] = (st_mode & S_IXUSR) ? 's' : 'S';}// 2. SGID:组用户 x 位为 s,无 x 权限则为 Sif (st_mode & S_ISGID) {mode_str[6] = (st_mode & S_IXGRP) ? 's' : 'S';}// 3. Sticky Bit:其他用户 x 位为 t,无 x 权限则为 Tif (st_mode & S_ISVTX) {mode_str[9] = (st_mode & S_IXOTH) ? 't' : 'T';}
}

测试用例

# 测试 SUID 权限(/bin/passwd)
./fileperm /bin/passwd
Custom Mode: -rwsr-xr-x /bin/passwd
ls -l Mode: -rwsr-xr-x /bin/passwd# 测试 Sticky Bit 权限(/tmp)
./fileperm /tmp
Custom Mode: drwxrwxrwt /tmp
ls -l Mode: drwxrwxrwt /tmp

结果验证:程序正确识别 /bin/passwd 的 SUID 权限(权限位为 rwsr-xr-x)和 /tmp 的 Sticky Bit 权限(权限位为 drwxrwxrwt),与 ls -l 完全一致,实现了特殊权限的完整解析。

特殊权限的安全风险

  • SUID 权限滥用:给 /bin/bash 设置 SUID 权限(chmod 4755 /bin/bash),普通用户执行 bash 会获取 root 权限,导致系统被入侵;
  • SGID 目录权限过宽:给公共目录设置 SGID 后,若目录开放写权限,可能导致恶意用户创建文件并篡改组内数据;
  • Sticky Bit 未设置:公共目录(如 /tmp)未设置 Sticky Bit,普通用户可删除其他用户的临时文件,导致数据丢失。

安全建议:仅对必要的文件/目录设置特殊权限,定期通过 find / -perm /4000 -type f(查找 SUID 文件)、find / -perm /1000 -type d(查找 Sticky Bit 目录)检查特殊权限的异常使用。

本文从 st_mode 权限位结构出发,详细讲解了 UNIX 文件基础权限的判断方法、C 语言编程实现、权限作用与安全风险,同时拓展了特殊权限的应用。掌握文件权限控制是 UNIX 系统安全与运维的核心技能,无论是开发还是日常使用,都需重视权限的合理设置。

建议结合实际场景多做测试(如修改权限、编写权限判断脚本),加深对权限逻辑的理解,避免因权限设置不当导致安全问题。

http://www.dtcms.com/a/427644.html

相关文章:

  • 瑞芯微RK35XX系列FFmpeg硬件编解码实测,详细性能对比!
  • php网站后台搭建wordpress购买返现
  • 首架机下线!“四川造”大型载客eVTOL筑低空新里程碑
  • 基于STM32与influxDB的电力监控系统-13
  • 250925-0930技术总结
  • AI 重塑实体经济:从技术落地到价值创造的实践路径
  • 认识软件测试
  • 网站服务器数据库湛江网站建设公司哪个好
  • 动手实现简单Vue.js ,探索Vue原理
  • UNIX下C语言编程与实践18-UNIX 文件存储原理:目录、i 节点、数据块协同存储文件的过程
  • 珠宝怎么做网站wordpress 活动报名插件
  • 除自身以外数组的乘积
  • 爬虫逆向--Day25Day26--原型链补环境
  • 拍拍灯电路(用咪头识别拍拍动作)
  • 极限!ubuntu系统联网
  • 第三章 字典与集合
  • 网站设计的价格沪深300指数基金
  • Java-01-基础篇-JDK日志(JUL)
  • (基于江协科技)51单片机入门:7.LED点阵屏
  • 江协科技 CAN总线入门课程(错误处理)
  • 网站的建设与规划方案企业网站建设要素
  • antdv- Tooltip 文字提示组件
  • 算法题(222):摆花
  • 如何向alexa提交网站wordpress custom login
  • SpringCloud电商微服务项目衣拉客搭建指南
  • dev c++工具下载 dev c++安装包下载 dev c++软件网盘资源分享
  • 如何去掉Excel多余空行
  • 房地产网站欣赏万网空间管理
  • 做多语言网站多少钱免费网站安全软件大全下载安装
  • 【密码学实战】openHiTLS X509命令行工具: 数字证书生成与转换