162306a36Sopenharmony_ci// SPDX-License-Identifier: LGPL-2.1 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2007,2008 562306a36Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Contains the routines for mapping CIFS/NTFS ACLs 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/keyctl.h> 1562306a36Sopenharmony_ci#include <linux/key-type.h> 1662306a36Sopenharmony_ci#include <uapi/linux/posix_acl.h> 1762306a36Sopenharmony_ci#include <linux/posix_acl.h> 1862306a36Sopenharmony_ci#include <linux/posix_acl_xattr.h> 1962306a36Sopenharmony_ci#include <keys/user-type.h> 2062306a36Sopenharmony_ci#include "cifspdu.h" 2162306a36Sopenharmony_ci#include "cifsglob.h" 2262306a36Sopenharmony_ci#include "cifsacl.h" 2362306a36Sopenharmony_ci#include "cifsproto.h" 2462306a36Sopenharmony_ci#include "cifs_debug.h" 2562306a36Sopenharmony_ci#include "fs_context.h" 2662306a36Sopenharmony_ci#include "cifs_fs_sb.h" 2762306a36Sopenharmony_ci#include "cifs_unicode.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* security id for everyone/world system group */ 3062306a36Sopenharmony_cistatic const struct cifs_sid sid_everyone = { 3162306a36Sopenharmony_ci 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; 3262306a36Sopenharmony_ci/* security id for Authenticated Users system group */ 3362306a36Sopenharmony_cistatic const struct cifs_sid sid_authusers = { 3462306a36Sopenharmony_ci 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} }; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* S-1-22-1 Unmapped Unix users */ 3762306a36Sopenharmony_cistatic const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22}, 3862306a36Sopenharmony_ci {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* S-1-22-2 Unmapped Unix groups */ 4162306a36Sopenharmony_cistatic const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, 4262306a36Sopenharmony_ci {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * See https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* S-1-5-88 MS NFS and Apple style UID/GID/mode */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* S-1-5-88-1 Unix uid */ 5162306a36Sopenharmony_cistatic const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5}, 5262306a36Sopenharmony_ci {cpu_to_le32(88), 5362306a36Sopenharmony_ci cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* S-1-5-88-2 Unix gid */ 5662306a36Sopenharmony_cistatic const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5}, 5762306a36Sopenharmony_ci {cpu_to_le32(88), 5862306a36Sopenharmony_ci cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* S-1-5-88-3 Unix mode */ 6162306a36Sopenharmony_cistatic const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5}, 6262306a36Sopenharmony_ci {cpu_to_le32(88), 6362306a36Sopenharmony_ci cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic const struct cred *root_cred; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int 6862306a36Sopenharmony_cicifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci char *payload; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* 7362306a36Sopenharmony_ci * If the payload is less than or equal to the size of a pointer, then 7462306a36Sopenharmony_ci * an allocation here is wasteful. Just copy the data directly to the 7562306a36Sopenharmony_ci * payload.value union member instead. 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * With this however, you must check the datalen before trying to 7862306a36Sopenharmony_ci * dereference payload.data! 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci if (prep->datalen <= sizeof(key->payload)) { 8162306a36Sopenharmony_ci key->payload.data[0] = NULL; 8262306a36Sopenharmony_ci memcpy(&key->payload, prep->data, prep->datalen); 8362306a36Sopenharmony_ci } else { 8462306a36Sopenharmony_ci payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL); 8562306a36Sopenharmony_ci if (!payload) 8662306a36Sopenharmony_ci return -ENOMEM; 8762306a36Sopenharmony_ci key->payload.data[0] = payload; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci key->datalen = prep->datalen; 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic inline void 9562306a36Sopenharmony_cicifs_idmap_key_destroy(struct key *key) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci if (key->datalen > sizeof(key->payload)) 9862306a36Sopenharmony_ci kfree(key->payload.data[0]); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic struct key_type cifs_idmap_key_type = { 10262306a36Sopenharmony_ci .name = "cifs.idmap", 10362306a36Sopenharmony_ci .instantiate = cifs_idmap_key_instantiate, 10462306a36Sopenharmony_ci .destroy = cifs_idmap_key_destroy, 10562306a36Sopenharmony_ci .describe = user_describe, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic char * 10962306a36Sopenharmony_cisid_to_key_str(struct cifs_sid *sidptr, unsigned int type) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci int i, len; 11262306a36Sopenharmony_ci unsigned int saval; 11362306a36Sopenharmony_ci char *sidstr, *strptr; 11462306a36Sopenharmony_ci unsigned long long id_auth_val; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 3 bytes for prefix */ 11762306a36Sopenharmony_ci sidstr = kmalloc(3 + SID_STRING_BASE_SIZE + 11862306a36Sopenharmony_ci (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth), 11962306a36Sopenharmony_ci GFP_KERNEL); 12062306a36Sopenharmony_ci if (!sidstr) 12162306a36Sopenharmony_ci return sidstr; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci strptr = sidstr; 12462306a36Sopenharmony_ci len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g', 12562306a36Sopenharmony_ci sidptr->revision); 12662306a36Sopenharmony_ci strptr += len; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* The authority field is a single 48-bit number */ 12962306a36Sopenharmony_ci id_auth_val = (unsigned long long)sidptr->authority[5]; 13062306a36Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[4] << 8; 13162306a36Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[3] << 16; 13262306a36Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[2] << 24; 13362306a36Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[1] << 32; 13462306a36Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[0] << 48; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * MS-DTYP states that if the authority is >= 2^32, then it should be 13862306a36Sopenharmony_ci * expressed as a hex value. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci if (id_auth_val <= UINT_MAX) 14162306a36Sopenharmony_ci len = sprintf(strptr, "-%llu", id_auth_val); 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci len = sprintf(strptr, "-0x%llx", id_auth_val); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci strptr += len; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci for (i = 0; i < sidptr->num_subauth; ++i) { 14862306a36Sopenharmony_ci saval = le32_to_cpu(sidptr->sub_auth[i]); 14962306a36Sopenharmony_ci len = sprintf(strptr, "-%u", saval); 15062306a36Sopenharmony_ci strptr += len; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return sidstr; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * if the two SIDs (roughly equivalent to a UUID for a user or group) are 15862306a36Sopenharmony_ci * the same returns zero, if they do not match returns non-zero. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_cistatic int 16162306a36Sopenharmony_cicompare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci int i; 16462306a36Sopenharmony_ci int num_subauth, num_sat, num_saw; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if ((!ctsid) || (!cwsid)) 16762306a36Sopenharmony_ci return 1; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* compare the revision */ 17062306a36Sopenharmony_ci if (ctsid->revision != cwsid->revision) { 17162306a36Sopenharmony_ci if (ctsid->revision > cwsid->revision) 17262306a36Sopenharmony_ci return 1; 17362306a36Sopenharmony_ci else 17462306a36Sopenharmony_ci return -1; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* compare all of the six auth values */ 17862306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; ++i) { 17962306a36Sopenharmony_ci if (ctsid->authority[i] != cwsid->authority[i]) { 18062306a36Sopenharmony_ci if (ctsid->authority[i] > cwsid->authority[i]) 18162306a36Sopenharmony_ci return 1; 18262306a36Sopenharmony_ci else 18362306a36Sopenharmony_ci return -1; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* compare all of the subauth values if any */ 18862306a36Sopenharmony_ci num_sat = ctsid->num_subauth; 18962306a36Sopenharmony_ci num_saw = cwsid->num_subauth; 19062306a36Sopenharmony_ci num_subauth = num_sat < num_saw ? num_sat : num_saw; 19162306a36Sopenharmony_ci if (num_subauth) { 19262306a36Sopenharmony_ci for (i = 0; i < num_subauth; ++i) { 19362306a36Sopenharmony_ci if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { 19462306a36Sopenharmony_ci if (le32_to_cpu(ctsid->sub_auth[i]) > 19562306a36Sopenharmony_ci le32_to_cpu(cwsid->sub_auth[i])) 19662306a36Sopenharmony_ci return 1; 19762306a36Sopenharmony_ci else 19862306a36Sopenharmony_ci return -1; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; /* sids compare/match */ 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic bool 20762306a36Sopenharmony_ciis_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci int i; 21062306a36Sopenharmony_ci int num_subauth; 21162306a36Sopenharmony_ci const struct cifs_sid *pwell_known_sid; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (!psid || (puid == NULL)) 21462306a36Sopenharmony_ci return false; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci num_subauth = psid->num_subauth; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */ 21962306a36Sopenharmony_ci if (num_subauth == 2) { 22062306a36Sopenharmony_ci if (is_group) 22162306a36Sopenharmony_ci pwell_known_sid = &sid_unix_groups; 22262306a36Sopenharmony_ci else 22362306a36Sopenharmony_ci pwell_known_sid = &sid_unix_users; 22462306a36Sopenharmony_ci } else if (num_subauth == 3) { 22562306a36Sopenharmony_ci if (is_group) 22662306a36Sopenharmony_ci pwell_known_sid = &sid_unix_NFS_groups; 22762306a36Sopenharmony_ci else 22862306a36Sopenharmony_ci pwell_known_sid = &sid_unix_NFS_users; 22962306a36Sopenharmony_ci } else 23062306a36Sopenharmony_ci return false; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* compare the revision */ 23362306a36Sopenharmony_ci if (psid->revision != pwell_known_sid->revision) 23462306a36Sopenharmony_ci return false; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* compare all of the six auth values */ 23762306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; ++i) { 23862306a36Sopenharmony_ci if (psid->authority[i] != pwell_known_sid->authority[i]) { 23962306a36Sopenharmony_ci cifs_dbg(FYI, "auth %d did not match\n", i); 24062306a36Sopenharmony_ci return false; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (num_subauth == 2) { 24562306a36Sopenharmony_ci if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) 24662306a36Sopenharmony_ci return false; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci *puid = le32_to_cpu(psid->sub_auth[1]); 24962306a36Sopenharmony_ci } else /* 3 subauths, ie Windows/Mac style */ { 25062306a36Sopenharmony_ci *puid = le32_to_cpu(psid->sub_auth[0]); 25162306a36Sopenharmony_ci if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) || 25262306a36Sopenharmony_ci (psid->sub_auth[1] != pwell_known_sid->sub_auth[1])) 25362306a36Sopenharmony_ci return false; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci *puid = le32_to_cpu(psid->sub_auth[2]); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid); 25962306a36Sopenharmony_ci return true; /* well known sid found, uid returned */ 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic __u16 26362306a36Sopenharmony_cicifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci int i; 26662306a36Sopenharmony_ci __u16 size = 1 + 1 + 6; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci dst->revision = src->revision; 26962306a36Sopenharmony_ci dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES); 27062306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; ++i) 27162306a36Sopenharmony_ci dst->authority[i] = src->authority[i]; 27262306a36Sopenharmony_ci for (i = 0; i < dst->num_subauth; ++i) 27362306a36Sopenharmony_ci dst->sub_auth[i] = src->sub_auth[i]; 27462306a36Sopenharmony_ci size += (dst->num_subauth * 4); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return size; 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int 28062306a36Sopenharmony_ciid_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int rc; 28362306a36Sopenharmony_ci struct key *sidkey; 28462306a36Sopenharmony_ci struct cifs_sid *ksid; 28562306a36Sopenharmony_ci unsigned int ksid_size; 28662306a36Sopenharmony_ci char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */ 28762306a36Sopenharmony_ci const struct cred *saved_cred; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci rc = snprintf(desc, sizeof(desc), "%ci:%u", 29062306a36Sopenharmony_ci sidtype == SIDOWNER ? 'o' : 'g', cid); 29162306a36Sopenharmony_ci if (rc >= sizeof(desc)) 29262306a36Sopenharmony_ci return -EINVAL; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci rc = 0; 29562306a36Sopenharmony_ci saved_cred = override_creds(root_cred); 29662306a36Sopenharmony_ci sidkey = request_key(&cifs_idmap_key_type, desc, ""); 29762306a36Sopenharmony_ci if (IS_ERR(sidkey)) { 29862306a36Sopenharmony_ci rc = -EINVAL; 29962306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n", 30062306a36Sopenharmony_ci __func__, sidtype == SIDOWNER ? 'u' : 'g', cid); 30162306a36Sopenharmony_ci goto out_revert_creds; 30262306a36Sopenharmony_ci } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) { 30362306a36Sopenharmony_ci rc = -EIO; 30462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n", 30562306a36Sopenharmony_ci __func__, sidkey->datalen); 30662306a36Sopenharmony_ci goto invalidate_key; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* 31062306a36Sopenharmony_ci * A sid is usually too large to be embedded in payload.value, but if 31162306a36Sopenharmony_ci * there are no subauthorities and the host has 8-byte pointers, then 31262306a36Sopenharmony_ci * it could be. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ci ksid = sidkey->datalen <= sizeof(sidkey->payload) ? 31562306a36Sopenharmony_ci (struct cifs_sid *)&sidkey->payload : 31662306a36Sopenharmony_ci (struct cifs_sid *)sidkey->payload.data[0]; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32)); 31962306a36Sopenharmony_ci if (ksid_size > sidkey->datalen) { 32062306a36Sopenharmony_ci rc = -EIO; 32162306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n", 32262306a36Sopenharmony_ci __func__, sidkey->datalen, ksid_size); 32362306a36Sopenharmony_ci goto invalidate_key; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci cifs_copy_sid(ssid, ksid); 32762306a36Sopenharmony_ciout_key_put: 32862306a36Sopenharmony_ci key_put(sidkey); 32962306a36Sopenharmony_ciout_revert_creds: 33062306a36Sopenharmony_ci revert_creds(saved_cred); 33162306a36Sopenharmony_ci return rc; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ciinvalidate_key: 33462306a36Sopenharmony_ci key_invalidate(sidkey); 33562306a36Sopenharmony_ci goto out_key_put; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciint 33962306a36Sopenharmony_cisid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, 34062306a36Sopenharmony_ci struct cifs_fattr *fattr, uint sidtype) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci int rc = 0; 34362306a36Sopenharmony_ci struct key *sidkey; 34462306a36Sopenharmony_ci char *sidstr; 34562306a36Sopenharmony_ci const struct cred *saved_cred; 34662306a36Sopenharmony_ci kuid_t fuid = cifs_sb->ctx->linux_uid; 34762306a36Sopenharmony_ci kgid_t fgid = cifs_sb->ctx->linux_gid; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * If we have too many subauthorities, then something is really wrong. 35162306a36Sopenharmony_ci * Just return an error. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { 35462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: %u subauthorities is too many!\n", 35562306a36Sopenharmony_ci __func__, psid->num_subauth); 35662306a36Sopenharmony_ci return -EIO; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) || 36062306a36Sopenharmony_ci (cifs_sb_master_tcon(cifs_sb)->posix_extensions)) { 36162306a36Sopenharmony_ci uint32_t unix_id; 36262306a36Sopenharmony_ci bool is_group; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (sidtype != SIDOWNER) 36562306a36Sopenharmony_ci is_group = true; 36662306a36Sopenharmony_ci else 36762306a36Sopenharmony_ci is_group = false; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (is_well_known_sid(psid, &unix_id, is_group) == false) 37062306a36Sopenharmony_ci goto try_upcall_to_get_id; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (is_group) { 37362306a36Sopenharmony_ci kgid_t gid; 37462306a36Sopenharmony_ci gid_t id; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci id = (gid_t)unix_id; 37762306a36Sopenharmony_ci gid = make_kgid(&init_user_ns, id); 37862306a36Sopenharmony_ci if (gid_valid(gid)) { 37962306a36Sopenharmony_ci fgid = gid; 38062306a36Sopenharmony_ci goto got_valid_id; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci } else { 38362306a36Sopenharmony_ci kuid_t uid; 38462306a36Sopenharmony_ci uid_t id; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci id = (uid_t)unix_id; 38762306a36Sopenharmony_ci uid = make_kuid(&init_user_ns, id); 38862306a36Sopenharmony_ci if (uid_valid(uid)) { 38962306a36Sopenharmony_ci fuid = uid; 39062306a36Sopenharmony_ci goto got_valid_id; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci /* If unable to find uid/gid easily from SID try via upcall */ 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_citry_upcall_to_get_id: 39762306a36Sopenharmony_ci sidstr = sid_to_key_str(psid, sidtype); 39862306a36Sopenharmony_ci if (!sidstr) 39962306a36Sopenharmony_ci return -ENOMEM; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci saved_cred = override_creds(root_cred); 40262306a36Sopenharmony_ci sidkey = request_key(&cifs_idmap_key_type, sidstr, ""); 40362306a36Sopenharmony_ci if (IS_ERR(sidkey)) { 40462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n", 40562306a36Sopenharmony_ci __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g'); 40662306a36Sopenharmony_ci goto out_revert_creds; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* 41062306a36Sopenharmony_ci * FIXME: Here we assume that uid_t and gid_t are same size. It's 41162306a36Sopenharmony_ci * probably a safe assumption but might be better to check based on 41262306a36Sopenharmony_ci * sidtype. 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t)); 41562306a36Sopenharmony_ci if (sidkey->datalen != sizeof(uid_t)) { 41662306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n", 41762306a36Sopenharmony_ci __func__, sidkey->datalen); 41862306a36Sopenharmony_ci key_invalidate(sidkey); 41962306a36Sopenharmony_ci goto out_key_put; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (sidtype == SIDOWNER) { 42362306a36Sopenharmony_ci kuid_t uid; 42462306a36Sopenharmony_ci uid_t id; 42562306a36Sopenharmony_ci memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t)); 42662306a36Sopenharmony_ci uid = make_kuid(&init_user_ns, id); 42762306a36Sopenharmony_ci if (uid_valid(uid)) 42862306a36Sopenharmony_ci fuid = uid; 42962306a36Sopenharmony_ci } else { 43062306a36Sopenharmony_ci kgid_t gid; 43162306a36Sopenharmony_ci gid_t id; 43262306a36Sopenharmony_ci memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t)); 43362306a36Sopenharmony_ci gid = make_kgid(&init_user_ns, id); 43462306a36Sopenharmony_ci if (gid_valid(gid)) 43562306a36Sopenharmony_ci fgid = gid; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ciout_key_put: 43962306a36Sopenharmony_ci key_put(sidkey); 44062306a36Sopenharmony_ciout_revert_creds: 44162306a36Sopenharmony_ci revert_creds(saved_cred); 44262306a36Sopenharmony_ci kfree(sidstr); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * Note that we return 0 here unconditionally. If the mapping 44662306a36Sopenharmony_ci * fails then we just fall back to using the ctx->linux_uid/linux_gid. 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_cigot_valid_id: 44962306a36Sopenharmony_ci rc = 0; 45062306a36Sopenharmony_ci if (sidtype == SIDOWNER) 45162306a36Sopenharmony_ci fattr->cf_uid = fuid; 45262306a36Sopenharmony_ci else 45362306a36Sopenharmony_ci fattr->cf_gid = fgid; 45462306a36Sopenharmony_ci return rc; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ciint 45862306a36Sopenharmony_ciinit_cifs_idmap(void) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci struct cred *cred; 46162306a36Sopenharmony_ci struct key *keyring; 46262306a36Sopenharmony_ci int ret; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci cifs_dbg(FYI, "Registering the %s key type\n", 46562306a36Sopenharmony_ci cifs_idmap_key_type.name); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* create an override credential set with a special thread keyring in 46862306a36Sopenharmony_ci * which requests are cached 46962306a36Sopenharmony_ci * 47062306a36Sopenharmony_ci * this is used to prevent malicious redirections from being installed 47162306a36Sopenharmony_ci * with add_key(). 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci cred = prepare_kernel_cred(&init_task); 47462306a36Sopenharmony_ci if (!cred) 47562306a36Sopenharmony_ci return -ENOMEM; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci keyring = keyring_alloc(".cifs_idmap", 47862306a36Sopenharmony_ci GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 47962306a36Sopenharmony_ci (KEY_POS_ALL & ~KEY_POS_SETATTR) | 48062306a36Sopenharmony_ci KEY_USR_VIEW | KEY_USR_READ, 48162306a36Sopenharmony_ci KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); 48262306a36Sopenharmony_ci if (IS_ERR(keyring)) { 48362306a36Sopenharmony_ci ret = PTR_ERR(keyring); 48462306a36Sopenharmony_ci goto failed_put_cred; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ret = register_key_type(&cifs_idmap_key_type); 48862306a36Sopenharmony_ci if (ret < 0) 48962306a36Sopenharmony_ci goto failed_put_key; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* instruct request_key() to use this special keyring as a cache for 49262306a36Sopenharmony_ci * the results it looks up */ 49362306a36Sopenharmony_ci set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); 49462306a36Sopenharmony_ci cred->thread_keyring = keyring; 49562306a36Sopenharmony_ci cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; 49662306a36Sopenharmony_ci root_cred = cred; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring)); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cifailed_put_key: 50262306a36Sopenharmony_ci key_put(keyring); 50362306a36Sopenharmony_cifailed_put_cred: 50462306a36Sopenharmony_ci put_cred(cred); 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_civoid 50962306a36Sopenharmony_ciexit_cifs_idmap(void) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci key_revoke(root_cred->thread_keyring); 51262306a36Sopenharmony_ci unregister_key_type(&cifs_idmap_key_type); 51362306a36Sopenharmony_ci put_cred(root_cred); 51462306a36Sopenharmony_ci cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci/* copy ntsd, owner sid, and group sid from a security descriptor to another */ 51862306a36Sopenharmony_cistatic __u32 copy_sec_desc(const struct cifs_ntsd *pntsd, 51962306a36Sopenharmony_ci struct cifs_ntsd *pnntsd, 52062306a36Sopenharmony_ci __u32 sidsoffset, 52162306a36Sopenharmony_ci struct cifs_sid *pownersid, 52262306a36Sopenharmony_ci struct cifs_sid *pgrpsid) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 52562306a36Sopenharmony_ci struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* copy security descriptor control portion */ 52862306a36Sopenharmony_ci pnntsd->revision = pntsd->revision; 52962306a36Sopenharmony_ci pnntsd->type = pntsd->type; 53062306a36Sopenharmony_ci pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd)); 53162306a36Sopenharmony_ci pnntsd->sacloffset = 0; 53262306a36Sopenharmony_ci pnntsd->osidoffset = cpu_to_le32(sidsoffset); 53362306a36Sopenharmony_ci pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid)); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* copy owner sid */ 53662306a36Sopenharmony_ci if (pownersid) 53762306a36Sopenharmony_ci owner_sid_ptr = pownersid; 53862306a36Sopenharmony_ci else 53962306a36Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 54062306a36Sopenharmony_ci le32_to_cpu(pntsd->osidoffset)); 54162306a36Sopenharmony_ci nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); 54262306a36Sopenharmony_ci cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* copy group sid */ 54562306a36Sopenharmony_ci if (pgrpsid) 54662306a36Sopenharmony_ci group_sid_ptr = pgrpsid; 54762306a36Sopenharmony_ci else 54862306a36Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 54962306a36Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset)); 55062306a36Sopenharmony_ci ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + 55162306a36Sopenharmony_ci sizeof(struct cifs_sid)); 55262306a36Sopenharmony_ci cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci return sidsoffset + (2 * sizeof(struct cifs_sid)); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci/* 55962306a36Sopenharmony_ci change posix mode to reflect permissions 56062306a36Sopenharmony_ci pmode is the existing mode (we only want to overwrite part of this 56162306a36Sopenharmony_ci bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007 56262306a36Sopenharmony_ci*/ 56362306a36Sopenharmony_cistatic void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode, 56462306a36Sopenharmony_ci umode_t *pdenied, umode_t mask) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci __u32 flags = le32_to_cpu(ace_flags); 56762306a36Sopenharmony_ci /* 56862306a36Sopenharmony_ci * Do not assume "preferred" or "canonical" order. 56962306a36Sopenharmony_ci * The first DENY or ALLOW ACE which matches perfectly is 57062306a36Sopenharmony_ci * the permission to be used. Once allowed or denied, same 57162306a36Sopenharmony_ci * permission in later ACEs do not matter. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* If not already allowed, deny these bits */ 57562306a36Sopenharmony_ci if (type == ACCESS_DENIED) { 57662306a36Sopenharmony_ci if (flags & GENERIC_ALL && 57762306a36Sopenharmony_ci !(*pmode & mask & 0777)) 57862306a36Sopenharmony_ci *pdenied |= mask & 0777; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (((flags & GENERIC_WRITE) || 58162306a36Sopenharmony_ci ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) && 58262306a36Sopenharmony_ci !(*pmode & mask & 0222)) 58362306a36Sopenharmony_ci *pdenied |= mask & 0222; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci if (((flags & GENERIC_READ) || 58662306a36Sopenharmony_ci ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) && 58762306a36Sopenharmony_ci !(*pmode & mask & 0444)) 58862306a36Sopenharmony_ci *pdenied |= mask & 0444; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (((flags & GENERIC_EXECUTE) || 59162306a36Sopenharmony_ci ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) && 59262306a36Sopenharmony_ci !(*pmode & mask & 0111)) 59362306a36Sopenharmony_ci *pdenied |= mask & 0111; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return; 59662306a36Sopenharmony_ci } else if (type != ACCESS_ALLOWED) { 59762306a36Sopenharmony_ci cifs_dbg(VFS, "unknown access control type %d\n", type); 59862306a36Sopenharmony_ci return; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci /* else ACCESS_ALLOWED type */ 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if ((flags & GENERIC_ALL) && 60362306a36Sopenharmony_ci !(*pdenied & mask & 0777)) { 60462306a36Sopenharmony_ci *pmode |= mask & 0777; 60562306a36Sopenharmony_ci cifs_dbg(NOISY, "all perms\n"); 60662306a36Sopenharmony_ci return; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (((flags & GENERIC_WRITE) || 61062306a36Sopenharmony_ci ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) && 61162306a36Sopenharmony_ci !(*pdenied & mask & 0222)) 61262306a36Sopenharmony_ci *pmode |= mask & 0222; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (((flags & GENERIC_READ) || 61562306a36Sopenharmony_ci ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) && 61662306a36Sopenharmony_ci !(*pdenied & mask & 0444)) 61762306a36Sopenharmony_ci *pmode |= mask & 0444; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (((flags & GENERIC_EXECUTE) || 62062306a36Sopenharmony_ci ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) && 62162306a36Sopenharmony_ci !(*pdenied & mask & 0111)) 62262306a36Sopenharmony_ci *pmode |= mask & 0111; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* If DELETE_CHILD is set only on an owner ACE, set sticky bit */ 62562306a36Sopenharmony_ci if (flags & FILE_DELETE_CHILD) { 62662306a36Sopenharmony_ci if (mask == ACL_OWNER_MASK) { 62762306a36Sopenharmony_ci if (!(*pdenied & 01000)) 62862306a36Sopenharmony_ci *pmode |= 01000; 62962306a36Sopenharmony_ci } else if (!(*pdenied & 01000)) { 63062306a36Sopenharmony_ci *pmode &= ~01000; 63162306a36Sopenharmony_ci *pdenied |= 01000; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode); 63662306a36Sopenharmony_ci return; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci/* 64062306a36Sopenharmony_ci Generate access flags to reflect permissions mode is the existing mode. 64162306a36Sopenharmony_ci This function is called for every ACE in the DACL whose SID matches 64262306a36Sopenharmony_ci with either owner or group or everyone. 64362306a36Sopenharmony_ci*/ 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic void mode_to_access_flags(umode_t mode, umode_t bits_to_use, 64662306a36Sopenharmony_ci __u32 *pace_flags) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci /* reset access mask */ 64962306a36Sopenharmony_ci *pace_flags = 0x0; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */ 65262306a36Sopenharmony_ci mode &= bits_to_use; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* check for R/W/X UGO since we do not know whose flags 65562306a36Sopenharmony_ci is this but we have cleared all the bits sans RWX for 65662306a36Sopenharmony_ci either user or group or other as per bits_to_use */ 65762306a36Sopenharmony_ci if (mode & S_IRUGO) 65862306a36Sopenharmony_ci *pace_flags |= SET_FILE_READ_RIGHTS; 65962306a36Sopenharmony_ci if (mode & S_IWUGO) 66062306a36Sopenharmony_ci *pace_flags |= SET_FILE_WRITE_RIGHTS; 66162306a36Sopenharmony_ci if (mode & S_IXUGO) 66262306a36Sopenharmony_ci *pace_flags |= SET_FILE_EXEC_RIGHTS; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n", 66562306a36Sopenharmony_ci mode, *pace_flags); 66662306a36Sopenharmony_ci return; 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic __u16 cifs_copy_ace(struct cifs_ace *dst, struct cifs_ace *src, struct cifs_sid *psid) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci __u16 size = 1 + 1 + 2 + 4; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci dst->type = src->type; 67462306a36Sopenharmony_ci dst->flags = src->flags; 67562306a36Sopenharmony_ci dst->access_req = src->access_req; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* Check if there's a replacement sid specified */ 67862306a36Sopenharmony_ci if (psid) 67962306a36Sopenharmony_ci size += cifs_copy_sid(&dst->sid, psid); 68062306a36Sopenharmony_ci else 68162306a36Sopenharmony_ci size += cifs_copy_sid(&dst->sid, &src->sid); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci dst->size = cpu_to_le16(size); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci return size; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic __u16 fill_ace_for_sid(struct cifs_ace *pntace, 68962306a36Sopenharmony_ci const struct cifs_sid *psid, __u64 nmode, 69062306a36Sopenharmony_ci umode_t bits, __u8 access_type, 69162306a36Sopenharmony_ci bool allow_delete_child) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci int i; 69462306a36Sopenharmony_ci __u16 size = 0; 69562306a36Sopenharmony_ci __u32 access_req = 0; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci pntace->type = access_type; 69862306a36Sopenharmony_ci pntace->flags = 0x0; 69962306a36Sopenharmony_ci mode_to_access_flags(nmode, bits, &access_req); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (access_type == ACCESS_ALLOWED && allow_delete_child) 70262306a36Sopenharmony_ci access_req |= FILE_DELETE_CHILD; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (access_type == ACCESS_ALLOWED && !access_req) 70562306a36Sopenharmony_ci access_req = SET_MINIMUM_RIGHTS; 70662306a36Sopenharmony_ci else if (access_type == ACCESS_DENIED) 70762306a36Sopenharmony_ci access_req &= ~SET_MINIMUM_RIGHTS; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci pntace->access_req = cpu_to_le32(access_req); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci pntace->sid.revision = psid->revision; 71262306a36Sopenharmony_ci pntace->sid.num_subauth = psid->num_subauth; 71362306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 71462306a36Sopenharmony_ci pntace->sid.authority[i] = psid->authority[i]; 71562306a36Sopenharmony_ci for (i = 0; i < psid->num_subauth; i++) 71662306a36Sopenharmony_ci pntace->sid.sub_auth[i] = psid->sub_auth[i]; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4); 71962306a36Sopenharmony_ci pntace->size = cpu_to_le16(size); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return size; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG2 72662306a36Sopenharmony_cistatic void dump_ace(struct cifs_ace *pace, char *end_of_acl) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci int num_subauth; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* validate that we do not go past end of acl */ 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (le16_to_cpu(pace->size) < 16) { 73362306a36Sopenharmony_ci cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size)); 73462306a36Sopenharmony_ci return; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) { 73862306a36Sopenharmony_ci cifs_dbg(VFS, "ACL too small to parse ACE\n"); 73962306a36Sopenharmony_ci return; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci num_subauth = pace->sid.num_subauth; 74362306a36Sopenharmony_ci if (num_subauth) { 74462306a36Sopenharmony_ci int i; 74562306a36Sopenharmony_ci cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n", 74662306a36Sopenharmony_ci pace->sid.revision, pace->sid.num_subauth, pace->type, 74762306a36Sopenharmony_ci pace->flags, le16_to_cpu(pace->size)); 74862306a36Sopenharmony_ci for (i = 0; i < num_subauth; ++i) { 74962306a36Sopenharmony_ci cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n", 75062306a36Sopenharmony_ci i, le32_to_cpu(pace->sid.sub_auth[i])); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci /* BB add length check to make sure that we do not have huge 75462306a36Sopenharmony_ci num auths and therefore go off the end */ 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci#endif 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_cistatic void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, 76262306a36Sopenharmony_ci struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, 76362306a36Sopenharmony_ci struct cifs_fattr *fattr, bool mode_from_special_sid) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci int i; 76662306a36Sopenharmony_ci int num_aces = 0; 76762306a36Sopenharmony_ci int acl_size; 76862306a36Sopenharmony_ci char *acl_base; 76962306a36Sopenharmony_ci struct cifs_ace **ppace; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* BB need to add parm so we can store the SID BB */ 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (!pdacl) { 77462306a36Sopenharmony_ci /* no DACL in the security descriptor, set 77562306a36Sopenharmony_ci all the permissions for user/group/other */ 77662306a36Sopenharmony_ci fattr->cf_mode |= 0777; 77762306a36Sopenharmony_ci return; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* validate that we do not go past end of acl */ 78162306a36Sopenharmony_ci if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { 78262306a36Sopenharmony_ci cifs_dbg(VFS, "ACL too small to parse DACL\n"); 78362306a36Sopenharmony_ci return; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", 78762306a36Sopenharmony_ci le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), 78862306a36Sopenharmony_ci le32_to_cpu(pdacl->num_aces)); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci /* reset rwx permissions for user/group/other. 79162306a36Sopenharmony_ci Also, if num_aces is 0 i.e. DACL has no ACEs, 79262306a36Sopenharmony_ci user/group/other have no permissions */ 79362306a36Sopenharmony_ci fattr->cf_mode &= ~(0777); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci acl_base = (char *)pdacl; 79662306a36Sopenharmony_ci acl_size = sizeof(struct cifs_acl); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci num_aces = le32_to_cpu(pdacl->num_aces); 79962306a36Sopenharmony_ci if (num_aces > 0) { 80062306a36Sopenharmony_ci umode_t denied_mode = 0; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *)) 80362306a36Sopenharmony_ci return; 80462306a36Sopenharmony_ci ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *), 80562306a36Sopenharmony_ci GFP_KERNEL); 80662306a36Sopenharmony_ci if (!ppace) 80762306a36Sopenharmony_ci return; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci for (i = 0; i < num_aces; ++i) { 81062306a36Sopenharmony_ci ppace[i] = (struct cifs_ace *) (acl_base + acl_size); 81162306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG2 81262306a36Sopenharmony_ci dump_ace(ppace[i], end_of_acl); 81362306a36Sopenharmony_ci#endif 81462306a36Sopenharmony_ci if (mode_from_special_sid && 81562306a36Sopenharmony_ci (compare_sids(&(ppace[i]->sid), 81662306a36Sopenharmony_ci &sid_unix_NFS_mode) == 0)) { 81762306a36Sopenharmony_ci /* 81862306a36Sopenharmony_ci * Full permissions are: 81962306a36Sopenharmony_ci * 07777 = S_ISUID | S_ISGID | S_ISVTX | 82062306a36Sopenharmony_ci * S_IRWXU | S_IRWXG | S_IRWXO 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_ci fattr->cf_mode &= ~07777; 82362306a36Sopenharmony_ci fattr->cf_mode |= 82462306a36Sopenharmony_ci le32_to_cpu(ppace[i]->sid.sub_auth[2]); 82562306a36Sopenharmony_ci break; 82662306a36Sopenharmony_ci } else { 82762306a36Sopenharmony_ci if (compare_sids(&(ppace[i]->sid), pownersid) == 0) { 82862306a36Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 82962306a36Sopenharmony_ci ppace[i]->type, 83062306a36Sopenharmony_ci &fattr->cf_mode, 83162306a36Sopenharmony_ci &denied_mode, 83262306a36Sopenharmony_ci ACL_OWNER_MASK); 83362306a36Sopenharmony_ci } else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) { 83462306a36Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 83562306a36Sopenharmony_ci ppace[i]->type, 83662306a36Sopenharmony_ci &fattr->cf_mode, 83762306a36Sopenharmony_ci &denied_mode, 83862306a36Sopenharmony_ci ACL_GROUP_MASK); 83962306a36Sopenharmony_ci } else if ((compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) || 84062306a36Sopenharmony_ci (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)) { 84162306a36Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 84262306a36Sopenharmony_ci ppace[i]->type, 84362306a36Sopenharmony_ci &fattr->cf_mode, 84462306a36Sopenharmony_ci &denied_mode, 84562306a36Sopenharmony_ci ACL_EVERYONE_MASK); 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/* memcpy((void *)(&(cifscred->aces[i])), 85162306a36Sopenharmony_ci (void *)ppace[i], 85262306a36Sopenharmony_ci sizeof(struct cifs_ace)); */ 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci acl_base = (char *)ppace[i]; 85562306a36Sopenharmony_ci acl_size = le16_to_cpu(ppace[i]->size); 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci kfree(ppace); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ciunsigned int setup_authusers_ACE(struct cifs_ace *pntace) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci int i; 86762306a36Sopenharmony_ci unsigned int ace_size = 20; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci pntace->type = ACCESS_ALLOWED_ACE_TYPE; 87062306a36Sopenharmony_ci pntace->flags = 0x0; 87162306a36Sopenharmony_ci pntace->access_req = cpu_to_le32(GENERIC_ALL); 87262306a36Sopenharmony_ci pntace->sid.num_subauth = 1; 87362306a36Sopenharmony_ci pntace->sid.revision = 1; 87462306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 87562306a36Sopenharmony_ci pntace->sid.authority[i] = sid_authusers.authority[i]; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0]; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ 88062306a36Sopenharmony_ci pntace->size = cpu_to_le16(ace_size); 88162306a36Sopenharmony_ci return ace_size; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci/* 88562306a36Sopenharmony_ci * Fill in the special SID based on the mode. See 88662306a36Sopenharmony_ci * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx 88762306a36Sopenharmony_ci */ 88862306a36Sopenharmony_ciunsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode) 88962306a36Sopenharmony_ci{ 89062306a36Sopenharmony_ci int i; 89162306a36Sopenharmony_ci unsigned int ace_size = 28; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci pntace->type = ACCESS_DENIED_ACE_TYPE; 89462306a36Sopenharmony_ci pntace->flags = 0x0; 89562306a36Sopenharmony_ci pntace->access_req = 0; 89662306a36Sopenharmony_ci pntace->sid.num_subauth = 3; 89762306a36Sopenharmony_ci pntace->sid.revision = 1; 89862306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 89962306a36Sopenharmony_ci pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i]; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0]; 90262306a36Sopenharmony_ci pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1]; 90362306a36Sopenharmony_ci pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ 90662306a36Sopenharmony_ci pntace->size = cpu_to_le16(ace_size); 90762306a36Sopenharmony_ci return ace_size; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ciunsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci int i; 91362306a36Sopenharmony_ci unsigned int ace_size = 28; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci pntace->type = ACCESS_ALLOWED_ACE_TYPE; 91662306a36Sopenharmony_ci pntace->flags = 0x0; 91762306a36Sopenharmony_ci pntace->access_req = cpu_to_le32(GENERIC_ALL); 91862306a36Sopenharmony_ci pntace->sid.num_subauth = 3; 91962306a36Sopenharmony_ci pntace->sid.revision = 1; 92062306a36Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 92162306a36Sopenharmony_ci pntace->sid.authority[i] = sid_unix_NFS_users.authority[i]; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0]; 92462306a36Sopenharmony_ci pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1]; 92562306a36Sopenharmony_ci pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ 92862306a36Sopenharmony_ci pntace->size = cpu_to_le16(ace_size); 92962306a36Sopenharmony_ci return ace_size; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic void populate_new_aces(char *nacl_base, 93362306a36Sopenharmony_ci struct cifs_sid *pownersid, 93462306a36Sopenharmony_ci struct cifs_sid *pgrpsid, 93562306a36Sopenharmony_ci __u64 *pnmode, u32 *pnum_aces, u16 *pnsize, 93662306a36Sopenharmony_ci bool modefromsid) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci __u64 nmode; 93962306a36Sopenharmony_ci u32 num_aces = 0; 94062306a36Sopenharmony_ci u16 nsize = 0; 94162306a36Sopenharmony_ci __u64 user_mode; 94262306a36Sopenharmony_ci __u64 group_mode; 94362306a36Sopenharmony_ci __u64 other_mode; 94462306a36Sopenharmony_ci __u64 deny_user_mode = 0; 94562306a36Sopenharmony_ci __u64 deny_group_mode = 0; 94662306a36Sopenharmony_ci bool sticky_set = false; 94762306a36Sopenharmony_ci struct cifs_ace *pnntace = NULL; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci nmode = *pnmode; 95062306a36Sopenharmony_ci num_aces = *pnum_aces; 95162306a36Sopenharmony_ci nsize = *pnsize; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (modefromsid) { 95462306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 95562306a36Sopenharmony_ci nsize += setup_special_mode_ACE(pnntace, nmode); 95662306a36Sopenharmony_ci num_aces++; 95762306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 95862306a36Sopenharmony_ci nsize += setup_authusers_ACE(pnntace); 95962306a36Sopenharmony_ci num_aces++; 96062306a36Sopenharmony_ci goto set_size; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* 96462306a36Sopenharmony_ci * We'll try to keep the mode as requested by the user. 96562306a36Sopenharmony_ci * But in cases where we cannot meaningfully convert that 96662306a36Sopenharmony_ci * into ACL, return back the updated mode, so that it is 96762306a36Sopenharmony_ci * updated in the inode. 96862306a36Sopenharmony_ci */ 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (!memcmp(pownersid, pgrpsid, sizeof(struct cifs_sid))) { 97162306a36Sopenharmony_ci /* 97262306a36Sopenharmony_ci * Case when owner and group SIDs are the same. 97362306a36Sopenharmony_ci * Set the more restrictive of the two modes. 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_ci user_mode = nmode & (nmode << 3) & 0700; 97662306a36Sopenharmony_ci group_mode = nmode & (nmode >> 3) & 0070; 97762306a36Sopenharmony_ci } else { 97862306a36Sopenharmony_ci user_mode = nmode & 0700; 97962306a36Sopenharmony_ci group_mode = nmode & 0070; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci other_mode = nmode & 0007; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci /* We need DENY ACE when the perm is more restrictive than the next sets. */ 98562306a36Sopenharmony_ci deny_user_mode = ~(user_mode) & ((group_mode << 3) | (other_mode << 6)) & 0700; 98662306a36Sopenharmony_ci deny_group_mode = ~(group_mode) & (other_mode << 3) & 0070; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci *pnmode = user_mode | group_mode | other_mode | (nmode & ~0777); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* This tells if we should allow delete child for group and everyone. */ 99162306a36Sopenharmony_ci if (nmode & 01000) 99262306a36Sopenharmony_ci sticky_set = true; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (deny_user_mode) { 99562306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 99662306a36Sopenharmony_ci nsize += fill_ace_for_sid(pnntace, pownersid, deny_user_mode, 99762306a36Sopenharmony_ci 0700, ACCESS_DENIED, false); 99862306a36Sopenharmony_ci num_aces++; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/ 100262306a36Sopenharmony_ci if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) { 100362306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 100462306a36Sopenharmony_ci nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode, 100562306a36Sopenharmony_ci 0070, ACCESS_DENIED, false); 100662306a36Sopenharmony_ci num_aces++; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 101062306a36Sopenharmony_ci nsize += fill_ace_for_sid(pnntace, pownersid, user_mode, 101162306a36Sopenharmony_ci 0700, ACCESS_ALLOWED, true); 101262306a36Sopenharmony_ci num_aces++; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */ 101562306a36Sopenharmony_ci if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) { 101662306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 101762306a36Sopenharmony_ci nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode, 101862306a36Sopenharmony_ci 0070, ACCESS_DENIED, false); 101962306a36Sopenharmony_ci num_aces++; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 102362306a36Sopenharmony_ci nsize += fill_ace_for_sid(pnntace, pgrpsid, group_mode, 102462306a36Sopenharmony_ci 0070, ACCESS_ALLOWED, !sticky_set); 102562306a36Sopenharmony_ci num_aces++; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 102862306a36Sopenharmony_ci nsize += fill_ace_for_sid(pnntace, &sid_everyone, other_mode, 102962306a36Sopenharmony_ci 0007, ACCESS_ALLOWED, !sticky_set); 103062306a36Sopenharmony_ci num_aces++; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ciset_size: 103362306a36Sopenharmony_ci *pnum_aces = num_aces; 103462306a36Sopenharmony_ci *pnsize = nsize; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic __u16 replace_sids_and_copy_aces(struct cifs_acl *pdacl, struct cifs_acl *pndacl, 103862306a36Sopenharmony_ci struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, 103962306a36Sopenharmony_ci struct cifs_sid *pnownersid, struct cifs_sid *pngrpsid) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci int i; 104262306a36Sopenharmony_ci u16 size = 0; 104362306a36Sopenharmony_ci struct cifs_ace *pntace = NULL; 104462306a36Sopenharmony_ci char *acl_base = NULL; 104562306a36Sopenharmony_ci u32 src_num_aces = 0; 104662306a36Sopenharmony_ci u16 nsize = 0; 104762306a36Sopenharmony_ci struct cifs_ace *pnntace = NULL; 104862306a36Sopenharmony_ci char *nacl_base = NULL; 104962306a36Sopenharmony_ci u16 ace_size = 0; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci acl_base = (char *)pdacl; 105262306a36Sopenharmony_ci size = sizeof(struct cifs_acl); 105362306a36Sopenharmony_ci src_num_aces = le32_to_cpu(pdacl->num_aces); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci nacl_base = (char *)pndacl; 105662306a36Sopenharmony_ci nsize = sizeof(struct cifs_acl); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* Go through all the ACEs */ 105962306a36Sopenharmony_ci for (i = 0; i < src_num_aces; ++i) { 106062306a36Sopenharmony_ci pntace = (struct cifs_ace *) (acl_base + size); 106162306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0) 106462306a36Sopenharmony_ci ace_size = cifs_copy_ace(pnntace, pntace, pnownersid); 106562306a36Sopenharmony_ci else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0) 106662306a36Sopenharmony_ci ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid); 106762306a36Sopenharmony_ci else 106862306a36Sopenharmony_ci ace_size = cifs_copy_ace(pnntace, pntace, NULL); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci size += le16_to_cpu(pntace->size); 107162306a36Sopenharmony_ci nsize += ace_size; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci return nsize; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl, 107862306a36Sopenharmony_ci struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, 107962306a36Sopenharmony_ci __u64 *pnmode, bool mode_from_sid) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci int i; 108262306a36Sopenharmony_ci u16 size = 0; 108362306a36Sopenharmony_ci struct cifs_ace *pntace = NULL; 108462306a36Sopenharmony_ci char *acl_base = NULL; 108562306a36Sopenharmony_ci u32 src_num_aces = 0; 108662306a36Sopenharmony_ci u16 nsize = 0; 108762306a36Sopenharmony_ci struct cifs_ace *pnntace = NULL; 108862306a36Sopenharmony_ci char *nacl_base = NULL; 108962306a36Sopenharmony_ci u32 num_aces = 0; 109062306a36Sopenharmony_ci bool new_aces_set = false; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* Assuming that pndacl and pnmode are never NULL */ 109362306a36Sopenharmony_ci nacl_base = (char *)pndacl; 109462306a36Sopenharmony_ci nsize = sizeof(struct cifs_acl); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* If pdacl is NULL, we don't have a src. Simply populate new ACL. */ 109762306a36Sopenharmony_ci if (!pdacl) { 109862306a36Sopenharmony_ci populate_new_aces(nacl_base, 109962306a36Sopenharmony_ci pownersid, pgrpsid, 110062306a36Sopenharmony_ci pnmode, &num_aces, &nsize, 110162306a36Sopenharmony_ci mode_from_sid); 110262306a36Sopenharmony_ci goto finalize_dacl; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci acl_base = (char *)pdacl; 110662306a36Sopenharmony_ci size = sizeof(struct cifs_acl); 110762306a36Sopenharmony_ci src_num_aces = le32_to_cpu(pdacl->num_aces); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* Retain old ACEs which we can retain */ 111062306a36Sopenharmony_ci for (i = 0; i < src_num_aces; ++i) { 111162306a36Sopenharmony_ci pntace = (struct cifs_ace *) (acl_base + size); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci if (!new_aces_set && (pntace->flags & INHERITED_ACE)) { 111462306a36Sopenharmony_ci /* Place the new ACEs in between existing explicit and inherited */ 111562306a36Sopenharmony_ci populate_new_aces(nacl_base, 111662306a36Sopenharmony_ci pownersid, pgrpsid, 111762306a36Sopenharmony_ci pnmode, &num_aces, &nsize, 111862306a36Sopenharmony_ci mode_from_sid); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci new_aces_set = true; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci /* If it's any one of the ACE we're replacing, skip! */ 112462306a36Sopenharmony_ci if (((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) || 112562306a36Sopenharmony_ci (compare_sids(&pntace->sid, pownersid) == 0) || 112662306a36Sopenharmony_ci (compare_sids(&pntace->sid, pgrpsid) == 0) || 112762306a36Sopenharmony_ci (compare_sids(&pntace->sid, &sid_everyone) == 0) || 112862306a36Sopenharmony_ci (compare_sids(&pntace->sid, &sid_authusers) == 0))) { 112962306a36Sopenharmony_ci goto next_ace; 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci /* update the pointer to the next ACE to populate*/ 113362306a36Sopenharmony_ci pnntace = (struct cifs_ace *) (nacl_base + nsize); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci nsize += cifs_copy_ace(pnntace, pntace, NULL); 113662306a36Sopenharmony_ci num_aces++; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cinext_ace: 113962306a36Sopenharmony_ci size += le16_to_cpu(pntace->size); 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci /* If inherited ACEs are not present, place the new ones at the tail */ 114362306a36Sopenharmony_ci if (!new_aces_set) { 114462306a36Sopenharmony_ci populate_new_aces(nacl_base, 114562306a36Sopenharmony_ci pownersid, pgrpsid, 114662306a36Sopenharmony_ci pnmode, &num_aces, &nsize, 114762306a36Sopenharmony_ci mode_from_sid); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci new_aces_set = true; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cifinalize_dacl: 115362306a36Sopenharmony_ci pndacl->num_aces = cpu_to_le32(num_aces); 115462306a36Sopenharmony_ci pndacl->size = cpu_to_le16(nsize); 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci return 0; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int parse_sid(struct cifs_sid *psid, char *end_of_acl) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci /* BB need to add parm so we can store the SID BB */ 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci /* validate that we do not go past end of ACL - sid must be at least 8 116462306a36Sopenharmony_ci bytes long (assuming no sub-auths - e.g. the null SID */ 116562306a36Sopenharmony_ci if (end_of_acl < (char *)psid + 8) { 116662306a36Sopenharmony_ci cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid); 116762306a36Sopenharmony_ci return -EINVAL; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG2 117162306a36Sopenharmony_ci if (psid->num_subauth) { 117262306a36Sopenharmony_ci int i; 117362306a36Sopenharmony_ci cifs_dbg(FYI, "SID revision %d num_auth %d\n", 117462306a36Sopenharmony_ci psid->revision, psid->num_subauth); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci for (i = 0; i < psid->num_subauth; i++) { 117762306a36Sopenharmony_ci cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n", 117862306a36Sopenharmony_ci i, le32_to_cpu(psid->sub_auth[i])); 117962306a36Sopenharmony_ci } 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* BB add length check to make sure that we do not have huge 118262306a36Sopenharmony_ci num auths and therefore go off the end */ 118362306a36Sopenharmony_ci cifs_dbg(FYI, "RID 0x%x\n", 118462306a36Sopenharmony_ci le32_to_cpu(psid->sub_auth[psid->num_subauth-1])); 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci#endif 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci return 0; 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci/* Convert CIFS ACL to POSIX form */ 119362306a36Sopenharmony_cistatic int parse_sec_desc(struct cifs_sb_info *cifs_sb, 119462306a36Sopenharmony_ci struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr, 119562306a36Sopenharmony_ci bool get_mode_from_special_sid) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci int rc = 0; 119862306a36Sopenharmony_ci struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 119962306a36Sopenharmony_ci struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ 120062306a36Sopenharmony_ci char *end_of_acl = ((char *)pntsd) + acl_len; 120162306a36Sopenharmony_ci __u32 dacloffset; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (pntsd == NULL) 120462306a36Sopenharmony_ci return -EIO; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 120762306a36Sopenharmony_ci le32_to_cpu(pntsd->osidoffset)); 120862306a36Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 120962306a36Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset)); 121062306a36Sopenharmony_ci dacloffset = le32_to_cpu(pntsd->dacloffset); 121162306a36Sopenharmony_ci dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 121262306a36Sopenharmony_ci cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", 121362306a36Sopenharmony_ci pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), 121462306a36Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset), 121562306a36Sopenharmony_ci le32_to_cpu(pntsd->sacloffset), dacloffset); 121662306a36Sopenharmony_ci/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ 121762306a36Sopenharmony_ci rc = parse_sid(owner_sid_ptr, end_of_acl); 121862306a36Sopenharmony_ci if (rc) { 121962306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc); 122062306a36Sopenharmony_ci return rc; 122162306a36Sopenharmony_ci } 122262306a36Sopenharmony_ci rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER); 122362306a36Sopenharmony_ci if (rc) { 122462306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n", 122562306a36Sopenharmony_ci __func__, rc); 122662306a36Sopenharmony_ci return rc; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci rc = parse_sid(group_sid_ptr, end_of_acl); 123062306a36Sopenharmony_ci if (rc) { 123162306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n", 123262306a36Sopenharmony_ci __func__, rc); 123362306a36Sopenharmony_ci return rc; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); 123662306a36Sopenharmony_ci if (rc) { 123762306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n", 123862306a36Sopenharmony_ci __func__, rc); 123962306a36Sopenharmony_ci return rc; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci if (dacloffset) 124362306a36Sopenharmony_ci parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, 124462306a36Sopenharmony_ci group_sid_ptr, fattr, get_mode_from_special_sid); 124562306a36Sopenharmony_ci else 124662306a36Sopenharmony_ci cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */ 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci return rc; 124962306a36Sopenharmony_ci} 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci/* Convert permission bits from mode to equivalent CIFS ACL */ 125262306a36Sopenharmony_cistatic int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, 125362306a36Sopenharmony_ci __u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid, 125462306a36Sopenharmony_ci bool mode_from_sid, bool id_from_sid, int *aclflag) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci int rc = 0; 125762306a36Sopenharmony_ci __u32 dacloffset; 125862306a36Sopenharmony_ci __u32 ndacloffset; 125962306a36Sopenharmony_ci __u32 sidsoffset; 126062306a36Sopenharmony_ci struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 126162306a36Sopenharmony_ci struct cifs_sid *nowner_sid_ptr = NULL, *ngroup_sid_ptr = NULL; 126262306a36Sopenharmony_ci struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */ 126362306a36Sopenharmony_ci struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ 126462306a36Sopenharmony_ci char *end_of_acl = ((char *)pntsd) + secdesclen; 126562306a36Sopenharmony_ci u16 size = 0; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci dacloffset = le32_to_cpu(pntsd->dacloffset); 126862306a36Sopenharmony_ci if (dacloffset) { 126962306a36Sopenharmony_ci dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 127062306a36Sopenharmony_ci if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) { 127162306a36Sopenharmony_ci cifs_dbg(VFS, "Server returned illegal ACL size\n"); 127262306a36Sopenharmony_ci return -EINVAL; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 127762306a36Sopenharmony_ci le32_to_cpu(pntsd->osidoffset)); 127862306a36Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 127962306a36Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset)); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */ 128262306a36Sopenharmony_ci ndacloffset = sizeof(struct cifs_ntsd); 128362306a36Sopenharmony_ci ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); 128462306a36Sopenharmony_ci ndacl_ptr->revision = 128562306a36Sopenharmony_ci dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci ndacl_ptr->size = cpu_to_le16(0); 128862306a36Sopenharmony_ci ndacl_ptr->num_aces = cpu_to_le32(0); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr, 129162306a36Sopenharmony_ci pnmode, mode_from_sid); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 129462306a36Sopenharmony_ci /* copy the non-dacl portion of secdesc */ 129562306a36Sopenharmony_ci *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset, 129662306a36Sopenharmony_ci NULL, NULL); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci *aclflag |= CIFS_ACL_DACL; 129962306a36Sopenharmony_ci } else { 130062306a36Sopenharmony_ci ndacloffset = sizeof(struct cifs_ntsd); 130162306a36Sopenharmony_ci ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); 130262306a36Sopenharmony_ci ndacl_ptr->revision = 130362306a36Sopenharmony_ci dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION); 130462306a36Sopenharmony_ci ndacl_ptr->num_aces = dacl_ptr ? dacl_ptr->num_aces : 0; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (uid_valid(uid)) { /* chown */ 130762306a36Sopenharmony_ci uid_t id; 130862306a36Sopenharmony_ci nowner_sid_ptr = kzalloc(sizeof(struct cifs_sid), 130962306a36Sopenharmony_ci GFP_KERNEL); 131062306a36Sopenharmony_ci if (!nowner_sid_ptr) { 131162306a36Sopenharmony_ci rc = -ENOMEM; 131262306a36Sopenharmony_ci goto chown_chgrp_exit; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci id = from_kuid(&init_user_ns, uid); 131562306a36Sopenharmony_ci if (id_from_sid) { 131662306a36Sopenharmony_ci struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr; 131762306a36Sopenharmony_ci /* Populate the user ownership fields S-1-5-88-1 */ 131862306a36Sopenharmony_ci osid->Revision = 1; 131962306a36Sopenharmony_ci osid->NumAuth = 3; 132062306a36Sopenharmony_ci osid->Authority[5] = 5; 132162306a36Sopenharmony_ci osid->SubAuthorities[0] = cpu_to_le32(88); 132262306a36Sopenharmony_ci osid->SubAuthorities[1] = cpu_to_le32(1); 132362306a36Sopenharmony_ci osid->SubAuthorities[2] = cpu_to_le32(id); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci } else { /* lookup sid with upcall */ 132662306a36Sopenharmony_ci rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); 132762306a36Sopenharmony_ci if (rc) { 132862306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", 132962306a36Sopenharmony_ci __func__, rc, id); 133062306a36Sopenharmony_ci goto chown_chgrp_exit; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci } 133362306a36Sopenharmony_ci *aclflag |= CIFS_ACL_OWNER; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci if (gid_valid(gid)) { /* chgrp */ 133662306a36Sopenharmony_ci gid_t id; 133762306a36Sopenharmony_ci ngroup_sid_ptr = kzalloc(sizeof(struct cifs_sid), 133862306a36Sopenharmony_ci GFP_KERNEL); 133962306a36Sopenharmony_ci if (!ngroup_sid_ptr) { 134062306a36Sopenharmony_ci rc = -ENOMEM; 134162306a36Sopenharmony_ci goto chown_chgrp_exit; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci id = from_kgid(&init_user_ns, gid); 134462306a36Sopenharmony_ci if (id_from_sid) { 134562306a36Sopenharmony_ci struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr; 134662306a36Sopenharmony_ci /* Populate the group ownership fields S-1-5-88-2 */ 134762306a36Sopenharmony_ci gsid->Revision = 1; 134862306a36Sopenharmony_ci gsid->NumAuth = 3; 134962306a36Sopenharmony_ci gsid->Authority[5] = 5; 135062306a36Sopenharmony_ci gsid->SubAuthorities[0] = cpu_to_le32(88); 135162306a36Sopenharmony_ci gsid->SubAuthorities[1] = cpu_to_le32(2); 135262306a36Sopenharmony_ci gsid->SubAuthorities[2] = cpu_to_le32(id); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci } else { /* lookup sid with upcall */ 135562306a36Sopenharmony_ci rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); 135662306a36Sopenharmony_ci if (rc) { 135762306a36Sopenharmony_ci cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", 135862306a36Sopenharmony_ci __func__, rc, id); 135962306a36Sopenharmony_ci goto chown_chgrp_exit; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci *aclflag |= CIFS_ACL_GROUP; 136362306a36Sopenharmony_ci } 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci if (dacloffset) { 136662306a36Sopenharmony_ci /* Replace ACEs for old owner with new one */ 136762306a36Sopenharmony_ci size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr, 136862306a36Sopenharmony_ci owner_sid_ptr, group_sid_ptr, 136962306a36Sopenharmony_ci nowner_sid_ptr, ngroup_sid_ptr); 137062306a36Sopenharmony_ci ndacl_ptr->size = cpu_to_le16(size); 137162306a36Sopenharmony_ci } 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 137462306a36Sopenharmony_ci /* copy the non-dacl portion of secdesc */ 137562306a36Sopenharmony_ci *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset, 137662306a36Sopenharmony_ci nowner_sid_ptr, ngroup_sid_ptr); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cichown_chgrp_exit: 137962306a36Sopenharmony_ci /* errors could jump here. So make sure we return soon after this */ 138062306a36Sopenharmony_ci kfree(nowner_sid_ptr); 138162306a36Sopenharmony_ci kfree(ngroup_sid_ptr); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci return rc; 138562306a36Sopenharmony_ci} 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY 138862306a36Sopenharmony_cistruct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, 138962306a36Sopenharmony_ci const struct cifs_fid *cifsfid, u32 *pacllen, 139062306a36Sopenharmony_ci u32 __maybe_unused unused) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 139362306a36Sopenharmony_ci unsigned int xid; 139462306a36Sopenharmony_ci int rc; 139562306a36Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (IS_ERR(tlink)) 139862306a36Sopenharmony_ci return ERR_CAST(tlink); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci xid = get_xid(); 140162306a36Sopenharmony_ci rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd, 140262306a36Sopenharmony_ci pacllen); 140362306a36Sopenharmony_ci free_xid(xid); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci cifs_put_tlink(tlink); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen); 140862306a36Sopenharmony_ci if (rc) 140962306a36Sopenharmony_ci return ERR_PTR(rc); 141062306a36Sopenharmony_ci return pntsd; 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, 141462306a36Sopenharmony_ci const char *path, u32 *pacllen) 141562306a36Sopenharmony_ci{ 141662306a36Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 141762306a36Sopenharmony_ci int oplock = 0; 141862306a36Sopenharmony_ci unsigned int xid; 141962306a36Sopenharmony_ci int rc; 142062306a36Sopenharmony_ci struct cifs_tcon *tcon; 142162306a36Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 142262306a36Sopenharmony_ci struct cifs_fid fid; 142362306a36Sopenharmony_ci struct cifs_open_parms oparms; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (IS_ERR(tlink)) 142662306a36Sopenharmony_ci return ERR_CAST(tlink); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci tcon = tlink_tcon(tlink); 142962306a36Sopenharmony_ci xid = get_xid(); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci oparms = (struct cifs_open_parms) { 143262306a36Sopenharmony_ci .tcon = tcon, 143362306a36Sopenharmony_ci .cifs_sb = cifs_sb, 143462306a36Sopenharmony_ci .desired_access = READ_CONTROL, 143562306a36Sopenharmony_ci .create_options = cifs_create_options(cifs_sb, 0), 143662306a36Sopenharmony_ci .disposition = FILE_OPEN, 143762306a36Sopenharmony_ci .path = path, 143862306a36Sopenharmony_ci .fid = &fid, 143962306a36Sopenharmony_ci }; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci rc = CIFS_open(xid, &oparms, &oplock, NULL); 144262306a36Sopenharmony_ci if (!rc) { 144362306a36Sopenharmony_ci rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen); 144462306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci cifs_put_tlink(tlink); 144862306a36Sopenharmony_ci free_xid(xid); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen); 145162306a36Sopenharmony_ci if (rc) 145262306a36Sopenharmony_ci return ERR_PTR(rc); 145362306a36Sopenharmony_ci return pntsd; 145462306a36Sopenharmony_ci} 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci/* Retrieve an ACL from the server */ 145762306a36Sopenharmony_cistruct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, 145862306a36Sopenharmony_ci struct inode *inode, const char *path, 145962306a36Sopenharmony_ci u32 *pacllen, u32 info) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 146262306a36Sopenharmony_ci struct cifsFileInfo *open_file = NULL; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci if (inode) 146562306a36Sopenharmony_ci open_file = find_readable_file(CIFS_I(inode), true); 146662306a36Sopenharmony_ci if (!open_file) 146762306a36Sopenharmony_ci return get_cifs_acl_by_path(cifs_sb, path, pacllen); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info); 147062306a36Sopenharmony_ci cifsFileInfo_put(open_file); 147162306a36Sopenharmony_ci return pntsd; 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* Set an ACL on the server */ 147562306a36Sopenharmony_ciint set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, 147662306a36Sopenharmony_ci struct inode *inode, const char *path, int aclflag) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci int oplock = 0; 147962306a36Sopenharmony_ci unsigned int xid; 148062306a36Sopenharmony_ci int rc, access_flags; 148162306a36Sopenharmony_ci struct cifs_tcon *tcon; 148262306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 148362306a36Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 148462306a36Sopenharmony_ci struct cifs_fid fid; 148562306a36Sopenharmony_ci struct cifs_open_parms oparms; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci if (IS_ERR(tlink)) 148862306a36Sopenharmony_ci return PTR_ERR(tlink); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci tcon = tlink_tcon(tlink); 149162306a36Sopenharmony_ci xid = get_xid(); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) 149462306a36Sopenharmony_ci access_flags = WRITE_OWNER; 149562306a36Sopenharmony_ci else 149662306a36Sopenharmony_ci access_flags = WRITE_DAC; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci oparms = (struct cifs_open_parms) { 149962306a36Sopenharmony_ci .tcon = tcon, 150062306a36Sopenharmony_ci .cifs_sb = cifs_sb, 150162306a36Sopenharmony_ci .desired_access = access_flags, 150262306a36Sopenharmony_ci .create_options = cifs_create_options(cifs_sb, 0), 150362306a36Sopenharmony_ci .disposition = FILE_OPEN, 150462306a36Sopenharmony_ci .path = path, 150562306a36Sopenharmony_ci .fid = &fid, 150662306a36Sopenharmony_ci }; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci rc = CIFS_open(xid, &oparms, &oplock, NULL); 150962306a36Sopenharmony_ci if (rc) { 151062306a36Sopenharmony_ci cifs_dbg(VFS, "Unable to open file to set ACL\n"); 151162306a36Sopenharmony_ci goto out; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag); 151562306a36Sopenharmony_ci cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 151862306a36Sopenharmony_ciout: 151962306a36Sopenharmony_ci free_xid(xid); 152062306a36Sopenharmony_ci cifs_put_tlink(tlink); 152162306a36Sopenharmony_ci return rc; 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */ 152662306a36Sopenharmony_ciint 152762306a36Sopenharmony_cicifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, 152862306a36Sopenharmony_ci struct inode *inode, bool mode_from_special_sid, 152962306a36Sopenharmony_ci const char *path, const struct cifs_fid *pfid) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 153262306a36Sopenharmony_ci u32 acllen = 0; 153362306a36Sopenharmony_ci int rc = 0; 153462306a36Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 153562306a36Sopenharmony_ci struct smb_version_operations *ops; 153662306a36Sopenharmony_ci const u32 info = 0; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci cifs_dbg(NOISY, "converting ACL to mode for %s\n", path); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (IS_ERR(tlink)) 154162306a36Sopenharmony_ci return PTR_ERR(tlink); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci ops = tlink_tcon(tlink)->ses->server->ops; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (pfid && (ops->get_acl_by_fid)) 154662306a36Sopenharmony_ci pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info); 154762306a36Sopenharmony_ci else if (ops->get_acl) 154862306a36Sopenharmony_ci pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info); 154962306a36Sopenharmony_ci else { 155062306a36Sopenharmony_ci cifs_put_tlink(tlink); 155162306a36Sopenharmony_ci return -EOPNOTSUPP; 155262306a36Sopenharmony_ci } 155362306a36Sopenharmony_ci /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ 155462306a36Sopenharmony_ci if (IS_ERR(pntsd)) { 155562306a36Sopenharmony_ci rc = PTR_ERR(pntsd); 155662306a36Sopenharmony_ci cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); 155762306a36Sopenharmony_ci } else if (mode_from_special_sid) { 155862306a36Sopenharmony_ci rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true); 155962306a36Sopenharmony_ci kfree(pntsd); 156062306a36Sopenharmony_ci } else { 156162306a36Sopenharmony_ci /* get approximated mode from ACL */ 156262306a36Sopenharmony_ci rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false); 156362306a36Sopenharmony_ci kfree(pntsd); 156462306a36Sopenharmony_ci if (rc) 156562306a36Sopenharmony_ci cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc); 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci cifs_put_tlink(tlink); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci return rc; 157162306a36Sopenharmony_ci} 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci/* Convert mode bits to an ACL so we can update the ACL on the server */ 157462306a36Sopenharmony_ciint 157562306a36Sopenharmony_ciid_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, 157662306a36Sopenharmony_ci kuid_t uid, kgid_t gid) 157762306a36Sopenharmony_ci{ 157862306a36Sopenharmony_ci int rc = 0; 157962306a36Sopenharmony_ci int aclflag = CIFS_ACL_DACL; /* default flag to set */ 158062306a36Sopenharmony_ci __u32 secdesclen = 0; 158162306a36Sopenharmony_ci __u32 nsecdesclen = 0; 158262306a36Sopenharmony_ci __u32 dacloffset = 0; 158362306a36Sopenharmony_ci struct cifs_acl *dacl_ptr = NULL; 158462306a36Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ 158562306a36Sopenharmony_ci struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ 158662306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 158762306a36Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 158862306a36Sopenharmony_ci struct smb_version_operations *ops; 158962306a36Sopenharmony_ci bool mode_from_sid, id_from_sid; 159062306a36Sopenharmony_ci const u32 info = 0; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if (IS_ERR(tlink)) 159362306a36Sopenharmony_ci return PTR_ERR(tlink); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci ops = tlink_tcon(tlink)->ses->server->ops; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci cifs_dbg(NOISY, "set ACL from mode for %s\n", path); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci /* Get the security descriptor */ 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (ops->get_acl == NULL) { 160262306a36Sopenharmony_ci cifs_put_tlink(tlink); 160362306a36Sopenharmony_ci return -EOPNOTSUPP; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info); 160762306a36Sopenharmony_ci if (IS_ERR(pntsd)) { 160862306a36Sopenharmony_ci rc = PTR_ERR(pntsd); 160962306a36Sopenharmony_ci cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); 161062306a36Sopenharmony_ci cifs_put_tlink(tlink); 161162306a36Sopenharmony_ci return rc; 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) 161562306a36Sopenharmony_ci mode_from_sid = true; 161662306a36Sopenharmony_ci else 161762306a36Sopenharmony_ci mode_from_sid = false; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) 162062306a36Sopenharmony_ci id_from_sid = true; 162162306a36Sopenharmony_ci else 162262306a36Sopenharmony_ci id_from_sid = false; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */ 162562306a36Sopenharmony_ci nsecdesclen = secdesclen; 162662306a36Sopenharmony_ci if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */ 162762306a36Sopenharmony_ci if (mode_from_sid) 162862306a36Sopenharmony_ci nsecdesclen += 2 * sizeof(struct cifs_ace); 162962306a36Sopenharmony_ci else /* cifsacl */ 163062306a36Sopenharmony_ci nsecdesclen += 5 * sizeof(struct cifs_ace); 163162306a36Sopenharmony_ci } else { /* chown */ 163262306a36Sopenharmony_ci /* When ownership changes, changes new owner sid length could be different */ 163362306a36Sopenharmony_ci nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2); 163462306a36Sopenharmony_ci dacloffset = le32_to_cpu(pntsd->dacloffset); 163562306a36Sopenharmony_ci if (dacloffset) { 163662306a36Sopenharmony_ci dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 163762306a36Sopenharmony_ci if (mode_from_sid) 163862306a36Sopenharmony_ci nsecdesclen += 163962306a36Sopenharmony_ci le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace); 164062306a36Sopenharmony_ci else /* cifsacl */ 164162306a36Sopenharmony_ci nsecdesclen += le16_to_cpu(dacl_ptr->size); 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* 164662306a36Sopenharmony_ci * Add three ACEs for owner, group, everyone getting rid of other ACEs 164762306a36Sopenharmony_ci * as chmod disables ACEs and set the security descriptor. Allocate 164862306a36Sopenharmony_ci * memory for the smb header, set security descriptor request security 164962306a36Sopenharmony_ci * descriptor parameters, and security descriptor itself 165062306a36Sopenharmony_ci */ 165162306a36Sopenharmony_ci nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN); 165262306a36Sopenharmony_ci pnntsd = kmalloc(nsecdesclen, GFP_KERNEL); 165362306a36Sopenharmony_ci if (!pnntsd) { 165462306a36Sopenharmony_ci kfree(pntsd); 165562306a36Sopenharmony_ci cifs_put_tlink(tlink); 165662306a36Sopenharmony_ci return -ENOMEM; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid, 166062306a36Sopenharmony_ci mode_from_sid, id_from_sid, &aclflag); 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (ops->set_acl == NULL) 166562306a36Sopenharmony_ci rc = -EOPNOTSUPP; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (!rc) { 166862306a36Sopenharmony_ci /* Set the security descriptor */ 166962306a36Sopenharmony_ci rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag); 167062306a36Sopenharmony_ci cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); 167162306a36Sopenharmony_ci } 167262306a36Sopenharmony_ci cifs_put_tlink(tlink); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci kfree(pnntsd); 167562306a36Sopenharmony_ci kfree(pntsd); 167662306a36Sopenharmony_ci return rc; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistruct posix_acl *cifs_get_acl(struct mnt_idmap *idmap, 168062306a36Sopenharmony_ci struct dentry *dentry, int type) 168162306a36Sopenharmony_ci{ 168262306a36Sopenharmony_ci#if defined(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) && defined(CONFIG_CIFS_POSIX) 168362306a36Sopenharmony_ci struct posix_acl *acl = NULL; 168462306a36Sopenharmony_ci ssize_t rc = -EOPNOTSUPP; 168562306a36Sopenharmony_ci unsigned int xid; 168662306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 168762306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 168862306a36Sopenharmony_ci struct tcon_link *tlink; 168962306a36Sopenharmony_ci struct cifs_tcon *pTcon; 169062306a36Sopenharmony_ci const char *full_path; 169162306a36Sopenharmony_ci void *page; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 169462306a36Sopenharmony_ci if (IS_ERR(tlink)) 169562306a36Sopenharmony_ci return ERR_CAST(tlink); 169662306a36Sopenharmony_ci pTcon = tlink_tcon(tlink); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci xid = get_xid(); 169962306a36Sopenharmony_ci page = alloc_dentry_path(); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci full_path = build_path_from_dentry(dentry, page); 170262306a36Sopenharmony_ci if (IS_ERR(full_path)) { 170362306a36Sopenharmony_ci acl = ERR_CAST(full_path); 170462306a36Sopenharmony_ci goto out; 170562306a36Sopenharmony_ci } 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci /* return alt name if available as pseudo attr */ 170862306a36Sopenharmony_ci switch (type) { 170962306a36Sopenharmony_ci case ACL_TYPE_ACCESS: 171062306a36Sopenharmony_ci if (sb->s_flags & SB_POSIXACL) 171162306a36Sopenharmony_ci rc = cifs_do_get_acl(xid, pTcon, full_path, &acl, 171262306a36Sopenharmony_ci ACL_TYPE_ACCESS, 171362306a36Sopenharmony_ci cifs_sb->local_nls, 171462306a36Sopenharmony_ci cifs_remap(cifs_sb)); 171562306a36Sopenharmony_ci break; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci case ACL_TYPE_DEFAULT: 171862306a36Sopenharmony_ci if (sb->s_flags & SB_POSIXACL) 171962306a36Sopenharmony_ci rc = cifs_do_get_acl(xid, pTcon, full_path, &acl, 172062306a36Sopenharmony_ci ACL_TYPE_DEFAULT, 172162306a36Sopenharmony_ci cifs_sb->local_nls, 172262306a36Sopenharmony_ci cifs_remap(cifs_sb)); 172362306a36Sopenharmony_ci break; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci if (rc < 0) { 172762306a36Sopenharmony_ci if (rc == -EINVAL) 172862306a36Sopenharmony_ci acl = ERR_PTR(-EOPNOTSUPP); 172962306a36Sopenharmony_ci else 173062306a36Sopenharmony_ci acl = ERR_PTR(rc); 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ciout: 173462306a36Sopenharmony_ci free_dentry_path(page); 173562306a36Sopenharmony_ci free_xid(xid); 173662306a36Sopenharmony_ci cifs_put_tlink(tlink); 173762306a36Sopenharmony_ci return acl; 173862306a36Sopenharmony_ci#else 173962306a36Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 174062306a36Sopenharmony_ci#endif 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ciint cifs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, 174462306a36Sopenharmony_ci struct posix_acl *acl, int type) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci#if defined(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) && defined(CONFIG_CIFS_POSIX) 174762306a36Sopenharmony_ci int rc = -EOPNOTSUPP; 174862306a36Sopenharmony_ci unsigned int xid; 174962306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 175062306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 175162306a36Sopenharmony_ci struct tcon_link *tlink; 175262306a36Sopenharmony_ci struct cifs_tcon *pTcon; 175362306a36Sopenharmony_ci const char *full_path; 175462306a36Sopenharmony_ci void *page; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci tlink = cifs_sb_tlink(cifs_sb); 175762306a36Sopenharmony_ci if (IS_ERR(tlink)) 175862306a36Sopenharmony_ci return PTR_ERR(tlink); 175962306a36Sopenharmony_ci pTcon = tlink_tcon(tlink); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci xid = get_xid(); 176262306a36Sopenharmony_ci page = alloc_dentry_path(); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci full_path = build_path_from_dentry(dentry, page); 176562306a36Sopenharmony_ci if (IS_ERR(full_path)) { 176662306a36Sopenharmony_ci rc = PTR_ERR(full_path); 176762306a36Sopenharmony_ci goto out; 176862306a36Sopenharmony_ci } 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (!acl) 177162306a36Sopenharmony_ci goto out; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci /* return dos attributes as pseudo xattr */ 177462306a36Sopenharmony_ci /* return alt name if available as pseudo attr */ 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci /* if proc/fs/cifs/streamstoxattr is set then 177762306a36Sopenharmony_ci search server for EAs or streams to 177862306a36Sopenharmony_ci returns as xattrs */ 177962306a36Sopenharmony_ci if (posix_acl_xattr_size(acl->a_count) > CIFSMaxBufSize) { 178062306a36Sopenharmony_ci cifs_dbg(FYI, "size of EA value too large\n"); 178162306a36Sopenharmony_ci rc = -EOPNOTSUPP; 178262306a36Sopenharmony_ci goto out; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci switch (type) { 178662306a36Sopenharmony_ci case ACL_TYPE_ACCESS: 178762306a36Sopenharmony_ci if (sb->s_flags & SB_POSIXACL) 178862306a36Sopenharmony_ci rc = cifs_do_set_acl(xid, pTcon, full_path, acl, 178962306a36Sopenharmony_ci ACL_TYPE_ACCESS, 179062306a36Sopenharmony_ci cifs_sb->local_nls, 179162306a36Sopenharmony_ci cifs_remap(cifs_sb)); 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci case ACL_TYPE_DEFAULT: 179562306a36Sopenharmony_ci if (sb->s_flags & SB_POSIXACL) 179662306a36Sopenharmony_ci rc = cifs_do_set_acl(xid, pTcon, full_path, acl, 179762306a36Sopenharmony_ci ACL_TYPE_DEFAULT, 179862306a36Sopenharmony_ci cifs_sb->local_nls, 179962306a36Sopenharmony_ci cifs_remap(cifs_sb)); 180062306a36Sopenharmony_ci break; 180162306a36Sopenharmony_ci } 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ciout: 180462306a36Sopenharmony_ci free_dentry_path(page); 180562306a36Sopenharmony_ci free_xid(xid); 180662306a36Sopenharmony_ci cifs_put_tlink(tlink); 180762306a36Sopenharmony_ci return rc; 180862306a36Sopenharmony_ci#else 180962306a36Sopenharmony_ci return -EOPNOTSUPP; 181062306a36Sopenharmony_ci#endif 181162306a36Sopenharmony_ci} 1812