~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/smb/server/ndr.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 mnt_idmap *idmap,
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(idmap, 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(idmap, 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 }
515 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php