2021SC@SDUSC
先简单说一下Linux的文件权限,在Linux下,一个文件的操作对象可以分为三类:user,group,other,文件的权限也有三种:read,write,execute。那么对于user和group来说,他们有文件的rwx三种权限,而other的权限为0。这就是UGO权限,它最大的缺点是无法为额外的用户设置合适的权限。
ACL(Access Control List)是访问控制列表,在Linux中用于设定用户针对文件的权限,它是对UGO权限管理的补充。ACL可以对额外的某个用户或用户组设置权限,即不只有文件的user和group可以访问该文件,可以解决UGO无法解决的情况。举个例子,在UGO权限下,一个文件有一个user和一个group,他们有文件的rwx权限,此外的其他人都是无权限的,此时有一个人需要该文件的r权限,但又不属于该文件的group,就需要ACL专门为此用户设置权限。如果没有ACL 的话,只能将该用户加入group或other中,那么在group中用户会得到额外的权限,在other中又需要给予other这个群体中所有用户同等的权限,这种设定是很不合理的。
在posix标准里,一个acl结构体定义如下
typedef struct {
__le16 e_tag;
__le16 e_perm;
__le32 e_id;
} posix_acl_xattr_entry;
e_tag即Entry tag type 有以下六种类型:
ACL_USER_OBJ:相当于user的权限
ACL_USER:是ACL定义的其他用户的权限
ACL_GROUP_OBJ:相当于group的权限
ACL_GROUP:是ACL定义的其他用户组的权限
ACL_MASK:定义了ACL_USER,ACL_GROUP_OBJ和ACL_GROUP的最大权限,即如果mask存在,那么获取的权限的值为mask的值,而非group或user的实际权限,可能mask为rwx,group为rw。
ACL_OTHER:相当于other的权限
e_perm代表权限,就是rwx三种权限。
e_id标识唯一的用户或用户组,并且只有ACL_USER和ACL_GROUP有值,因为只有这两个tag是定义了额外的用户权限。
简单地来说ACL就是可以设置特定用户或者用户组对于一个文件或目录的操作权限,分为Access ACL和Default ACL,分别对文件和目录进行操作,Default ACL是指对于一个目录进行Default ACL设置,并且在此目录下建立的文件都将继承此目录的ACL。关于ACL需要掌握的命令也只有三个: getfacl, setfacl, chacl。getfacl命令是用来读取文件的ACL;setfacl是用来设定文件的ACL;chacl是用来改变文件和目录的Access ACL和Default ACL。
那么先分析acl.h文件,ext2_acl_entry是ext2文件系统的acl结构体,遵循posix标准,ext2_acl_entry_short则取消了e_id。ext2_acl_header则只有版本号。
typedef struct {
__le16 e_tag;
__le16 e_perm;
__le32 e_id;
} ext2_acl_entry;
typedef struct {
__le16 e_tag;
__le16 e_perm;
} ext2_acl_entry_short;
typedef struct {
__le32 a_version;
} ext2_acl_header;
以下函数能根据acl项目的数目获得ext2的acl大小,因为共有六种e_tag,如果count<=4,那么 必然是ACL_USER_OBJ、ACL_GROUP_OBJ、ACL_MASK、ACL_OTHER中的几个,即是没有e_id字段,那么只需要ext2_acl_header的大小ext2_acl_header的大小加上count乘ext2_acl_entry_short的大小;否则ext2_acl_header的大小需要加上4个ext2_acl_entry_short的大小和(count-4)个ext2_acl_entry的大小。
static inline size_t ext2_acl_size(int count)
{
if (count <= 4) {
return sizeof(ext2_acl_header) +
count * sizeof(ext2_acl_entry_short);
} else {
return sizeof(ext2_acl_header) +
4 * sizeof(ext2_acl_entry_short) +
(count - 4) * sizeof(ext2_acl_entry);
}
}
以下函数能根据acl大小获得ext2的acl项目的数目,是上面函数的逆推。分析算法,如上一个函数所示,每个size都有一个ext2_acl_header,那么size先减去ext2_acl_header的大小,此时有两种情况,一是count<=4,一是count>4,区分方法就是size减去4*ext2_acl_entry_short,小于0说明count<=4,那么count计算方法就是上面函数的倒推了。
static inline int ext2_acl_count(size_t size)
{
ssize_t s;
size -= sizeof(ext2_acl_header);
s = size - 4 * sizeof(ext2_acl_entry_short);
if (s < 0) {
if (size % sizeof(ext2_acl_entry_short))
return -1;
return size / sizeof(ext2_acl_entry_short);
} else {
if (s % sizeof(ext2_acl_entry))
return -1;
return s / sizeof(ext2_acl_entry) + 4;
}
}
下面是一段if else 的结构,是关于ACL的一些config,如果定义了CONFIG_EXT2_FS_POSIX_ACL,就采用第一段配置,否则用第二段。
#ifdef CONFIG_EXT2_FS_POSIX_ACL
/* Value for inode->u.ext2_i.i_acl and inode->u.ext2_i.i_default_acl
if the ACL has not been cached */
#define EXT2_ACL_NOT_CACHED ((void *)-1)
/* acl.c */
extern int ext2_permission (struct inode *, int, struct nameidata *);
extern int ext2_acl_chmod (struct inode *);
extern int ext2_init_acl (struct inode *, struct inode *);
#else
#include <linux/sched.h>
#define ext2_permission NULL
#define ext2_get_acl NULL
#define ext2_set_acl NULL
static inline int
ext2_acl_chmod (struct inode *inode)
{
return 0;
}
static inline int ext2_init_acl (struct inode *inode, struct inode *dir)
{
return 0;
}
#endif