* fs/sharefs/authentication.c
*
* Copyright (c) 2023 Huawei Device Co., Ltd.
*/
#include "authentication.h"
static inline __u16 perm_get_next_level(__u16 perm)
{
__u16 level = (perm & SHAREFS_PERM_MASK) + 1;
if (level <= SHAREFS_PERM_OTHER)
return level;
else
return SHAREFS_PERM_OTHER;
}
void fixup_perm_from_level(struct inode *dir, struct dentry *dentry)
{
struct sharefs_inode_info *hii = SHAREFS_I(dir);
struct inode *dinode = d_inode(dentry);
struct sharefs_inode_info *dinfo = SHAREFS_I(dinode);
const unsigned char* cur_name = dentry->d_name.name;
__u16 level = perm_get_next_level(hii->perm);
__u16 perm = 0;
int bid = 0;
if (IS_ERR_OR_NULL(dinode))
return;
dinode->i_uid = dir->i_uid;
dinode->i_gid = dir->i_gid;
switch (level) {
case SHAREFS_PERM_MNT:
bid = get_bundle_uid(SHAREFS_SB(dentry->d_sb),
dentry->d_name.name);
perm = level;
if (bid != 0) {
dinode->i_uid = KUIDT_INIT(bid);
dinode->i_gid = KGIDT_INIT(bid);
} else {
dinode->i_uid = ROOT_UID;
dinode->i_gid = ROOT_GID;
}
dinode->i_mode = (dinode->i_mode & S_IFMT) | SHAREFS_PERM_READONLY_DIR;
break;
case SHAREFS_PERM_DFS:
if (!strcmp(cur_name, SHAREFS_READ_DIR)) {
perm = SHAREFS_DIR_TYPE_READONLY | level;
sharefs_set_read_perm(dinode);
} else if (!strcmp(cur_name, SHAREFS_READWRITE_DIR)) {
perm = SHAREFS_DIR_TYPE_READWRITE | level;
sharefs_set_read_write_perm(dinode);
}
break;
case SHAREFS_PERM_OTHER:
if (is_read_only_auth(hii->perm)) {
perm = SHAREFS_DIR_TYPE_READONLY | SHAREFS_PERM_DFS;
sharefs_set_read_perm(dinode);
} else if (is_read_write_auth(hii->perm)) {
perm = SHAREFS_DIR_TYPE_READWRITE | SHAREFS_PERM_DFS;
sharefs_set_read_write_perm(dinode);
}
break;
default:
sharefs_err("sharedfs perm incorrect got default case, level:%u", level);
break;
}
dinfo->perm = perm;
}
void sharefs_root_inode_perm_init(struct inode *root_inode)
{
struct sharefs_inode_info *hii = SHAREFS_I(root_inode);
hii->perm = SHAREFS_PERM_FIX;
}
#ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE
const struct cred *sharefs_override_file_fsids(struct inode *dir, __u16 *_perm)
{
struct cred *cred = NULL;
cred = prepare_creds();
if (!cred)
return NULL;
cred->fsuid = dir->i_uid;
cred->fsgid = dir->i_gid;
return override_creds(cred);
}
void sharefs_revert_fsids(const struct cred *old_cred)
{
const struct cred *cur_cred;
cur_cred = current->cred;
revert_creds(old_cred);
put_cred(cur_cred);
}
#endif