1 /*
2    Copyright 2017 Skytechnology sp. z o.o.
3 
4    This file is part of LizardFS.
5 
6    LizardFS is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, version 3.
9 
10    LizardFS is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with LizardFS. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "context_wrap.h"
20 #include "lzfs_internal.h"
21 
22 void lzfs_int_apply_masks(liz_acl_t *lzfs_acl, uint32_t owner);
23 
lzfs_int_convert_fsal_acl(const fsal_acl_t * fsal_acl)24 liz_acl_t *lzfs_int_convert_fsal_acl(const fsal_acl_t *fsal_acl) {
25 	liz_acl_t *lzfs_acl = NULL;
26 
27 	if (!fsal_acl || (!fsal_acl->aces && fsal_acl->naces > 0)) {
28 		return NULL;
29 	}
30 
31 	int count = 0;
32 	for (unsigned i = 0; i < fsal_acl->naces; ++i) {
33 		fsal_ace_t *fsal_ace = fsal_acl->aces + i;
34 		count += (IS_FSAL_ACE_ALLOW(*fsal_ace) || IS_FSAL_ACE_DENY(*fsal_ace)) ? 1 : 0;
35 	}
36 
37 	lzfs_acl = liz_create_acl();
38 	if (!lzfs_acl) {
39 		return NULL;
40 	}
41 
42 	for (unsigned i = 0; i < fsal_acl->naces; ++i) {
43 		fsal_ace_t *fsal_ace = fsal_acl->aces + i;
44 		if (!(IS_FSAL_ACE_ALLOW(*fsal_ace) || IS_FSAL_ACE_DENY(*fsal_ace))) {
45 			continue;
46 		}
47 
48 		liz_acl_ace_t ace;
49 		ace.flags = fsal_ace->flag & 0xFF;
50 		ace.mask = fsal_ace->perm;
51 		ace.type = fsal_ace->type;
52 		if (IS_FSAL_ACE_GROUP_ID(*fsal_ace)) {
53 			ace.id = GET_FSAL_ACE_GROUP(*fsal_ace);
54 		} else {
55 			ace.id = GET_FSAL_ACE_USER(*fsal_ace);
56 		}
57 		if (IS_FSAL_ACE_SPECIAL_ID(*fsal_ace)) {
58 			ace.flags |= LIZ_ACL_SPECIAL_WHO;
59 			switch (GET_FSAL_ACE_USER(*fsal_ace)) {
60 			case FSAL_ACE_SPECIAL_OWNER:
61 				ace.id = LIZ_ACL_OWNER_SPECIAL_ID;
62 				break;
63 			case FSAL_ACE_SPECIAL_GROUP:
64 				ace.id = LIZ_ACL_GROUP_SPECIAL_ID;
65 				break;
66 			case FSAL_ACE_SPECIAL_EVERYONE:
67 				ace.id = LIZ_ACL_EVERYONE_SPECIAL_ID;
68 				break;
69 			default:
70 				LogFullDebug(COMPONENT_FSAL, "Invalid FSAL ACE special id type (%d)",
71 				             (int)GET_FSAL_ACE_USER(*fsal_ace));
72 				continue;
73 			}
74 		}
75 
76 		liz_add_acl_entry(lzfs_acl, &ace);
77 	}
78 
79 	return lzfs_acl;
80 }
81 
lzfs_int_convert_lzfs_acl(const liz_acl_t * lzfs_acl)82 fsal_acl_t *lzfs_int_convert_lzfs_acl(const liz_acl_t *lzfs_acl) {
83 	fsal_acl_data_t acl_data;
84 	fsal_acl_status_t acl_status;
85 	fsal_acl_t *fsal_acl = NULL;
86 
87 	if (!lzfs_acl) {
88 		return NULL;
89 	}
90 
91 	acl_data.naces = liz_get_acl_size(lzfs_acl);
92 	acl_data.aces = (fsal_ace_t *)nfs4_ace_alloc(acl_data.naces);
93 
94 	if (!acl_data.aces) {
95 		return NULL;
96 	}
97 
98 	for (unsigned i = 0; i < acl_data.naces; ++i) {
99 		fsal_ace_t *fsal_ace = acl_data.aces + i;
100 		liz_acl_ace_t lzfs_ace;
101 
102 		int rc = liz_get_acl_entry(lzfs_acl, i, &lzfs_ace);
103 		(void)rc;
104 		assert(rc == 0);
105 
106 		fsal_ace->type = lzfs_ace.type;
107 		fsal_ace->flag = lzfs_ace.flags & 0xFF;
108 		fsal_ace->iflag = (lzfs_ace.flags & LIZ_ACL_SPECIAL_WHO) ? FSAL_ACE_IFLAG_SPECIAL_ID : 0;
109 
110 		if (IS_FSAL_ACE_GROUP_ID(*fsal_ace)) {
111 			fsal_ace->who.gid = lzfs_ace.id;
112 		} else {
113 			fsal_ace->who.uid = lzfs_ace.id;
114 		}
115 
116 		if (IS_FSAL_ACE_SPECIAL_ID(*fsal_ace)) {
117 			switch (lzfs_ace.id) {
118 			case LIZ_ACL_OWNER_SPECIAL_ID:
119 				fsal_ace->who.uid = FSAL_ACE_SPECIAL_OWNER;
120 				break;
121 			case LIZ_ACL_GROUP_SPECIAL_ID:
122 				fsal_ace->who.uid = FSAL_ACE_SPECIAL_GROUP;
123 				break;
124 			case LIZ_ACL_EVERYONE_SPECIAL_ID:
125 				fsal_ace->who.uid = FSAL_ACE_SPECIAL_EVERYONE;
126 				break;
127 			default:
128 				fsal_ace->who.uid = FSAL_ACE_NORMAL_WHO;
129 				LogWarn(COMPONENT_FSAL, "Invalid LizardFS ACE special id type (%u)",
130 				        (unsigned)lzfs_ace.id);
131 			}
132 		}
133 	}
134 
135 	fsal_acl = nfs4_acl_new_entry(&acl_data, &acl_status);
136 	LogDebug(COMPONENT_FSAL, "fsal acl = %p, fsal_acl_status = %u", fsal_acl, acl_status);
137 	return fsal_acl;
138 }
139 
lzfs_int_getacl(struct lzfs_fsal_export * lzfs_export,uint32_t inode,uint32_t owner_id,fsal_acl_t ** fsal_acl)140 fsal_status_t lzfs_int_getacl(struct lzfs_fsal_export *lzfs_export, uint32_t inode,
141                               uint32_t owner_id, fsal_acl_t **fsal_acl) {
142 	if (*fsal_acl) {
143 		int acl_status = nfs4_acl_release_entry(*fsal_acl);
144 		if (acl_status != NFS_V4_ACL_SUCCESS) {
145 			LogCrit(COMPONENT_FSAL, "Failed to release old acl, status=%d", acl_status);
146 		}
147 		*fsal_acl = NULL;
148 	}
149 
150 	liz_acl_t *acl = NULL;
151 	int rc = liz_cred_getacl(lzfs_export->lzfs_instance, op_ctx->creds, inode, &acl);
152 	if (rc < 0) {
153 		LogFullDebug(COMPONENT_FSAL, "getacl status=%s export=%" PRIu16 " inode=%" PRIu32,
154 		             liz_error_string(liz_last_err()), lzfs_export->export.export_id, inode);
155 		return lzfs_fsal_last_err();
156 	}
157 
158 	lzfs_int_apply_masks(acl, owner_id);
159 
160 	*fsal_acl = lzfs_int_convert_lzfs_acl(acl);
161 	liz_destroy_acl(acl);
162 
163 	if (*fsal_acl == NULL) {
164 		LogFullDebug(COMPONENT_FSAL,
165 		             "Failed to convert lzfs acl to nfs4 acl, export=%" PRIu16 " inode=%" PRIu32,
166 		             lzfs_export->export.export_id, inode);
167 		return fsalstat(ERR_FSAL_FAULT, 0);
168 	}
169 
170 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
171 }
172 
lzfs_int_setacl(struct lzfs_fsal_export * lzfs_export,uint32_t inode,const fsal_acl_t * fsal_acl)173 fsal_status_t lzfs_int_setacl(struct lzfs_fsal_export *lzfs_export, uint32_t inode,
174                               const fsal_acl_t *fsal_acl) {
175 	if (!fsal_acl) {
176 		return fsalstat(ERR_FSAL_NO_ERROR, 0);
177 	}
178 
179 	liz_acl_t *lzfs_acl = lzfs_int_convert_fsal_acl(fsal_acl);
180 	if (!lzfs_acl) {
181 		LogFullDebug(COMPONENT_FSAL, "failed to convert acl");
182 		return fsalstat(ERR_FSAL_FAULT, 0);
183 	}
184 	int rc = liz_cred_setacl(lzfs_export->lzfs_instance, op_ctx->creds, inode, lzfs_acl);
185 	liz_destroy_acl(lzfs_acl);
186 
187 	if (rc < 0) {
188 		LogFullDebug(COMPONENT_FSAL, "setacl returned %s (%d)", liz_error_string(liz_last_err()),
189 		             (int)liz_last_err());
190 		return lzfs_fsal_last_err();
191 	}
192 
193 	return fsalstat(ERR_FSAL_NO_ERROR, 0);
194 }
195