1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * fs/sharefs/authentication.c
4 *
5 * Copyright (c) 2023 Huawei Device Co., Ltd.
6 */
7#include "authentication.h"
8
9static inline __u16 perm_get_next_level(__u16 perm)
10{
11	__u16 level = (perm & SHAREFS_PERM_MASK) + 1;
12
13	if (level <= SHAREFS_PERM_OTHER)
14		return level;
15	else
16		return SHAREFS_PERM_OTHER;
17}
18
19void fixup_perm_from_level(struct inode *dir, struct dentry *dentry)
20{
21	struct sharefs_inode_info *hii = SHAREFS_I(dir);
22	struct inode *dinode = d_inode(dentry);
23	struct sharefs_inode_info *dinfo = SHAREFS_I(dinode);
24	const unsigned char* cur_name =  dentry->d_name.name;
25	__u16 level = perm_get_next_level(hii->perm);
26	__u16 perm = 0;
27	int bid = 0;
28
29	if (IS_ERR_OR_NULL(dinode))
30		return;
31	dinode->i_uid = dir->i_uid;
32	dinode->i_gid = dir->i_gid;
33	switch (level) {
34	case SHAREFS_PERM_MNT:
35		bid = get_bundle_uid(SHAREFS_SB(dentry->d_sb),
36					 dentry->d_name.name);
37		perm = level;
38		if (bid != 0) {
39			dinode->i_uid = KUIDT_INIT(bid);
40			dinode->i_gid = KGIDT_INIT(bid);
41		} else {
42			dinode->i_uid = ROOT_UID;
43			dinode->i_gid = ROOT_GID;
44		}
45		dinode->i_mode = (dinode->i_mode & S_IFMT) | SHAREFS_PERM_READONLY_DIR;
46		break;
47	case SHAREFS_PERM_DFS:
48		if (!strcmp(cur_name, SHAREFS_READ_DIR)) {
49			perm = SHAREFS_DIR_TYPE_READONLY | level;
50			sharefs_set_read_perm(dinode);
51		} else if (!strcmp(cur_name, SHAREFS_READWRITE_DIR)) {
52			perm = SHAREFS_DIR_TYPE_READWRITE | level;
53			sharefs_set_read_write_perm(dinode);
54		}
55		break;
56	case SHAREFS_PERM_OTHER:
57		if (is_read_only_auth(hii->perm)) {
58			perm = SHAREFS_DIR_TYPE_READONLY | SHAREFS_PERM_DFS;
59			sharefs_set_read_perm(dinode);
60		} else if (is_read_write_auth(hii->perm)) {
61			perm = SHAREFS_DIR_TYPE_READWRITE | SHAREFS_PERM_DFS;
62			sharefs_set_read_write_perm(dinode);
63		}
64		break;
65	default:
66		sharefs_err("sharedfs perm incorrect got default case, level:%u", level);
67		break;
68	}
69	dinfo->perm = perm;
70}
71
72void sharefs_root_inode_perm_init(struct inode *root_inode)
73{
74	struct sharefs_inode_info *hii = SHAREFS_I(root_inode);
75	hii->perm = SHAREFS_PERM_FIX;
76}
77
78#ifdef CONFIG_SHAREFS_SUPPORT_OVERRIDE
79const struct cred *sharefs_override_file_fsids(struct inode *dir, __u16 *_perm)
80{
81	struct cred *cred = NULL;
82	cred = prepare_creds();
83	if (!cred)
84		return NULL;
85
86	cred->fsuid = dir->i_uid;
87	cred->fsgid = dir->i_gid;
88	return override_creds(cred);
89}
90
91void sharefs_revert_fsids(const struct cred *old_cred)
92{
93	const struct cred *cur_cred;
94	cur_cred = current->cred;
95	revert_creds(old_cred);
96	put_cred(cur_cred);
97}
98#endif