ksmbd: replace struct dentry with struct path in some function's arguments
[linux-block.git] / fs / ksmbd / ndr.c
CommitLineData
e2f34481
NJ
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2021 Samsung Electronics Co., Ltd.
4 * Author(s): Namjae Jeon <linkinjeon@kernel.org>
5 */
6
7#include <linux/fs.h>
8
9#include "glob.h"
10#include "ndr.h"
11
cb5b047f
HL
12static inline char *ndr_get_field(struct ndr *n)
13{
14 return n->data + n->offset;
15}
e2f34481 16
e2f34481
NJ
17static int try_to_realloc_ndr_blob(struct ndr *n, size_t sz)
18{
19 char *data;
20
21 data = krealloc(n->data, n->offset + sz + 1024, GFP_KERNEL);
22 if (!data)
23 return -ENOMEM;
24
25 n->data = data;
26 n->length += 1024;
27 memset(n->data + n->offset, 0, 1024);
28 return 0;
29}
30
31static void ndr_write_int16(struct ndr *n, __u16 value)
32{
33 if (n->length <= n->offset + sizeof(value))
34 try_to_realloc_ndr_blob(n, sizeof(value));
35
cb5b047f 36 *(__le16 *)ndr_get_field(n) = cpu_to_le16(value);
e2f34481
NJ
37 n->offset += sizeof(value);
38}
39
40static void ndr_write_int32(struct ndr *n, __u32 value)
41{
42 if (n->length <= n->offset + sizeof(value))
43 try_to_realloc_ndr_blob(n, sizeof(value));
44
cb5b047f 45 *(__le32 *)ndr_get_field(n) = cpu_to_le32(value);
e2f34481
NJ
46 n->offset += sizeof(value);
47}
48
49static void ndr_write_int64(struct ndr *n, __u64 value)
50{
51 if (n->length <= n->offset + sizeof(value))
52 try_to_realloc_ndr_blob(n, sizeof(value));
53
cb5b047f 54 *(__le64 *)ndr_get_field(n) = cpu_to_le64(value);
e2f34481
NJ
55 n->offset += sizeof(value);
56}
57
58static int ndr_write_bytes(struct ndr *n, void *value, size_t sz)
59{
60 if (n->length <= n->offset + sz)
61 try_to_realloc_ndr_blob(n, sz);
62
cb5b047f 63 memcpy(ndr_get_field(n), value, sz);
e2f34481
NJ
64 n->offset += sz;
65 return 0;
66}
67
68static int ndr_write_string(struct ndr *n, void *value, size_t sz)
69{
70 if (n->length <= n->offset + sz)
71 try_to_realloc_ndr_blob(n, sz);
72
cb5b047f 73 strncpy(ndr_get_field(n), value, sz);
e2f34481
NJ
74 sz++;
75 n->offset += sz;
c2220322 76 n->offset = ALIGN(n->offset, 2);
e2f34481
NJ
77 return 0;
78}
79
80static int ndr_read_string(struct ndr *n, void *value, size_t sz)
81{
cb5b047f 82 int len = strnlen(ndr_get_field(n), sz);
e2f34481 83
cb5b047f 84 memcpy(value, ndr_get_field(n), len);
e2f34481
NJ
85 len++;
86 n->offset += len;
c2220322 87 n->offset = ALIGN(n->offset, 2);
e2f34481
NJ
88 return 0;
89}
90
91static int ndr_read_bytes(struct ndr *n, void *value, size_t sz)
92{
cb5b047f 93 memcpy(value, ndr_get_field(n), sz);
e2f34481
NJ
94 n->offset += sz;
95 return 0;
96}
97
98static __u16 ndr_read_int16(struct ndr *n)
99{
100 __u16 ret;
101
cb5b047f 102 ret = le16_to_cpu(*(__le16 *)ndr_get_field(n));
e2f34481
NJ
103 n->offset += sizeof(__u16);
104 return ret;
105}
106
107static __u32 ndr_read_int32(struct ndr *n)
108{
109 __u32 ret;
110
cb5b047f 111 ret = le32_to_cpu(*(__le32 *)ndr_get_field(n));
e2f34481
NJ
112 n->offset += sizeof(__u32);
113 return ret;
114}
115
116static __u64 ndr_read_int64(struct ndr *n)
117{
118 __u64 ret;
119
cb5b047f 120 ret = le64_to_cpu(*(__le64 *)ndr_get_field(n));
e2f34481
NJ
121 n->offset += sizeof(__u64);
122 return ret;
123}
124
125int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
126{
127 char hex_attr[12] = {0};
128
129 n->offset = 0;
130 n->length = 1024;
131 n->data = kzalloc(n->length, GFP_KERNEL);
132 if (!n->data)
133 return -ENOMEM;
134
135 if (da->version == 3) {
136 snprintf(hex_attr, 10, "0x%x", da->attr);
137 ndr_write_string(n, hex_attr, strlen(hex_attr));
138 } else {
139 ndr_write_string(n, "", strlen(""));
140 }
141 ndr_write_int16(n, da->version);
142 ndr_write_int32(n, da->version);
143
144 ndr_write_int32(n, da->flags);
145 ndr_write_int32(n, da->attr);
146 if (da->version == 3) {
147 ndr_write_int32(n, da->ea_size);
148 ndr_write_int64(n, da->size);
149 ndr_write_int64(n, da->alloc_size);
64b39f4a 150 } else {
e2f34481 151 ndr_write_int64(n, da->itime);
64b39f4a 152 }
e2f34481
NJ
153 ndr_write_int64(n, da->create_time);
154 if (da->version == 3)
155 ndr_write_int64(n, da->change_time);
156 return 0;
157}
158
159int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
160{
161 char hex_attr[12] = {0};
162 int version2;
163
164 n->offset = 0;
165 ndr_read_string(n, hex_attr, n->length - n->offset);
166 da->version = ndr_read_int16(n);
167
168 if (da->version != 3 && da->version != 4) {
bde1694a 169 pr_err("v%d version is not supported\n", da->version);
e2f34481
NJ
170 return -EINVAL;
171 }
172
173 version2 = ndr_read_int32(n);
174 if (da->version != version2) {
bde1694a
NJ
175 pr_err("ndr version mismatched(version: %d, version2: %d)\n",
176 da->version, version2);
e2f34481
NJ
177 return -EINVAL;
178 }
179
180 ndr_read_int32(n);
181 da->attr = ndr_read_int32(n);
182 if (da->version == 4) {
183 da->itime = ndr_read_int64(n);
184 da->create_time = ndr_read_int64(n);
185 } else {
186 ndr_read_int32(n);
187 ndr_read_int64(n);
188 ndr_read_int64(n);
189 da->create_time = ndr_read_int64(n);
190 ndr_read_int64(n);
191 }
192
193 return 0;
194}
195
196static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl)
197{
198 int i;
199
200 ndr_write_int32(n, acl->count);
c2220322 201 n->offset = ALIGN(n->offset, 8);
e2f34481
NJ
202 ndr_write_int32(n, acl->count);
203 ndr_write_int32(n, 0);
204
205 for (i = 0; i < acl->count; i++) {
c2220322 206 n->offset = ALIGN(n->offset, 8);
e2f34481
NJ
207 ndr_write_int16(n, acl->entries[i].type);
208 ndr_write_int16(n, acl->entries[i].type);
209
210 if (acl->entries[i].type == SMB_ACL_USER) {
c2220322 211 n->offset = ALIGN(n->offset, 8);
e2f34481
NJ
212 ndr_write_int64(n, acl->entries[i].uid);
213 } else if (acl->entries[i].type == SMB_ACL_GROUP) {
c2220322 214 n->offset = ALIGN(n->offset, 8);
e2f34481
NJ
215 ndr_write_int64(n, acl->entries[i].gid);
216 }
217
218 /* push permission */
219 ndr_write_int32(n, acl->entries[i].perm);
220 }
221
222 return 0;
223}
224
225int ndr_encode_posix_acl(struct ndr *n, struct inode *inode,
070fb21e
NJ
226 struct xattr_smb_acl *acl,
227 struct xattr_smb_acl *def_acl)
e2f34481
NJ
228{
229 int ref_id = 0x00020000;
230
231 n->offset = 0;
232 n->length = 1024;
233 n->data = kzalloc(n->length, GFP_KERNEL);
234 if (!n->data)
235 return -ENOMEM;
236
237 if (acl) {
238 /* ACL ACCESS */
239 ndr_write_int32(n, ref_id);
240 ref_id += 4;
64b39f4a 241 } else {
e2f34481 242 ndr_write_int32(n, 0);
64b39f4a 243 }
e2f34481
NJ
244
245 if (def_acl) {
246 /* DEFAULT ACL ACCESS */
247 ndr_write_int32(n, ref_id);
248 ref_id += 4;
64b39f4a 249 } else {
e2f34481 250 ndr_write_int32(n, 0);
64b39f4a 251 }
e2f34481
NJ
252
253 ndr_write_int64(n, from_kuid(&init_user_ns, inode->i_uid));
254 ndr_write_int64(n, from_kgid(&init_user_ns, inode->i_gid));
255 ndr_write_int32(n, inode->i_mode);
256
257 if (acl) {
258 ndr_encode_posix_acl_entry(n, acl);
259 if (def_acl)
260 ndr_encode_posix_acl_entry(n, def_acl);
261 }
262 return 0;
263}
264
265int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
266{
267 int ref_id = 0x00020004;
268
269 n->offset = 0;
270 n->length = 2048;
271 n->data = kzalloc(n->length, GFP_KERNEL);
272 if (!n->data)
273 return -ENOMEM;
274
275 ndr_write_int16(n, acl->version);
276 ndr_write_int32(n, acl->version);
277 ndr_write_int16(n, 2);
278 ndr_write_int32(n, ref_id);
279
280 /* push hash type and hash 64bytes */
281 ndr_write_int16(n, acl->hash_type);
282 ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
283 ndr_write_bytes(n, acl->desc, acl->desc_len);
284 ndr_write_int64(n, acl->current_time);
285 ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
286
287 /* push ndr for security descriptor */
288 ndr_write_bytes(n, acl->sd_buf, acl->sd_size);
289
290 return 0;
291}
292
293int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
294{
295 int version2;
296
297 n->offset = 0;
298 acl->version = ndr_read_int16(n);
299 if (acl->version != 4) {
bde1694a 300 pr_err("v%d version is not supported\n", acl->version);
e2f34481
NJ
301 return -EINVAL;
302 }
303
304 version2 = ndr_read_int32(n);
305 if (acl->version != version2) {
bde1694a
NJ
306 pr_err("ndr version mismatched(version: %d, version2: %d)\n",
307 acl->version, version2);
e2f34481
NJ
308 return -EINVAL;
309 }
310
311 /* Read Level */
312 ndr_read_int16(n);
313 /* Read Ref Id */
314 ndr_read_int32(n);
315 acl->hash_type = ndr_read_int16(n);
316 ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
317
318 ndr_read_bytes(n, acl->desc, 10);
319 if (strncmp(acl->desc, "posix_acl", 9)) {
bde1694a 320 pr_err("Invalid acl description : %s\n", acl->desc);
e2f34481
NJ
321 return -EINVAL;
322 }
323
324 /* Read Time */
325 ndr_read_int64(n);
326 /* Read Posix ACL hash */
327 ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
328 acl->sd_size = n->length - n->offset;
329 acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL);
330 if (!acl->sd_buf)
331 return -ENOMEM;
332
333 ndr_read_bytes(n, acl->sd_buf, acl->sd_size);
334
335 return 0;
336}