GNU Linux-libre 6.1.86-gnu
[releases.git] / fs / smb / server / 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 -EINVAL;
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                 ksmbd_debug(VFS, "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                 ksmbd_debug(VFS, "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         vfsuid_t vfsuid;
349         vfsgid_t vfsgid;
350
351         n->offset = 0;
352         n->length = 1024;
353         n->data = kzalloc(n->length, GFP_KERNEL);
354         if (!n->data)
355                 return -ENOMEM;
356
357         if (acl) {
358                 /* ACL ACCESS */
359                 ret = ndr_write_int32(n, ref_id);
360                 ref_id += 4;
361         } else {
362                 ret = ndr_write_int32(n, 0);
363         }
364         if (ret)
365                 return ret;
366
367         if (def_acl) {
368                 /* DEFAULT ACL ACCESS */
369                 ret = ndr_write_int32(n, ref_id);
370                 ref_id += 4;
371         } else {
372                 ret = ndr_write_int32(n, 0);
373         }
374         if (ret)
375                 return ret;
376
377         vfsuid = i_uid_into_vfsuid(user_ns, inode);
378         ret = ndr_write_int64(n, from_kuid(&init_user_ns, vfsuid_into_kuid(vfsuid)));
379         if (ret)
380                 return ret;
381         vfsgid = i_gid_into_vfsgid(user_ns, inode);
382         ret = ndr_write_int64(n, from_kgid(&init_user_ns, vfsgid_into_kgid(vfsgid)));
383         if (ret)
384                 return ret;
385         ret = ndr_write_int32(n, inode->i_mode);
386         if (ret)
387                 return ret;
388
389         if (acl) {
390                 ret = ndr_encode_posix_acl_entry(n, acl);
391                 if (def_acl && !ret)
392                         ret = ndr_encode_posix_acl_entry(n, def_acl);
393         }
394         return ret;
395 }
396
397 int ndr_encode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
398 {
399         unsigned int ref_id = 0x00020004;
400         int ret;
401
402         n->offset = 0;
403         n->length = 2048;
404         n->data = kzalloc(n->length, GFP_KERNEL);
405         if (!n->data)
406                 return -ENOMEM;
407
408         ret = ndr_write_int16(n, acl->version);
409         if (ret)
410                 return ret;
411
412         ret = ndr_write_int32(n, acl->version);
413         if (ret)
414                 return ret;
415
416         ret = ndr_write_int16(n, 2);
417         if (ret)
418                 return ret;
419
420         ret = ndr_write_int32(n, ref_id);
421         if (ret)
422                 return ret;
423
424         /* push hash type and hash 64bytes */
425         ret = ndr_write_int16(n, acl->hash_type);
426         if (ret)
427                 return ret;
428
429         ret = ndr_write_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
430         if (ret)
431                 return ret;
432
433         ret = ndr_write_bytes(n, acl->desc, acl->desc_len);
434         if (ret)
435                 return ret;
436
437         ret = ndr_write_int64(n, acl->current_time);
438         if (ret)
439                 return ret;
440
441         ret = ndr_write_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
442         if (ret)
443                 return ret;
444
445         /* push ndr for security descriptor */
446         ret = ndr_write_bytes(n, acl->sd_buf, acl->sd_size);
447         return ret;
448 }
449
450 int ndr_decode_v4_ntacl(struct ndr *n, struct xattr_ntacl *acl)
451 {
452         unsigned int version2;
453         int ret;
454
455         n->offset = 0;
456         ret = ndr_read_int16(n, &acl->version);
457         if (ret)
458                 return ret;
459         if (acl->version != 4) {
460                 ksmbd_debug(VFS, "v%d version is not supported\n", acl->version);
461                 return -EINVAL;
462         }
463
464         ret = ndr_read_int32(n, &version2);
465         if (ret)
466                 return ret;
467         if (acl->version != version2) {
468                 ksmbd_debug(VFS, "ndr version mismatched(version: %d, version2: %d)\n",
469                        acl->version, version2);
470                 return -EINVAL;
471         }
472
473         /* Read Level */
474         ret = ndr_read_int16(n, NULL);
475         if (ret)
476                 return ret;
477
478         /* Read Ref Id */
479         ret = ndr_read_int32(n, NULL);
480         if (ret)
481                 return ret;
482
483         ret = ndr_read_int16(n, &acl->hash_type);
484         if (ret)
485                 return ret;
486
487         ret = ndr_read_bytes(n, acl->hash, XATTR_SD_HASH_SIZE);
488         if (ret)
489                 return ret;
490
491         ndr_read_bytes(n, acl->desc, 10);
492         if (strncmp(acl->desc, "posix_acl", 9)) {
493                 pr_err("Invalid acl description : %s\n", acl->desc);
494                 return -EINVAL;
495         }
496
497         /* Read Time */
498         ret = ndr_read_int64(n, NULL);
499         if (ret)
500                 return ret;
501
502         /* Read Posix ACL hash */
503         ret = ndr_read_bytes(n, acl->posix_acl_hash, XATTR_SD_HASH_SIZE);
504         if (ret)
505                 return ret;
506
507         acl->sd_size = n->length - n->offset;
508         acl->sd_buf = kzalloc(acl->sd_size, GFP_KERNEL);
509         if (!acl->sd_buf)
510                 return -ENOMEM;
511
512         ret = ndr_read_bytes(n, acl->sd_buf, acl->sd_size);
513         return ret;
514 }