linux/fs/cifs/cifsacl.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/cifsacl.c
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2007,2008
   5 *   Author(s): Steve French (sfrench@us.ibm.com)
   6 *
   7 *   Contains the routines for mapping CIFS/NTFS ACLs
   8 *
   9 *   This library is free software; you can redistribute it and/or modify
  10 *   it under the terms of the GNU Lesser General Public License as published
  11 *   by the Free Software Foundation; either version 2.1 of the License, or
  12 *   (at your option) any later version.
  13 *
  14 *   This library is distributed in the hope that it will be useful,
  15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  17 *   the GNU Lesser General Public License for more details.
  18 *
  19 *   You should have received a copy of the GNU Lesser General Public License
  20 *   along with this library; if not, write to the Free Software
  21 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22 */
  23
  24#include <linux/fs.h>
  25#include <linux/slab.h>
  26#include <linux/string.h>
  27#include <linux/keyctl.h>
  28#include <linux/key-type.h>
  29#include <keys/user-type.h>
  30#include "cifspdu.h"
  31#include "cifsglob.h"
  32#include "cifsacl.h"
  33#include "cifsproto.h"
  34#include "cifs_debug.h"
  35
  36/* security id for everyone/world system group */
  37static const struct cifs_sid sid_everyone = {
  38        1, 1, {0, 0, 0, 0, 0, 1}, {0} };
  39/* security id for Authenticated Users system group */
  40static const struct cifs_sid sid_authusers = {
  41        1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
  42/* group users */
  43static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
  44
  45static const struct cred *root_cred;
  46
  47static int
  48cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
  49{
  50        char *payload;
  51
  52        /*
  53         * If the payload is less than or equal to the size of a pointer, then
  54         * an allocation here is wasteful. Just copy the data directly to the
  55         * payload.value union member instead.
  56         *
  57         * With this however, you must check the datalen before trying to
  58         * dereference payload.data!
  59         */
  60        if (prep->datalen <= sizeof(key->payload)) {
  61                key->payload.value = 0;
  62                memcpy(&key->payload.value, prep->data, prep->datalen);
  63                key->datalen = prep->datalen;
  64                return 0;
  65        }
  66        payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
  67        if (!payload)
  68                return -ENOMEM;
  69
  70        key->payload.data = payload;
  71        key->datalen = prep->datalen;
  72        return 0;
  73}
  74
  75static inline void
  76cifs_idmap_key_destroy(struct key *key)
  77{
  78        if (key->datalen > sizeof(key->payload))
  79                kfree(key->payload.data);
  80}
  81
  82static struct key_type cifs_idmap_key_type = {
  83        .name        = "cifs.idmap",
  84        .instantiate = cifs_idmap_key_instantiate,
  85        .destroy     = cifs_idmap_key_destroy,
  86        .describe    = user_describe,
  87        .match       = user_match,
  88};
  89
  90static char *
  91sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
  92{
  93        int i, len;
  94        unsigned int saval;
  95        char *sidstr, *strptr;
  96        unsigned long long id_auth_val;
  97
  98        /* 3 bytes for prefix */
  99        sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
 100                         (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
 101                         GFP_KERNEL);
 102        if (!sidstr)
 103                return sidstr;
 104
 105        strptr = sidstr;
 106        len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
 107                        sidptr->revision);
 108        strptr += len;
 109
 110        /* The authority field is a single 48-bit number */
 111        id_auth_val = (unsigned long long)sidptr->authority[5];
 112        id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
 113        id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
 114        id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
 115        id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
 116        id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
 117
 118        /*
 119         * MS-DTYP states that if the authority is >= 2^32, then it should be
 120         * expressed as a hex value.
 121         */
 122        if (id_auth_val <= UINT_MAX)
 123                len = sprintf(strptr, "-%llu", id_auth_val);
 124        else
 125                len = sprintf(strptr, "-0x%llx", id_auth_val);
 126
 127        strptr += len;
 128
 129        for (i = 0; i < sidptr->num_subauth; ++i) {
 130                saval = le32_to_cpu(sidptr->sub_auth[i]);
 131                len = sprintf(strptr, "-%u", saval);
 132                strptr += len;
 133        }
 134
 135        return sidstr;
 136}
 137
 138/*
 139 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
 140 * the same returns zero, if they do not match returns non-zero.
 141 */
 142static int
 143compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
 144{
 145        int i;
 146        int num_subauth, num_sat, num_saw;
 147
 148        if ((!ctsid) || (!cwsid))
 149                return 1;
 150
 151        /* compare the revision */
 152        if (ctsid->revision != cwsid->revision) {
 153                if (ctsid->revision > cwsid->revision)
 154                        return 1;
 155                else
 156                        return -1;
 157        }
 158
 159        /* compare all of the six auth values */
 160        for (i = 0; i < NUM_AUTHS; ++i) {
 161                if (ctsid->authority[i] != cwsid->authority[i]) {
 162                        if (ctsid->authority[i] > cwsid->authority[i])
 163                                return 1;
 164                        else
 165                                return -1;
 166                }
 167        }
 168
 169        /* compare all of the subauth values if any */
 170        num_sat = ctsid->num_subauth;
 171        num_saw = cwsid->num_subauth;
 172        num_subauth = num_sat < num_saw ? num_sat : num_saw;
 173        if (num_subauth) {
 174                for (i = 0; i < num_subauth; ++i) {
 175                        if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
 176                                if (le32_to_cpu(ctsid->sub_auth[i]) >
 177                                        le32_to_cpu(cwsid->sub_auth[i]))
 178                                        return 1;
 179                                else
 180                                        return -1;
 181                        }
 182                }
 183        }
 184
 185        return 0; /* sids compare/match */
 186}
 187
 188static void
 189cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
 190{
 191        int i;
 192
 193        dst->revision = src->revision;
 194        dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
 195        for (i = 0; i < NUM_AUTHS; ++i)
 196                dst->authority[i] = src->authority[i];
 197        for (i = 0; i < dst->num_subauth; ++i)
 198                dst->sub_auth[i] = src->sub_auth[i];
 199}
 200
 201static int
 202id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
 203{
 204        int rc;
 205        struct key *sidkey;
 206        struct cifs_sid *ksid;
 207        unsigned int ksid_size;
 208        char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
 209        const struct cred *saved_cred;
 210
 211        rc = snprintf(desc, sizeof(desc), "%ci:%u",
 212                        sidtype == SIDOWNER ? 'o' : 'g', cid);
 213        if (rc >= sizeof(desc))
 214                return -EINVAL;
 215
 216        rc = 0;
 217        saved_cred = override_creds(root_cred);
 218        sidkey = request_key(&cifs_idmap_key_type, desc, "");
 219        if (IS_ERR(sidkey)) {
 220                rc = -EINVAL;
 221                cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
 222                         __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
 223                goto out_revert_creds;
 224        } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
 225                rc = -EIO;
 226                cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
 227                         __func__, sidkey->datalen);
 228                goto invalidate_key;
 229        }
 230
 231        /*
 232         * A sid is usually too large to be embedded in payload.value, but if
 233         * there are no subauthorities and the host has 8-byte pointers, then
 234         * it could be.
 235         */
 236        ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
 237                (struct cifs_sid *)&sidkey->payload.value :
 238                (struct cifs_sid *)sidkey->payload.data;
 239
 240        ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
 241        if (ksid_size > sidkey->datalen) {
 242                rc = -EIO;
 243                cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
 244                         __func__, sidkey->datalen, ksid_size);
 245                goto invalidate_key;
 246        }
 247
 248        cifs_copy_sid(ssid, ksid);
 249out_key_put:
 250        key_put(sidkey);
 251out_revert_creds:
 252        revert_creds(saved_cred);
 253        return rc;
 254
 255invalidate_key:
 256        key_invalidate(sidkey);
 257        goto out_key_put;
 258}
 259
 260static int
 261sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
 262                struct cifs_fattr *fattr, uint sidtype)
 263{
 264        int rc;
 265        struct key *sidkey;
 266        char *sidstr;
 267        const struct cred *saved_cred;
 268        kuid_t fuid = cifs_sb->mnt_uid;
 269        kgid_t fgid = cifs_sb->mnt_gid;
 270
 271        /*
 272         * If we have too many subauthorities, then something is really wrong.
 273         * Just return an error.
 274         */
 275        if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
 276                cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
 277                         __func__, psid->num_subauth);
 278                return -EIO;
 279        }
 280
 281        sidstr = sid_to_key_str(psid, sidtype);
 282        if (!sidstr)
 283                return -ENOMEM;
 284
 285        saved_cred = override_creds(root_cred);
 286        sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
 287        if (IS_ERR(sidkey)) {
 288                rc = -EINVAL;
 289                cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
 290                         __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
 291                goto out_revert_creds;
 292        }
 293
 294        /*
 295         * FIXME: Here we assume that uid_t and gid_t are same size. It's
 296         * probably a safe assumption but might be better to check based on
 297         * sidtype.
 298         */
 299        BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
 300        if (sidkey->datalen != sizeof(uid_t)) {
 301                rc = -EIO;
 302                cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
 303                         __func__, sidkey->datalen);
 304                key_invalidate(sidkey);
 305                goto out_key_put;
 306        }
 307
 308        if (sidtype == SIDOWNER) {
 309                kuid_t uid;
 310                uid_t id;
 311                memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
 312                uid = make_kuid(&init_user_ns, id);
 313                if (uid_valid(uid))
 314                        fuid = uid;
 315        } else {
 316                kgid_t gid;
 317                gid_t id;
 318                memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
 319                gid = make_kgid(&init_user_ns, id);
 320                if (gid_valid(gid))
 321                        fgid = gid;
 322        }
 323
 324out_key_put:
 325        key_put(sidkey);
 326out_revert_creds:
 327        revert_creds(saved_cred);
 328        kfree(sidstr);
 329
 330        /*
 331         * Note that we return 0 here unconditionally. If the mapping
 332         * fails then we just fall back to using the mnt_uid/mnt_gid.
 333         */
 334        if (sidtype == SIDOWNER)
 335                fattr->cf_uid = fuid;
 336        else
 337                fattr->cf_gid = fgid;
 338        return 0;
 339}
 340
 341int
 342init_cifs_idmap(void)
 343{
 344        struct cred *cred;
 345        struct key *keyring;
 346        int ret;
 347
 348        cifs_dbg(FYI, "Registering the %s key type\n",
 349                 cifs_idmap_key_type.name);
 350
 351        /* create an override credential set with a special thread keyring in
 352         * which requests are cached
 353         *
 354         * this is used to prevent malicious redirections from being installed
 355         * with add_key().
 356         */
 357        cred = prepare_kernel_cred(NULL);
 358        if (!cred)
 359                return -ENOMEM;
 360
 361        keyring = keyring_alloc(".cifs_idmap",
 362                                GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
 363                                (KEY_POS_ALL & ~KEY_POS_SETATTR) |
 364                                KEY_USR_VIEW | KEY_USR_READ,
 365                                KEY_ALLOC_NOT_IN_QUOTA, NULL);
 366        if (IS_ERR(keyring)) {
 367                ret = PTR_ERR(keyring);
 368                goto failed_put_cred;
 369        }
 370
 371        ret = register_key_type(&cifs_idmap_key_type);
 372        if (ret < 0)
 373                goto failed_put_key;
 374
 375        /* instruct request_key() to use this special keyring as a cache for
 376         * the results it looks up */
 377        set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
 378        cred->thread_keyring = keyring;
 379        cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
 380        root_cred = cred;
 381
 382        cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
 383        return 0;
 384
 385failed_put_key:
 386        key_put(keyring);
 387failed_put_cred:
 388        put_cred(cred);
 389        return ret;
 390}
 391
 392void
 393exit_cifs_idmap(void)
 394{
 395        key_revoke(root_cred->thread_keyring);
 396        unregister_key_type(&cifs_idmap_key_type);
 397        put_cred(root_cred);
 398        cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
 399}
 400
 401/* copy ntsd, owner sid, and group sid from a security descriptor to another */
 402static void copy_sec_desc(const struct cifs_ntsd *pntsd,
 403                                struct cifs_ntsd *pnntsd, __u32 sidsoffset)
 404{
 405        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
 406        struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
 407
 408        /* copy security descriptor control portion */
 409        pnntsd->revision = pntsd->revision;
 410        pnntsd->type = pntsd->type;
 411        pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
 412        pnntsd->sacloffset = 0;
 413        pnntsd->osidoffset = cpu_to_le32(sidsoffset);
 414        pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
 415
 416        /* copy owner sid */
 417        owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 418                                le32_to_cpu(pntsd->osidoffset));
 419        nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
 420        cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
 421
 422        /* copy group sid */
 423        group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 424                                le32_to_cpu(pntsd->gsidoffset));
 425        ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
 426                                        sizeof(struct cifs_sid));
 427        cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
 428
 429        return;
 430}
 431
 432
 433/*
 434   change posix mode to reflect permissions
 435   pmode is the existing mode (we only want to overwrite part of this
 436   bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
 437*/
 438static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
 439                                 umode_t *pbits_to_set)
 440{
 441        __u32 flags = le32_to_cpu(ace_flags);
 442        /* the order of ACEs is important.  The canonical order is to begin with
 443           DENY entries followed by ALLOW, otherwise an allow entry could be
 444           encountered first, making the subsequent deny entry like "dead code"
 445           which would be superflous since Windows stops when a match is made
 446           for the operation you are trying to perform for your user */
 447
 448        /* For deny ACEs we change the mask so that subsequent allow access
 449           control entries do not turn on the bits we are denying */
 450        if (type == ACCESS_DENIED) {
 451                if (flags & GENERIC_ALL)
 452                        *pbits_to_set &= ~S_IRWXUGO;
 453
 454                if ((flags & GENERIC_WRITE) ||
 455                        ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
 456                        *pbits_to_set &= ~S_IWUGO;
 457                if ((flags & GENERIC_READ) ||
 458                        ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
 459                        *pbits_to_set &= ~S_IRUGO;
 460                if ((flags & GENERIC_EXECUTE) ||
 461                        ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
 462                        *pbits_to_set &= ~S_IXUGO;
 463                return;
 464        } else if (type != ACCESS_ALLOWED) {
 465                cifs_dbg(VFS, "unknown access control type %d\n", type);
 466                return;
 467        }
 468        /* else ACCESS_ALLOWED type */
 469
 470        if (flags & GENERIC_ALL) {
 471                *pmode |= (S_IRWXUGO & (*pbits_to_set));
 472                cifs_dbg(NOISY, "all perms\n");
 473                return;
 474        }
 475        if ((flags & GENERIC_WRITE) ||
 476                        ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
 477                *pmode |= (S_IWUGO & (*pbits_to_set));
 478        if ((flags & GENERIC_READ) ||
 479                        ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
 480                *pmode |= (S_IRUGO & (*pbits_to_set));
 481        if ((flags & GENERIC_EXECUTE) ||
 482                        ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
 483                *pmode |= (S_IXUGO & (*pbits_to_set));
 484
 485        cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
 486        return;
 487}
 488
 489/*
 490   Generate access flags to reflect permissions mode is the existing mode.
 491   This function is called for every ACE in the DACL whose SID matches
 492   with either owner or group or everyone.
 493*/
 494
 495static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
 496                                __u32 *pace_flags)
 497{
 498        /* reset access mask */
 499        *pace_flags = 0x0;
 500
 501        /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
 502        mode &= bits_to_use;
 503
 504        /* check for R/W/X UGO since we do not know whose flags
 505           is this but we have cleared all the bits sans RWX for
 506           either user or group or other as per bits_to_use */
 507        if (mode & S_IRUGO)
 508                *pace_flags |= SET_FILE_READ_RIGHTS;
 509        if (mode & S_IWUGO)
 510                *pace_flags |= SET_FILE_WRITE_RIGHTS;
 511        if (mode & S_IXUGO)
 512                *pace_flags |= SET_FILE_EXEC_RIGHTS;
 513
 514        cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
 515                 mode, *pace_flags);
 516        return;
 517}
 518
 519static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
 520                        const struct cifs_sid *psid, __u64 nmode, umode_t bits)
 521{
 522        int i;
 523        __u16 size = 0;
 524        __u32 access_req = 0;
 525
 526        pntace->type = ACCESS_ALLOWED;
 527        pntace->flags = 0x0;
 528        mode_to_access_flags(nmode, bits, &access_req);
 529        if (!access_req)
 530                access_req = SET_MINIMUM_RIGHTS;
 531        pntace->access_req = cpu_to_le32(access_req);
 532
 533        pntace->sid.revision = psid->revision;
 534        pntace->sid.num_subauth = psid->num_subauth;
 535        for (i = 0; i < NUM_AUTHS; i++)
 536                pntace->sid.authority[i] = psid->authority[i];
 537        for (i = 0; i < psid->num_subauth; i++)
 538                pntace->sid.sub_auth[i] = psid->sub_auth[i];
 539
 540        size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
 541        pntace->size = cpu_to_le16(size);
 542
 543        return size;
 544}
 545
 546
 547#ifdef CONFIG_CIFS_DEBUG2
 548static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
 549{
 550        int num_subauth;
 551
 552        /* validate that we do not go past end of acl */
 553
 554        if (le16_to_cpu(pace->size) < 16) {
 555                cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
 556                return;
 557        }
 558
 559        if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
 560                cifs_dbg(VFS, "ACL too small to parse ACE\n");
 561                return;
 562        }
 563
 564        num_subauth = pace->sid.num_subauth;
 565        if (num_subauth) {
 566                int i;
 567                cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
 568                         pace->sid.revision, pace->sid.num_subauth, pace->type,
 569                         pace->flags, le16_to_cpu(pace->size));
 570                for (i = 0; i < num_subauth; ++i) {
 571                        cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
 572                                 i, le32_to_cpu(pace->sid.sub_auth[i]));
 573                }
 574
 575                /* BB add length check to make sure that we do not have huge
 576                        num auths and therefore go off the end */
 577        }
 578
 579        return;
 580}
 581#endif
 582
 583
 584static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
 585                       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
 586                       struct cifs_fattr *fattr)
 587{
 588        int i;
 589        int num_aces = 0;
 590        int acl_size;
 591        char *acl_base;
 592        struct cifs_ace **ppace;
 593
 594        /* BB need to add parm so we can store the SID BB */
 595
 596        if (!pdacl) {
 597                /* no DACL in the security descriptor, set
 598                   all the permissions for user/group/other */
 599                fattr->cf_mode |= S_IRWXUGO;
 600                return;
 601        }
 602
 603        /* validate that we do not go past end of acl */
 604        if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
 605                cifs_dbg(VFS, "ACL too small to parse DACL\n");
 606                return;
 607        }
 608
 609        cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
 610                 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
 611                 le32_to_cpu(pdacl->num_aces));
 612
 613        /* reset rwx permissions for user/group/other.
 614           Also, if num_aces is 0 i.e. DACL has no ACEs,
 615           user/group/other have no permissions */
 616        fattr->cf_mode &= ~(S_IRWXUGO);
 617
 618        acl_base = (char *)pdacl;
 619        acl_size = sizeof(struct cifs_acl);
 620
 621        num_aces = le32_to_cpu(pdacl->num_aces);
 622        if (num_aces > 0) {
 623                umode_t user_mask = S_IRWXU;
 624                umode_t group_mask = S_IRWXG;
 625                umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
 626
 627                if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
 628                        return;
 629                ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
 630                                GFP_KERNEL);
 631                if (!ppace)
 632                        return;
 633
 634                for (i = 0; i < num_aces; ++i) {
 635                        ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
 636#ifdef CONFIG_CIFS_DEBUG2
 637                        dump_ace(ppace[i], end_of_acl);
 638#endif
 639                        if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
 640                                access_flags_to_mode(ppace[i]->access_req,
 641                                                     ppace[i]->type,
 642                                                     &fattr->cf_mode,
 643                                                     &user_mask);
 644                        if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
 645                                access_flags_to_mode(ppace[i]->access_req,
 646                                                     ppace[i]->type,
 647                                                     &fattr->cf_mode,
 648                                                     &group_mask);
 649                        if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
 650                                access_flags_to_mode(ppace[i]->access_req,
 651                                                     ppace[i]->type,
 652                                                     &fattr->cf_mode,
 653                                                     &other_mask);
 654                        if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
 655                                access_flags_to_mode(ppace[i]->access_req,
 656                                                     ppace[i]->type,
 657                                                     &fattr->cf_mode,
 658                                                     &other_mask);
 659
 660
 661/*                      memcpy((void *)(&(cifscred->aces[i])),
 662                                (void *)ppace[i],
 663                                sizeof(struct cifs_ace)); */
 664
 665                        acl_base = (char *)ppace[i];
 666                        acl_size = le16_to_cpu(ppace[i]->size);
 667                }
 668
 669                kfree(ppace);
 670        }
 671
 672        return;
 673}
 674
 675
 676static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
 677                        struct cifs_sid *pgrpsid, __u64 nmode)
 678{
 679        u16 size = 0;
 680        struct cifs_acl *pnndacl;
 681
 682        pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
 683
 684        size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
 685                                        pownersid, nmode, S_IRWXU);
 686        size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
 687                                        pgrpsid, nmode, S_IRWXG);
 688        size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
 689                                         &sid_everyone, nmode, S_IRWXO);
 690
 691        pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
 692        pndacl->num_aces = cpu_to_le32(3);
 693
 694        return 0;
 695}
 696
 697
 698static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
 699{
 700        /* BB need to add parm so we can store the SID BB */
 701
 702        /* validate that we do not go past end of ACL - sid must be at least 8
 703           bytes long (assuming no sub-auths - e.g. the null SID */
 704        if (end_of_acl < (char *)psid + 8) {
 705                cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
 706                return -EINVAL;
 707        }
 708
 709#ifdef CONFIG_CIFS_DEBUG2
 710        if (psid->num_subauth) {
 711                int i;
 712                cifs_dbg(FYI, "SID revision %d num_auth %d\n",
 713                         psid->revision, psid->num_subauth);
 714
 715                for (i = 0; i < psid->num_subauth; i++) {
 716                        cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
 717                                 i, le32_to_cpu(psid->sub_auth[i]));
 718                }
 719
 720                /* BB add length check to make sure that we do not have huge
 721                        num auths and therefore go off the end */
 722                cifs_dbg(FYI, "RID 0x%x\n",
 723                         le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
 724        }
 725#endif
 726
 727        return 0;
 728}
 729
 730
 731/* Convert CIFS ACL to POSIX form */
 732static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
 733                struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
 734{
 735        int rc = 0;
 736        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
 737        struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
 738        char *end_of_acl = ((char *)pntsd) + acl_len;
 739        __u32 dacloffset;
 740
 741        if (pntsd == NULL)
 742                return -EIO;
 743
 744        owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 745                                le32_to_cpu(pntsd->osidoffset));
 746        group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 747                                le32_to_cpu(pntsd->gsidoffset));
 748        dacloffset = le32_to_cpu(pntsd->dacloffset);
 749        dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
 750        cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
 751                 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
 752                 le32_to_cpu(pntsd->gsidoffset),
 753                 le32_to_cpu(pntsd->sacloffset), dacloffset);
 754/*      cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
 755        rc = parse_sid(owner_sid_ptr, end_of_acl);
 756        if (rc) {
 757                cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
 758                return rc;
 759        }
 760        rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
 761        if (rc) {
 762                cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
 763                         __func__, rc);
 764                return rc;
 765        }
 766
 767        rc = parse_sid(group_sid_ptr, end_of_acl);
 768        if (rc) {
 769                cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
 770                         __func__, rc);
 771                return rc;
 772        }
 773        rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
 774        if (rc) {
 775                cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
 776                         __func__, rc);
 777                return rc;
 778        }
 779
 780        if (dacloffset)
 781                parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
 782                           group_sid_ptr, fattr);
 783        else
 784                cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
 785
 786        return rc;
 787}
 788
 789/* Convert permission bits from mode to equivalent CIFS ACL */
 790static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
 791        __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
 792{
 793        int rc = 0;
 794        __u32 dacloffset;
 795        __u32 ndacloffset;
 796        __u32 sidsoffset;
 797        struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
 798        struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
 799        struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
 800        struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
 801
 802        if (nmode != NO_CHANGE_64) { /* chmod */
 803                owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 804                                le32_to_cpu(pntsd->osidoffset));
 805                group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
 806                                le32_to_cpu(pntsd->gsidoffset));
 807                dacloffset = le32_to_cpu(pntsd->dacloffset);
 808                dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
 809                ndacloffset = sizeof(struct cifs_ntsd);
 810                ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
 811                ndacl_ptr->revision = dacl_ptr->revision;
 812                ndacl_ptr->size = 0;
 813                ndacl_ptr->num_aces = 0;
 814
 815                rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
 816                                        nmode);
 817                sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
 818                /* copy sec desc control portion & owner and group sids */
 819                copy_sec_desc(pntsd, pnntsd, sidsoffset);
 820                *aclflag = CIFS_ACL_DACL;
 821        } else {
 822                memcpy(pnntsd, pntsd, secdesclen);
 823                if (uid_valid(uid)) { /* chown */
 824                        uid_t id;
 825                        owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
 826                                        le32_to_cpu(pnntsd->osidoffset));
 827                        nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
 828                                                                GFP_KERNEL);
 829                        if (!nowner_sid_ptr)
 830                                return -ENOMEM;
 831                        id = from_kuid(&init_user_ns, uid);
 832                        rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
 833                        if (rc) {
 834                                cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
 835                                         __func__, rc, id);
 836                                kfree(nowner_sid_ptr);
 837                                return rc;
 838                        }
 839                        cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
 840                        kfree(nowner_sid_ptr);
 841                        *aclflag = CIFS_ACL_OWNER;
 842                }
 843                if (gid_valid(gid)) { /* chgrp */
 844                        gid_t id;
 845                        group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
 846                                        le32_to_cpu(pnntsd->gsidoffset));
 847                        ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
 848                                                                GFP_KERNEL);
 849                        if (!ngroup_sid_ptr)
 850                                return -ENOMEM;
 851                        id = from_kgid(&init_user_ns, gid);
 852                        rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
 853                        if (rc) {
 854                                cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
 855                                         __func__, rc, id);
 856                                kfree(ngroup_sid_ptr);
 857                                return rc;
 858                        }
 859                        cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
 860                        kfree(ngroup_sid_ptr);
 861                        *aclflag = CIFS_ACL_GROUP;
 862                }
 863        }
 864
 865        return rc;
 866}
 867
 868static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
 869                __u16 fid, u32 *pacllen)
 870{
 871        struct cifs_ntsd *pntsd = NULL;
 872        unsigned int xid;
 873        int rc;
 874        struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 875
 876        if (IS_ERR(tlink))
 877                return ERR_CAST(tlink);
 878
 879        xid = get_xid();
 880        rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
 881        free_xid(xid);
 882
 883        cifs_put_tlink(tlink);
 884
 885        cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
 886        if (rc)
 887                return ERR_PTR(rc);
 888        return pntsd;
 889}
 890
 891static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
 892                const char *path, u32 *pacllen)
 893{
 894        struct cifs_ntsd *pntsd = NULL;
 895        int oplock = 0;
 896        unsigned int xid;
 897        int rc, create_options = 0;
 898        __u16 fid;
 899        struct cifs_tcon *tcon;
 900        struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 901
 902        if (IS_ERR(tlink))
 903                return ERR_CAST(tlink);
 904
 905        tcon = tlink_tcon(tlink);
 906        xid = get_xid();
 907
 908        if (backup_cred(cifs_sb))
 909                create_options |= CREATE_OPEN_BACKUP_INTENT;
 910
 911        rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
 912                        create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
 913                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 914        if (!rc) {
 915                rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
 916                CIFSSMBClose(xid, tcon, fid);
 917        }
 918
 919        cifs_put_tlink(tlink);
 920        free_xid(xid);
 921
 922        cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
 923        if (rc)
 924                return ERR_PTR(rc);
 925        return pntsd;
 926}
 927
 928/* Retrieve an ACL from the server */
 929struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
 930                                      struct inode *inode, const char *path,
 931                                      u32 *pacllen)
 932{
 933        struct cifs_ntsd *pntsd = NULL;
 934        struct cifsFileInfo *open_file = NULL;
 935
 936        if (inode)
 937                open_file = find_readable_file(CIFS_I(inode), true);
 938        if (!open_file)
 939                return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 940
 941        pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
 942        cifsFileInfo_put(open_file);
 943        return pntsd;
 944}
 945
 946 /* Set an ACL on the server */
 947int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
 948                        struct inode *inode, const char *path, int aclflag)
 949{
 950        int oplock = 0;
 951        unsigned int xid;
 952        int rc, access_flags, create_options = 0;
 953        __u16 fid;
 954        struct cifs_tcon *tcon;
 955        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 956        struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
 957
 958        if (IS_ERR(tlink))
 959                return PTR_ERR(tlink);
 960
 961        tcon = tlink_tcon(tlink);
 962        xid = get_xid();
 963
 964        if (backup_cred(cifs_sb))
 965                create_options |= CREATE_OPEN_BACKUP_INTENT;
 966
 967        if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
 968                access_flags = WRITE_OWNER;
 969        else
 970                access_flags = WRITE_DAC;
 971
 972        rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
 973                        create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
 974                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 975        if (rc) {
 976                cifs_dbg(VFS, "Unable to open file to set ACL\n");
 977                goto out;
 978        }
 979
 980        rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
 981        cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
 982
 983        CIFSSMBClose(xid, tcon, fid);
 984out:
 985        free_xid(xid);
 986        cifs_put_tlink(tlink);
 987        return rc;
 988}
 989
 990/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
 991int
 992cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
 993                  struct inode *inode, const char *path, const __u16 *pfid)
 994{
 995        struct cifs_ntsd *pntsd = NULL;
 996        u32 acllen = 0;
 997        int rc = 0;
 998
 999        cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
1000
1001        if (pfid)
1002                pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1003        else
1004                pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
1005
1006        /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
1007        if (IS_ERR(pntsd)) {
1008                rc = PTR_ERR(pntsd);
1009                cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
1010        } else {
1011                rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
1012                kfree(pntsd);
1013                if (rc)
1014                        cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
1015        }
1016
1017        return rc;
1018}
1019
1020/* Convert mode bits to an ACL so we can update the ACL on the server */
1021int
1022id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1023                        kuid_t uid, kgid_t gid)
1024{
1025        int rc = 0;
1026        int aclflag = CIFS_ACL_DACL; /* default flag to set */
1027        __u32 secdesclen = 0;
1028        struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1029        struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
1030
1031        cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
1032
1033        /* Get the security descriptor */
1034        pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
1035        if (IS_ERR(pntsd)) {
1036                rc = PTR_ERR(pntsd);
1037                cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
1038                goto out;
1039        }
1040
1041        /*
1042         * Add three ACEs for owner, group, everyone getting rid of other ACEs
1043         * as chmod disables ACEs and set the security descriptor. Allocate
1044         * memory for the smb header, set security descriptor request security
1045         * descriptor parameters, and secuirty descriptor itself
1046         */
1047        secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
1048        pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1049        if (!pnntsd) {
1050                kfree(pntsd);
1051                return -ENOMEM;
1052        }
1053
1054        rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1055                                &aclflag);
1056
1057        cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
1058
1059        if (!rc) {
1060                /* Set the security descriptor */
1061                rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1062                cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
1063        }
1064
1065        kfree(pnntsd);
1066        kfree(pntsd);
1067out:
1068        return rc;
1069}
1070
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.