linux/fs/ksmbd/ndr.c
<<
>>
Prefs
   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
  12static inline char *ndr_get_field(struct ndr *n)
  13{
  14        return n->data + n->offset;
  15}
  16
  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 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
  46static 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
  61static 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
  76static 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
  91static 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
 110static 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
 126static 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
 137static 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
 148static 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
 159static 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
 170int 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
 229int 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
 296static 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
 340int 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
 393int 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
 446int 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}
 511