Merge branch 'misc.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / fs / ksmbd / ndr.c
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
12 static inline char *ndr_get_field(struct ndr *n)
13 {
14         return n->data + n->offset;
15 }
16
17 static 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
31 static int ndr_write_int16(struct ndr *n, __u16 value)
32 {
33         if (n->length <= n->offset + sizeof(value)) {
34                 int ret;
35
36                 ret = try_to_realloc_ndr_blob(n, sizeof(value));
37                 if (ret)
38                         return ret;
39         }
40
41         *(__le16 *)ndr_get_field(n) = cpu_to_le16(value);
42         n->offset += sizeof(value);
43         return 0;
44 }
45
46 static int ndr_write_int32(struct ndr *n, __u32 value)
47 {
48         if (n->length <= n->offset + sizeof(value)) {
49                 int ret;
50
51                 ret = try_to_realloc_ndr_blob(n, sizeof(value));
52                 if (ret)
53                         return ret;
54         }
55
56         *(__le32 *)ndr_get_field(n) = cpu_to_le32(value);
57         n->offset += sizeof(value);
58         return 0;
59 }
60
61 static int ndr_write_int64(struct ndr *n, __u64 value)
62 {
63         if (n->length <= n->offset + sizeof(value)) {
64                 int ret;
65
66                 ret = try_to_realloc_ndr_blob(n, sizeof(value));
67                 if (ret)
68                         return ret;
69         }
70
71         *(__le64 *)ndr_get_field(n) = cpu_to_le64(value);
72         n->offset += sizeof(value);
73         return 0;
74 }
75
76 static int ndr_write_bytes(struct ndr *n, void *value, size_t sz)
77 {
78         if (n->length <= n->offset + sz) {
79                 int ret;
80
81                 ret = try_to_realloc_ndr_blob(n, sz);
82                 if (ret)
83                         return ret;
84         }
85
86         memcpy(ndr_get_field(n), value, sz);
87         n->offset += sz;
88         return 0;
89 }
90
91 static int ndr_write_string(struct ndr *n, char *value)
92 {
93         size_t sz;
94
95         sz = strlen(value) + 1;
96         if (n->length <= n->offset + sz) {
97                 int ret;
98
99                 ret = try_to_realloc_ndr_blob(n, sz);
100                 if (ret)
101                         return ret;
102         }
103
104         memcpy(ndr_get_field(n), value, sz);
105         n->offset += sz;
106         n->offset = ALIGN(n->offset, 2);
107         return 0;
108 }
109
110 static int ndr_read_string(struct ndr *n, void *value, size_t sz)
111 {
112         int len;
113
114         if (n->offset + sz > n->length)
115                 return -EINVAL;
116
117         len = strnlen(ndr_get_field(n), sz);
118         if (value)
119                 memcpy(value, ndr_get_field(n), len);
120         len++;
121         n->offset += len;
122         n->offset = ALIGN(n->offset, 2);
123         return 0;
124 }
125
126 static int ndr_read_bytes(struct ndr *n, void *value, size_t sz)
127 {
128         if (n->offset + sz > n->length)
129                 return -EINVAL;
130
131         if (value)
132                 memcpy(value, ndr_get_field(n), sz);
133         n->offset += sz;
134         return 0;
135 }
136
137 static int ndr_read_int16(struct ndr *n, __u16 *value)
138 {
139         if (n->offset + sizeof(__u16) > n->length)
140                 return -EINVAL;
141
142         if (value)
143                 *value = le16_to_cpu(*(__le16 *)ndr_get_field(n));
144         n->offset += sizeof(__u16);
145         return 0;
146 }
147
148 static int ndr_read_int32(struct ndr *n, __u32 *value)
149 {
150         if (n->offset + sizeof(__u32) > n->length)
151                 return 0;
152
153         if (value)
154                 *value = le32_to_cpu(*(__le32 *)ndr_get_field(n));
155         n->offset += sizeof(__u32);
156         return 0;
157 }
158
159 static int ndr_read_int64(struct ndr *n, __u64 *value)
160 {
161         if (n->offset + sizeof(__u64) > n->length)
162                 return -EINVAL;
163
164         if (value)
165                 *value = le64_to_cpu(*(__le64 *)ndr_get_field(n));
166         n->offset += sizeof(__u64);
167         return 0;
168 }
169
170 int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
171 {
172         char hex_attr[12] = {0};
173         int ret;
174
175         n->offset = 0;
176         n->length = 1024;
177         n->data = kzalloc(n->length, GFP_KERNEL);
178         if (!n->data)
179                 return -ENOMEM;
180
181         if (da->version == 3) {
182                 snprintf(hex_attr, 10, "0x%x", da->attr);
183                 ret = ndr_write_string(n, hex_attr);
184         } else {
185                 ret = ndr_write_string(n, "");
186         }
187         if (ret)
188                 return ret;
189
190         ret = ndr_write_int16(n, da->version);
191         if (ret)
192                 return ret;
193
194         ret = ndr_write_int32(n, da->version);
195         if (ret)
196                 return ret;
197
198         ret = ndr_write_int32(n, da->flags);
199         if (ret)
200                 return ret;
201
202         ret = ndr_write_int32(n, da->attr);
203         if (ret)
204                 return ret;
205
206         if (da->version == 3) {
207                 ret = ndr_write_int32(n, da->ea_size);
208                 if (ret)
209                         return ret;
210                 ret = ndr_write_int64(n, da->size);
211                 if (ret)
212                         return ret;
213                 ret = ndr_write_int64(n, da->alloc_size);
214         } else {
215                 ret = ndr_write_int64(n, da->itime);
216         }
217         if (ret)
218                 return ret;
219
220         ret = ndr_write_int64(n, da->create_time);
221         if (ret)
222                 return ret;
223
224         if (da->version == 3)
225                 ret = ndr_write_int64(n, da->change_time);
226         return ret;
227 }
228
229 int ndr_decode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
230 {
231         char hex_attr[12];
232         unsigned int version2;
233         int ret;
234
235         n->offset = 0;
236         ret = ndr_read_string(n, hex_attr, sizeof(hex_attr));
237         if (ret)
238                 return ret;
239
240         ret = ndr_read_int16(n, &da->version);
241         if (ret)
242                 return ret;
243
244         if (da->version != 3 && da->version != 4) {
245                 pr_err("v%d version is not supported\n", da->version);
246                 return -EINVAL;
247         }
248
249         ret = ndr_read_int32(n, &version2);
250         if (ret)
251                 return ret;
252
253         if (da->version != version2) {
254                 pr_err("ndr version mismatched(version: %d, version2: %d)\n",
255                        da->version, version2);
256                 return -EINVAL;
257         }
258
259         ret = ndr_read_int32(n, NULL);
260         if (ret)
261                 return ret;
262
263         ret = ndr_read_int32(n, &da->attr);
264         if (ret)
265                 return ret;
266
267         if (da->version == 4) {
268                 ret = ndr_read_int64(n, &da->itime);
269                 if (ret)
270                         return ret;
271
272                 ret = ndr_read_int64(n, &da->create_time);
273         } else {
274                 ret = ndr_read_int32(n, NULL);
275                 if (ret)
276                         return ret;
277
278                 ret = ndr_read_int64(n, NULL);
279                 if (ret)
280                         return ret;
281
282                 ret = ndr_read_int64(n, NULL);
283                 if (ret)
284                         return ret;
285
286                 ret = ndr_read_int64(n, &da->create_time);
287                 if (ret)
288                         return ret;
289
290                 ret = ndr_read_int64(n, NULL);
291         }
292
293         return ret;
294 }
295
296 static int ndr_encode_posix_acl_entry(struct ndr *n, struct xattr_smb_acl *acl)
297 {
298         int i, ret;
299
300         ret = ndr_write_int32(n, acl->count);
301         if (ret)
302                 return ret;
303
304         n->offset = ALIGN(n->offset, 8);
305         ret = ndr_write_int32(n, acl->count);
306         if (ret)
307                 return ret;
308
309         ret = ndr_write_int32(n, 0);
310         if (ret)
311                 return ret;
312
313         for (i = 0; i < acl->count; i++) {
314                 n->offset = ALIGN(n->offset, 8);
315                 ret = ndr_write_int16(n, acl->entries[i].type);
316                 if (ret)
317                         return ret;
318
319                 ret = ndr_write_int16(n, acl->entries[i].type);
320                 if (ret)
321                         return ret;
322
323                 if (acl->entries[i].type == SMB_ACL_USER) {
324                         n->offset = ALIGN(n->offset, 8);
325                         ret = ndr_write_int64(n, acl->entries[i].uid);
326                 } else if (acl->entries[i].type == SMB_ACL_GROUP) {
327                         n->offset = ALIGN(n->offset, 8);
328                         ret = ndr_write_int64(n, acl->entries[i].gid);
329                 }
330                 if (ret)
331                         return ret;
332
333                 /* push permission */
334                 ret = ndr_write_int32(n, acl->entries[i].perm);
335         }
336
337         return ret;
338 }
339
340 int ndr_encode_posix_acl(struct ndr *n,
341                          struct user_namespace *user_ns,
342                          struct inode *inode,
343                          struct xattr_smb_acl *acl,
344                          struct xattr_smb_acl *def_acl)
345 {
346         unsigned int ref_id = 0x00020000;
347         int ret;
348
349         n->offset = 0;
350         n->length = 1024;
351         n->data = kzalloc(n->length, GFP_KERNEL);
352         if (!n->data)
353                 return -ENOMEM;
354
355         if (acl) {
356                 /* ACL ACCESS */
357                 ret = ndr_write_int32(n, ref_id);
358                 ref_id += 4;
359         } else {
360                 ret = ndr_write_int32(n, 0);
361         }
362         if (ret)
363                 return ret;
364
365         if (def_acl) {
366                 /* DEFAULT ACL ACCESS */
367                 ret = ndr_write_int32(n, ref_id);
368                 ref_id += 4;
369         } else {
370                 ret = ndr_write_int32(n, 0);
371         }
372         if (ret)
373                 return ret;
374
375         ret = ndr_write_int64(n, from_kuid(&init_user_ns, i_uid_into_mnt(user_ns, inode)));
376         if (ret)
377                 return ret;
378         ret = ndr_write_int64(n, from_kgid(&init_user_ns, i_gid_into_mnt(user_ns, inode)));
379         if (ret)
380                 return ret;
381         ret = ndr_write_int32(n, inode->i_mode);
382         if (ret)
383                 return ret;
384
385         if (acl) {
386                 ret = ndr_encode_posix_acl_entry(n, acl);
387                 if (def_acl && !ret)
388                         ret = ndr_encode_posix_acl_entry(n, def_acl);
389         }
390         return ret;
391 }
392
393 int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
394 {
395         unsigned int ref_id = 0x00020004;
396         int ret;
397
398         n->offset = 0;
399         n->length = 2048;
400         n->data = kzalloc(n->length, GFP_KERNEL);
401         if (!n->data)
402                 return -ENOMEM;
403
404         ret = ndr_write_int16(n, acl->version);
405         if (ret)
406                 return ret;
407
408         ret = ndr_write_int32(n, acl->version);
409         if (ret)
410                 return ret;
411
412         ret = ndr_write_int16(n, 2);
413         if (ret)
414                 return ret;
415
416         ret = ndr_write_int32(n, ref_id);
417         if (ret)
418                 return ret;
419
420         /* push hash type and hash 64bytes */
421         ret = ndr_write_int16(n, acl->hash_type);
422         if (ret)
423                 return ret;
424
425         ret = ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
426         if (ret)
427                 return ret;
428
429         ret = ndr_write_bytes(n, acl->desc, acl->desc_len);
430         if (ret)
431                 return ret;
432
433         ret = ndr_write_int64(n, acl->current_time);
434         if (ret)
435                 return ret;
436
437         ret = ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
438         if (ret)
439                 return ret;
440
441         /* push ndr for security descriptor */
442         ret = ndr_write_bytes(n, acl->sd_buf, acl->sd_size);
443         return ret;
444 }
445
446 int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
447 {
448         unsigned int version2;
449         int ret;
450
451         n->offset = 0;
452         ret = ndr_read_int16(n, &acl->version);
453         if (ret)
454                 return ret;
455         if (acl->version != 4) {
456                 pr_err("v%d version is not supported\n", acl->version);
457                 return -EINVAL;
458         }
459
460         ret = ndr_read_int32(n, &version2);
461         if (ret)
462                 return ret;
463         if (acl->version != version2) {
464                 pr_err("ndr version mismatched(version: %d, version2: %d)\n",
465                        acl->version, version2);
466                 return -EINVAL;
467         }
468
469         /* Read Level */
470         ret = ndr_read_int16(n, NULL);
471         if (ret)
472                 return ret;
473
474         /* Read Ref Id */
475         ret = ndr_read_int32(n, NULL);
476         if (ret)
477                 return ret;
478
479         ret = ndr_read_int16(n, &acl->hash_type);
480         if (ret)
481                 return ret;
482
483         ret = ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
484         if (ret)
485                 return ret;
486
487         ndr_read_bytes(n, acl->desc, 10);
488         if (strncmp(acl->desc, "posix_acl", 9)) {
489                 pr_err("Invalid acl description : %s\n", acl->desc);
490                 return -EINVAL;
491         }
492
493         /* Read Time */
494         ret = ndr_read_int64(n, NULL);
495         if (ret)
496                 return ret;
497
498         /* Read Posix ACL hash */
499         ret = ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
500         if (ret)
501                 return ret;
502
503         acl->sd_size = n->length - n->offset;
504         acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL);
505         if (!acl->sd_buf)
506                 return -ENOMEM;
507
508         ret = ndr_read_bytes(n, acl->sd_buf, acl->sd_size);
509         return ret;
510 }