18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * fs/cifs/cifsacl.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) International Business Machines Corp., 2007,2008 58c2ecf20Sopenharmony_ci * Author(s): Steve French (sfrench@us.ibm.com) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Contains the routines for mapping CIFS/NTFS ACLs 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as published 118c2ecf20Sopenharmony_ci * by the Free Software Foundation; either version 2.1 of the License, or 128c2ecf20Sopenharmony_ci * (at your option) any later version. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This library is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 178c2ecf20Sopenharmony_ci * the GNU Lesser General Public License for more details. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public License 208c2ecf20Sopenharmony_ci * along with this library; if not, write to the Free Software 218c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/fs.h> 258c2ecf20Sopenharmony_ci#include <linux/slab.h> 268c2ecf20Sopenharmony_ci#include <linux/string.h> 278c2ecf20Sopenharmony_ci#include <linux/keyctl.h> 288c2ecf20Sopenharmony_ci#include <linux/key-type.h> 298c2ecf20Sopenharmony_ci#include <keys/user-type.h> 308c2ecf20Sopenharmony_ci#include "cifspdu.h" 318c2ecf20Sopenharmony_ci#include "cifsglob.h" 328c2ecf20Sopenharmony_ci#include "cifsacl.h" 338c2ecf20Sopenharmony_ci#include "cifsproto.h" 348c2ecf20Sopenharmony_ci#include "cifs_debug.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* security id for everyone/world system group */ 378c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_everyone = { 388c2ecf20Sopenharmony_ci 1, 1, {0, 0, 0, 0, 0, 1}, {0} }; 398c2ecf20Sopenharmony_ci/* security id for Authenticated Users system group */ 408c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_authusers = { 418c2ecf20Sopenharmony_ci 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} }; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* S-1-22-1 Unmapped Unix users */ 448c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22}, 458c2ecf20Sopenharmony_ci {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* S-1-22-2 Unmapped Unix groups */ 488c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, 498c2ecf20Sopenharmony_ci {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * See https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* S-1-5-88 MS NFS and Apple style UID/GID/mode */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* S-1-5-88-1 Unix uid */ 588c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5}, 598c2ecf20Sopenharmony_ci {cpu_to_le32(88), 608c2ecf20Sopenharmony_ci cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* S-1-5-88-2 Unix gid */ 638c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5}, 648c2ecf20Sopenharmony_ci {cpu_to_le32(88), 658c2ecf20Sopenharmony_ci cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* S-1-5-88-3 Unix mode */ 688c2ecf20Sopenharmony_cistatic const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5}, 698c2ecf20Sopenharmony_ci {cpu_to_le32(88), 708c2ecf20Sopenharmony_ci cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic const struct cred *root_cred; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int 758c2ecf20Sopenharmony_cicifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci char *payload; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * If the payload is less than or equal to the size of a pointer, then 818c2ecf20Sopenharmony_ci * an allocation here is wasteful. Just copy the data directly to the 828c2ecf20Sopenharmony_ci * payload.value union member instead. 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * With this however, you must check the datalen before trying to 858c2ecf20Sopenharmony_ci * dereference payload.data! 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci if (prep->datalen <= sizeof(key->payload)) { 888c2ecf20Sopenharmony_ci key->payload.data[0] = NULL; 898c2ecf20Sopenharmony_ci memcpy(&key->payload, prep->data, prep->datalen); 908c2ecf20Sopenharmony_ci } else { 918c2ecf20Sopenharmony_ci payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL); 928c2ecf20Sopenharmony_ci if (!payload) 938c2ecf20Sopenharmony_ci return -ENOMEM; 948c2ecf20Sopenharmony_ci key->payload.data[0] = payload; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci key->datalen = prep->datalen; 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic inline void 1028c2ecf20Sopenharmony_cicifs_idmap_key_destroy(struct key *key) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci if (key->datalen > sizeof(key->payload)) 1058c2ecf20Sopenharmony_ci kfree(key->payload.data[0]); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic struct key_type cifs_idmap_key_type = { 1098c2ecf20Sopenharmony_ci .name = "cifs.idmap", 1108c2ecf20Sopenharmony_ci .instantiate = cifs_idmap_key_instantiate, 1118c2ecf20Sopenharmony_ci .destroy = cifs_idmap_key_destroy, 1128c2ecf20Sopenharmony_ci .describe = user_describe, 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic char * 1168c2ecf20Sopenharmony_cisid_to_key_str(struct cifs_sid *sidptr, unsigned int type) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int i, len; 1198c2ecf20Sopenharmony_ci unsigned int saval; 1208c2ecf20Sopenharmony_ci char *sidstr, *strptr; 1218c2ecf20Sopenharmony_ci unsigned long long id_auth_val; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 3 bytes for prefix */ 1248c2ecf20Sopenharmony_ci sidstr = kmalloc(3 + SID_STRING_BASE_SIZE + 1258c2ecf20Sopenharmony_ci (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth), 1268c2ecf20Sopenharmony_ci GFP_KERNEL); 1278c2ecf20Sopenharmony_ci if (!sidstr) 1288c2ecf20Sopenharmony_ci return sidstr; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci strptr = sidstr; 1318c2ecf20Sopenharmony_ci len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g', 1328c2ecf20Sopenharmony_ci sidptr->revision); 1338c2ecf20Sopenharmony_ci strptr += len; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* The authority field is a single 48-bit number */ 1368c2ecf20Sopenharmony_ci id_auth_val = (unsigned long long)sidptr->authority[5]; 1378c2ecf20Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[4] << 8; 1388c2ecf20Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[3] << 16; 1398c2ecf20Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[2] << 24; 1408c2ecf20Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[1] << 32; 1418c2ecf20Sopenharmony_ci id_auth_val |= (unsigned long long)sidptr->authority[0] << 48; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * MS-DTYP states that if the authority is >= 2^32, then it should be 1458c2ecf20Sopenharmony_ci * expressed as a hex value. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (id_auth_val <= UINT_MAX) 1488c2ecf20Sopenharmony_ci len = sprintf(strptr, "-%llu", id_auth_val); 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci len = sprintf(strptr, "-0x%llx", id_auth_val); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci strptr += len; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci for (i = 0; i < sidptr->num_subauth; ++i) { 1558c2ecf20Sopenharmony_ci saval = le32_to_cpu(sidptr->sub_auth[i]); 1568c2ecf20Sopenharmony_ci len = sprintf(strptr, "-%u", saval); 1578c2ecf20Sopenharmony_ci strptr += len; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return sidstr; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* 1648c2ecf20Sopenharmony_ci * if the two SIDs (roughly equivalent to a UUID for a user or group) are 1658c2ecf20Sopenharmony_ci * the same returns zero, if they do not match returns non-zero. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic int 1688c2ecf20Sopenharmony_cicompare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci int i; 1718c2ecf20Sopenharmony_ci int num_subauth, num_sat, num_saw; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if ((!ctsid) || (!cwsid)) 1748c2ecf20Sopenharmony_ci return 1; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci /* compare the revision */ 1778c2ecf20Sopenharmony_ci if (ctsid->revision != cwsid->revision) { 1788c2ecf20Sopenharmony_ci if (ctsid->revision > cwsid->revision) 1798c2ecf20Sopenharmony_ci return 1; 1808c2ecf20Sopenharmony_ci else 1818c2ecf20Sopenharmony_ci return -1; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* compare all of the six auth values */ 1858c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; ++i) { 1868c2ecf20Sopenharmony_ci if (ctsid->authority[i] != cwsid->authority[i]) { 1878c2ecf20Sopenharmony_ci if (ctsid->authority[i] > cwsid->authority[i]) 1888c2ecf20Sopenharmony_ci return 1; 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci return -1; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* compare all of the subauth values if any */ 1958c2ecf20Sopenharmony_ci num_sat = ctsid->num_subauth; 1968c2ecf20Sopenharmony_ci num_saw = cwsid->num_subauth; 1978c2ecf20Sopenharmony_ci num_subauth = num_sat < num_saw ? num_sat : num_saw; 1988c2ecf20Sopenharmony_ci if (num_subauth) { 1998c2ecf20Sopenharmony_ci for (i = 0; i < num_subauth; ++i) { 2008c2ecf20Sopenharmony_ci if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) { 2018c2ecf20Sopenharmony_ci if (le32_to_cpu(ctsid->sub_auth[i]) > 2028c2ecf20Sopenharmony_ci le32_to_cpu(cwsid->sub_auth[i])) 2038c2ecf20Sopenharmony_ci return 1; 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci return -1; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; /* sids compare/match */ 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic bool 2148c2ecf20Sopenharmony_ciis_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci int i; 2178c2ecf20Sopenharmony_ci int num_subauth; 2188c2ecf20Sopenharmony_ci const struct cifs_sid *pwell_known_sid; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!psid || (puid == NULL)) 2218c2ecf20Sopenharmony_ci return false; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci num_subauth = psid->num_subauth; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */ 2268c2ecf20Sopenharmony_ci if (num_subauth == 2) { 2278c2ecf20Sopenharmony_ci if (is_group) 2288c2ecf20Sopenharmony_ci pwell_known_sid = &sid_unix_groups; 2298c2ecf20Sopenharmony_ci else 2308c2ecf20Sopenharmony_ci pwell_known_sid = &sid_unix_users; 2318c2ecf20Sopenharmony_ci } else if (num_subauth == 3) { 2328c2ecf20Sopenharmony_ci if (is_group) 2338c2ecf20Sopenharmony_ci pwell_known_sid = &sid_unix_NFS_groups; 2348c2ecf20Sopenharmony_ci else 2358c2ecf20Sopenharmony_ci pwell_known_sid = &sid_unix_NFS_users; 2368c2ecf20Sopenharmony_ci } else 2378c2ecf20Sopenharmony_ci return false; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* compare the revision */ 2408c2ecf20Sopenharmony_ci if (psid->revision != pwell_known_sid->revision) 2418c2ecf20Sopenharmony_ci return false; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* compare all of the six auth values */ 2448c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; ++i) { 2458c2ecf20Sopenharmony_ci if (psid->authority[i] != pwell_known_sid->authority[i]) { 2468c2ecf20Sopenharmony_ci cifs_dbg(FYI, "auth %d did not match\n", i); 2478c2ecf20Sopenharmony_ci return false; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (num_subauth == 2) { 2528c2ecf20Sopenharmony_ci if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) 2538c2ecf20Sopenharmony_ci return false; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci *puid = le32_to_cpu(psid->sub_auth[1]); 2568c2ecf20Sopenharmony_ci } else /* 3 subauths, ie Windows/Mac style */ { 2578c2ecf20Sopenharmony_ci *puid = le32_to_cpu(psid->sub_auth[0]); 2588c2ecf20Sopenharmony_ci if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) || 2598c2ecf20Sopenharmony_ci (psid->sub_auth[1] != pwell_known_sid->sub_auth[1])) 2608c2ecf20Sopenharmony_ci return false; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci *puid = le32_to_cpu(psid->sub_auth[2]); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid); 2668c2ecf20Sopenharmony_ci return true; /* well known sid found, uid returned */ 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void 2708c2ecf20Sopenharmony_cicifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci int i; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci dst->revision = src->revision; 2758c2ecf20Sopenharmony_ci dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES); 2768c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; ++i) 2778c2ecf20Sopenharmony_ci dst->authority[i] = src->authority[i]; 2788c2ecf20Sopenharmony_ci for (i = 0; i < dst->num_subauth; ++i) 2798c2ecf20Sopenharmony_ci dst->sub_auth[i] = src->sub_auth[i]; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int 2838c2ecf20Sopenharmony_ciid_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int rc; 2868c2ecf20Sopenharmony_ci struct key *sidkey; 2878c2ecf20Sopenharmony_ci struct cifs_sid *ksid; 2888c2ecf20Sopenharmony_ci unsigned int ksid_size; 2898c2ecf20Sopenharmony_ci char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */ 2908c2ecf20Sopenharmony_ci const struct cred *saved_cred; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci rc = snprintf(desc, sizeof(desc), "%ci:%u", 2938c2ecf20Sopenharmony_ci sidtype == SIDOWNER ? 'o' : 'g', cid); 2948c2ecf20Sopenharmony_ci if (rc >= sizeof(desc)) 2958c2ecf20Sopenharmony_ci return -EINVAL; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci rc = 0; 2988c2ecf20Sopenharmony_ci saved_cred = override_creds(root_cred); 2998c2ecf20Sopenharmony_ci sidkey = request_key(&cifs_idmap_key_type, desc, ""); 3008c2ecf20Sopenharmony_ci if (IS_ERR(sidkey)) { 3018c2ecf20Sopenharmony_ci rc = -EINVAL; 3028c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n", 3038c2ecf20Sopenharmony_ci __func__, sidtype == SIDOWNER ? 'u' : 'g', cid); 3048c2ecf20Sopenharmony_ci goto out_revert_creds; 3058c2ecf20Sopenharmony_ci } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) { 3068c2ecf20Sopenharmony_ci rc = -EIO; 3078c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n", 3088c2ecf20Sopenharmony_ci __func__, sidkey->datalen); 3098c2ecf20Sopenharmony_ci goto invalidate_key; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * A sid is usually too large to be embedded in payload.value, but if 3148c2ecf20Sopenharmony_ci * there are no subauthorities and the host has 8-byte pointers, then 3158c2ecf20Sopenharmony_ci * it could be. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci ksid = sidkey->datalen <= sizeof(sidkey->payload) ? 3188c2ecf20Sopenharmony_ci (struct cifs_sid *)&sidkey->payload : 3198c2ecf20Sopenharmony_ci (struct cifs_sid *)sidkey->payload.data[0]; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32)); 3228c2ecf20Sopenharmony_ci if (ksid_size > sidkey->datalen) { 3238c2ecf20Sopenharmony_ci rc = -EIO; 3248c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n", 3258c2ecf20Sopenharmony_ci __func__, sidkey->datalen, ksid_size); 3268c2ecf20Sopenharmony_ci goto invalidate_key; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci cifs_copy_sid(ssid, ksid); 3308c2ecf20Sopenharmony_ciout_key_put: 3318c2ecf20Sopenharmony_ci key_put(sidkey); 3328c2ecf20Sopenharmony_ciout_revert_creds: 3338c2ecf20Sopenharmony_ci revert_creds(saved_cred); 3348c2ecf20Sopenharmony_ci return rc; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ciinvalidate_key: 3378c2ecf20Sopenharmony_ci key_invalidate(sidkey); 3388c2ecf20Sopenharmony_ci goto out_key_put; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciint 3428c2ecf20Sopenharmony_cisid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, 3438c2ecf20Sopenharmony_ci struct cifs_fattr *fattr, uint sidtype) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int rc = 0; 3468c2ecf20Sopenharmony_ci struct key *sidkey; 3478c2ecf20Sopenharmony_ci char *sidstr; 3488c2ecf20Sopenharmony_ci const struct cred *saved_cred; 3498c2ecf20Sopenharmony_ci kuid_t fuid = cifs_sb->mnt_uid; 3508c2ecf20Sopenharmony_ci kgid_t fgid = cifs_sb->mnt_gid; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* 3538c2ecf20Sopenharmony_ci * If we have too many subauthorities, then something is really wrong. 3548c2ecf20Sopenharmony_ci * Just return an error. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ci if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) { 3578c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: %u subauthorities is too many!\n", 3588c2ecf20Sopenharmony_ci __func__, psid->num_subauth); 3598c2ecf20Sopenharmony_ci return -EIO; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) || 3638c2ecf20Sopenharmony_ci (cifs_sb_master_tcon(cifs_sb)->posix_extensions)) { 3648c2ecf20Sopenharmony_ci uint32_t unix_id; 3658c2ecf20Sopenharmony_ci bool is_group; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (sidtype != SIDOWNER) 3688c2ecf20Sopenharmony_ci is_group = true; 3698c2ecf20Sopenharmony_ci else 3708c2ecf20Sopenharmony_ci is_group = false; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (is_well_known_sid(psid, &unix_id, is_group) == false) 3738c2ecf20Sopenharmony_ci goto try_upcall_to_get_id; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (is_group) { 3768c2ecf20Sopenharmony_ci kgid_t gid; 3778c2ecf20Sopenharmony_ci gid_t id; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci id = (gid_t)unix_id; 3808c2ecf20Sopenharmony_ci gid = make_kgid(&init_user_ns, id); 3818c2ecf20Sopenharmony_ci if (gid_valid(gid)) { 3828c2ecf20Sopenharmony_ci fgid = gid; 3838c2ecf20Sopenharmony_ci goto got_valid_id; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } else { 3868c2ecf20Sopenharmony_ci kuid_t uid; 3878c2ecf20Sopenharmony_ci uid_t id; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci id = (uid_t)unix_id; 3908c2ecf20Sopenharmony_ci uid = make_kuid(&init_user_ns, id); 3918c2ecf20Sopenharmony_ci if (uid_valid(uid)) { 3928c2ecf20Sopenharmony_ci fuid = uid; 3938c2ecf20Sopenharmony_ci goto got_valid_id; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci /* If unable to find uid/gid easily from SID try via upcall */ 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_citry_upcall_to_get_id: 4008c2ecf20Sopenharmony_ci sidstr = sid_to_key_str(psid, sidtype); 4018c2ecf20Sopenharmony_ci if (!sidstr) 4028c2ecf20Sopenharmony_ci return -ENOMEM; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci saved_cred = override_creds(root_cred); 4058c2ecf20Sopenharmony_ci sidkey = request_key(&cifs_idmap_key_type, sidstr, ""); 4068c2ecf20Sopenharmony_ci if (IS_ERR(sidkey)) { 4078c2ecf20Sopenharmony_ci rc = -EINVAL; 4088c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n", 4098c2ecf20Sopenharmony_ci __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g'); 4108c2ecf20Sopenharmony_ci goto out_revert_creds; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * FIXME: Here we assume that uid_t and gid_t are same size. It's 4158c2ecf20Sopenharmony_ci * probably a safe assumption but might be better to check based on 4168c2ecf20Sopenharmony_ci * sidtype. 4178c2ecf20Sopenharmony_ci */ 4188c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t)); 4198c2ecf20Sopenharmony_ci if (sidkey->datalen != sizeof(uid_t)) { 4208c2ecf20Sopenharmony_ci rc = -EIO; 4218c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n", 4228c2ecf20Sopenharmony_ci __func__, sidkey->datalen); 4238c2ecf20Sopenharmony_ci key_invalidate(sidkey); 4248c2ecf20Sopenharmony_ci goto out_key_put; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (sidtype == SIDOWNER) { 4288c2ecf20Sopenharmony_ci kuid_t uid; 4298c2ecf20Sopenharmony_ci uid_t id; 4308c2ecf20Sopenharmony_ci memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t)); 4318c2ecf20Sopenharmony_ci uid = make_kuid(&init_user_ns, id); 4328c2ecf20Sopenharmony_ci if (uid_valid(uid)) 4338c2ecf20Sopenharmony_ci fuid = uid; 4348c2ecf20Sopenharmony_ci } else { 4358c2ecf20Sopenharmony_ci kgid_t gid; 4368c2ecf20Sopenharmony_ci gid_t id; 4378c2ecf20Sopenharmony_ci memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t)); 4388c2ecf20Sopenharmony_ci gid = make_kgid(&init_user_ns, id); 4398c2ecf20Sopenharmony_ci if (gid_valid(gid)) 4408c2ecf20Sopenharmony_ci fgid = gid; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciout_key_put: 4448c2ecf20Sopenharmony_ci key_put(sidkey); 4458c2ecf20Sopenharmony_ciout_revert_creds: 4468c2ecf20Sopenharmony_ci revert_creds(saved_cred); 4478c2ecf20Sopenharmony_ci kfree(sidstr); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * Note that we return 0 here unconditionally. If the mapping 4518c2ecf20Sopenharmony_ci * fails then we just fall back to using the mnt_uid/mnt_gid. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_cigot_valid_id: 4548c2ecf20Sopenharmony_ci rc = 0; 4558c2ecf20Sopenharmony_ci if (sidtype == SIDOWNER) 4568c2ecf20Sopenharmony_ci fattr->cf_uid = fuid; 4578c2ecf20Sopenharmony_ci else 4588c2ecf20Sopenharmony_ci fattr->cf_gid = fgid; 4598c2ecf20Sopenharmony_ci return rc; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ciint 4638c2ecf20Sopenharmony_ciinit_cifs_idmap(void) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci struct cred *cred; 4668c2ecf20Sopenharmony_ci struct key *keyring; 4678c2ecf20Sopenharmony_ci int ret; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Registering the %s key type\n", 4708c2ecf20Sopenharmony_ci cifs_idmap_key_type.name); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* create an override credential set with a special thread keyring in 4738c2ecf20Sopenharmony_ci * which requests are cached 4748c2ecf20Sopenharmony_ci * 4758c2ecf20Sopenharmony_ci * this is used to prevent malicious redirections from being installed 4768c2ecf20Sopenharmony_ci * with add_key(). 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ci cred = prepare_kernel_cred(NULL); 4798c2ecf20Sopenharmony_ci if (!cred) 4808c2ecf20Sopenharmony_ci return -ENOMEM; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci keyring = keyring_alloc(".cifs_idmap", 4838c2ecf20Sopenharmony_ci GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 4848c2ecf20Sopenharmony_ci (KEY_POS_ALL & ~KEY_POS_SETATTR) | 4858c2ecf20Sopenharmony_ci KEY_USR_VIEW | KEY_USR_READ, 4868c2ecf20Sopenharmony_ci KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL); 4878c2ecf20Sopenharmony_ci if (IS_ERR(keyring)) { 4888c2ecf20Sopenharmony_ci ret = PTR_ERR(keyring); 4898c2ecf20Sopenharmony_ci goto failed_put_cred; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ret = register_key_type(&cifs_idmap_key_type); 4938c2ecf20Sopenharmony_ci if (ret < 0) 4948c2ecf20Sopenharmony_ci goto failed_put_key; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* instruct request_key() to use this special keyring as a cache for 4978c2ecf20Sopenharmony_ci * the results it looks up */ 4988c2ecf20Sopenharmony_ci set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); 4998c2ecf20Sopenharmony_ci cred->thread_keyring = keyring; 5008c2ecf20Sopenharmony_ci cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; 5018c2ecf20Sopenharmony_ci root_cred = cred; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring)); 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cifailed_put_key: 5078c2ecf20Sopenharmony_ci key_put(keyring); 5088c2ecf20Sopenharmony_cifailed_put_cred: 5098c2ecf20Sopenharmony_ci put_cred(cred); 5108c2ecf20Sopenharmony_ci return ret; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_civoid 5148c2ecf20Sopenharmony_ciexit_cifs_idmap(void) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci key_revoke(root_cred->thread_keyring); 5178c2ecf20Sopenharmony_ci unregister_key_type(&cifs_idmap_key_type); 5188c2ecf20Sopenharmony_ci put_cred(root_cred); 5198c2ecf20Sopenharmony_ci cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci/* copy ntsd, owner sid, and group sid from a security descriptor to another */ 5238c2ecf20Sopenharmony_cistatic void copy_sec_desc(const struct cifs_ntsd *pntsd, 5248c2ecf20Sopenharmony_ci struct cifs_ntsd *pnntsd, __u32 sidsoffset) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 5278c2ecf20Sopenharmony_ci struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* copy security descriptor control portion */ 5308c2ecf20Sopenharmony_ci pnntsd->revision = pntsd->revision; 5318c2ecf20Sopenharmony_ci pnntsd->type = pntsd->type; 5328c2ecf20Sopenharmony_ci pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd)); 5338c2ecf20Sopenharmony_ci pnntsd->sacloffset = 0; 5348c2ecf20Sopenharmony_ci pnntsd->osidoffset = cpu_to_le32(sidsoffset); 5358c2ecf20Sopenharmony_ci pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid)); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* copy owner sid */ 5388c2ecf20Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 5398c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->osidoffset)); 5408c2ecf20Sopenharmony_ci nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset); 5418c2ecf20Sopenharmony_ci cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* copy group sid */ 5448c2ecf20Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 5458c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset)); 5468c2ecf20Sopenharmony_ci ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset + 5478c2ecf20Sopenharmony_ci sizeof(struct cifs_sid)); 5488c2ecf20Sopenharmony_ci cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* 5558c2ecf20Sopenharmony_ci change posix mode to reflect permissions 5568c2ecf20Sopenharmony_ci pmode is the existing mode (we only want to overwrite part of this 5578c2ecf20Sopenharmony_ci bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007 5588c2ecf20Sopenharmony_ci*/ 5598c2ecf20Sopenharmony_cistatic void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode, 5608c2ecf20Sopenharmony_ci umode_t *pbits_to_set) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci __u32 flags = le32_to_cpu(ace_flags); 5638c2ecf20Sopenharmony_ci /* the order of ACEs is important. The canonical order is to begin with 5648c2ecf20Sopenharmony_ci DENY entries followed by ALLOW, otherwise an allow entry could be 5658c2ecf20Sopenharmony_ci encountered first, making the subsequent deny entry like "dead code" 5668c2ecf20Sopenharmony_ci which would be superflous since Windows stops when a match is made 5678c2ecf20Sopenharmony_ci for the operation you are trying to perform for your user */ 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci /* For deny ACEs we change the mask so that subsequent allow access 5708c2ecf20Sopenharmony_ci control entries do not turn on the bits we are denying */ 5718c2ecf20Sopenharmony_ci if (type == ACCESS_DENIED) { 5728c2ecf20Sopenharmony_ci if (flags & GENERIC_ALL) 5738c2ecf20Sopenharmony_ci *pbits_to_set &= ~S_IRWXUGO; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if ((flags & GENERIC_WRITE) || 5768c2ecf20Sopenharmony_ci ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) 5778c2ecf20Sopenharmony_ci *pbits_to_set &= ~S_IWUGO; 5788c2ecf20Sopenharmony_ci if ((flags & GENERIC_READ) || 5798c2ecf20Sopenharmony_ci ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) 5808c2ecf20Sopenharmony_ci *pbits_to_set &= ~S_IRUGO; 5818c2ecf20Sopenharmony_ci if ((flags & GENERIC_EXECUTE) || 5828c2ecf20Sopenharmony_ci ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) 5838c2ecf20Sopenharmony_ci *pbits_to_set &= ~S_IXUGO; 5848c2ecf20Sopenharmony_ci return; 5858c2ecf20Sopenharmony_ci } else if (type != ACCESS_ALLOWED) { 5868c2ecf20Sopenharmony_ci cifs_dbg(VFS, "unknown access control type %d\n", type); 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci /* else ACCESS_ALLOWED type */ 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (flags & GENERIC_ALL) { 5928c2ecf20Sopenharmony_ci *pmode |= (S_IRWXUGO & (*pbits_to_set)); 5938c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "all perms\n"); 5948c2ecf20Sopenharmony_ci return; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci if ((flags & GENERIC_WRITE) || 5978c2ecf20Sopenharmony_ci ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) 5988c2ecf20Sopenharmony_ci *pmode |= (S_IWUGO & (*pbits_to_set)); 5998c2ecf20Sopenharmony_ci if ((flags & GENERIC_READ) || 6008c2ecf20Sopenharmony_ci ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) 6018c2ecf20Sopenharmony_ci *pmode |= (S_IRUGO & (*pbits_to_set)); 6028c2ecf20Sopenharmony_ci if ((flags & GENERIC_EXECUTE) || 6038c2ecf20Sopenharmony_ci ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) 6048c2ecf20Sopenharmony_ci *pmode |= (S_IXUGO & (*pbits_to_set)); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode); 6078c2ecf20Sopenharmony_ci return; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci/* 6118c2ecf20Sopenharmony_ci Generate access flags to reflect permissions mode is the existing mode. 6128c2ecf20Sopenharmony_ci This function is called for every ACE in the DACL whose SID matches 6138c2ecf20Sopenharmony_ci with either owner or group or everyone. 6148c2ecf20Sopenharmony_ci*/ 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic void mode_to_access_flags(umode_t mode, umode_t bits_to_use, 6178c2ecf20Sopenharmony_ci __u32 *pace_flags) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci /* reset access mask */ 6208c2ecf20Sopenharmony_ci *pace_flags = 0x0; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */ 6238c2ecf20Sopenharmony_ci mode &= bits_to_use; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* check for R/W/X UGO since we do not know whose flags 6268c2ecf20Sopenharmony_ci is this but we have cleared all the bits sans RWX for 6278c2ecf20Sopenharmony_ci either user or group or other as per bits_to_use */ 6288c2ecf20Sopenharmony_ci if (mode & S_IRUGO) 6298c2ecf20Sopenharmony_ci *pace_flags |= SET_FILE_READ_RIGHTS; 6308c2ecf20Sopenharmony_ci if (mode & S_IWUGO) 6318c2ecf20Sopenharmony_ci *pace_flags |= SET_FILE_WRITE_RIGHTS; 6328c2ecf20Sopenharmony_ci if (mode & S_IXUGO) 6338c2ecf20Sopenharmony_ci *pace_flags |= SET_FILE_EXEC_RIGHTS; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n", 6368c2ecf20Sopenharmony_ci mode, *pace_flags); 6378c2ecf20Sopenharmony_ci return; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic __u16 fill_ace_for_sid(struct cifs_ace *pntace, 6418c2ecf20Sopenharmony_ci const struct cifs_sid *psid, __u64 nmode, umode_t bits) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci int i; 6448c2ecf20Sopenharmony_ci __u16 size = 0; 6458c2ecf20Sopenharmony_ci __u32 access_req = 0; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci pntace->type = ACCESS_ALLOWED; 6488c2ecf20Sopenharmony_ci pntace->flags = 0x0; 6498c2ecf20Sopenharmony_ci mode_to_access_flags(nmode, bits, &access_req); 6508c2ecf20Sopenharmony_ci if (!access_req) 6518c2ecf20Sopenharmony_ci access_req = SET_MINIMUM_RIGHTS; 6528c2ecf20Sopenharmony_ci pntace->access_req = cpu_to_le32(access_req); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci pntace->sid.revision = psid->revision; 6558c2ecf20Sopenharmony_ci pntace->sid.num_subauth = psid->num_subauth; 6568c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 6578c2ecf20Sopenharmony_ci pntace->sid.authority[i] = psid->authority[i]; 6588c2ecf20Sopenharmony_ci for (i = 0; i < psid->num_subauth; i++) 6598c2ecf20Sopenharmony_ci pntace->sid.sub_auth[i] = psid->sub_auth[i]; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4); 6628c2ecf20Sopenharmony_ci pntace->size = cpu_to_le16(size); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci return size; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG2 6698c2ecf20Sopenharmony_cistatic void dump_ace(struct cifs_ace *pace, char *end_of_acl) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci int num_subauth; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* validate that we do not go past end of acl */ 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (le16_to_cpu(pace->size) < 16) { 6768c2ecf20Sopenharmony_ci cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size)); 6778c2ecf20Sopenharmony_ci return; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) { 6818c2ecf20Sopenharmony_ci cifs_dbg(VFS, "ACL too small to parse ACE\n"); 6828c2ecf20Sopenharmony_ci return; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci num_subauth = pace->sid.num_subauth; 6868c2ecf20Sopenharmony_ci if (num_subauth) { 6878c2ecf20Sopenharmony_ci int i; 6888c2ecf20Sopenharmony_ci cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n", 6898c2ecf20Sopenharmony_ci pace->sid.revision, pace->sid.num_subauth, pace->type, 6908c2ecf20Sopenharmony_ci pace->flags, le16_to_cpu(pace->size)); 6918c2ecf20Sopenharmony_ci for (i = 0; i < num_subauth; ++i) { 6928c2ecf20Sopenharmony_ci cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n", 6938c2ecf20Sopenharmony_ci i, le32_to_cpu(pace->sid.sub_auth[i])); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* BB add length check to make sure that we do not have huge 6978c2ecf20Sopenharmony_ci num auths and therefore go off the end */ 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci return; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci#endif 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, 7058c2ecf20Sopenharmony_ci struct cifs_sid *pownersid, struct cifs_sid *pgrpsid, 7068c2ecf20Sopenharmony_ci struct cifs_fattr *fattr, bool mode_from_special_sid) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci int i; 7098c2ecf20Sopenharmony_ci int num_aces = 0; 7108c2ecf20Sopenharmony_ci int acl_size; 7118c2ecf20Sopenharmony_ci char *acl_base; 7128c2ecf20Sopenharmony_ci struct cifs_ace **ppace; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* BB need to add parm so we can store the SID BB */ 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (!pdacl) { 7178c2ecf20Sopenharmony_ci /* no DACL in the security descriptor, set 7188c2ecf20Sopenharmony_ci all the permissions for user/group/other */ 7198c2ecf20Sopenharmony_ci fattr->cf_mode |= S_IRWXUGO; 7208c2ecf20Sopenharmony_ci return; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* validate that we do not go past end of acl */ 7248c2ecf20Sopenharmony_ci if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { 7258c2ecf20Sopenharmony_ci cifs_dbg(VFS, "ACL too small to parse DACL\n"); 7268c2ecf20Sopenharmony_ci return; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", 7308c2ecf20Sopenharmony_ci le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), 7318c2ecf20Sopenharmony_ci le32_to_cpu(pdacl->num_aces)); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* reset rwx permissions for user/group/other. 7348c2ecf20Sopenharmony_ci Also, if num_aces is 0 i.e. DACL has no ACEs, 7358c2ecf20Sopenharmony_ci user/group/other have no permissions */ 7368c2ecf20Sopenharmony_ci fattr->cf_mode &= ~(S_IRWXUGO); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci acl_base = (char *)pdacl; 7398c2ecf20Sopenharmony_ci acl_size = sizeof(struct cifs_acl); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci num_aces = le32_to_cpu(pdacl->num_aces); 7428c2ecf20Sopenharmony_ci if (num_aces > 0) { 7438c2ecf20Sopenharmony_ci umode_t user_mask = S_IRWXU; 7448c2ecf20Sopenharmony_ci umode_t group_mask = S_IRWXG; 7458c2ecf20Sopenharmony_ci umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *)) 7488c2ecf20Sopenharmony_ci return; 7498c2ecf20Sopenharmony_ci ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *), 7508c2ecf20Sopenharmony_ci GFP_KERNEL); 7518c2ecf20Sopenharmony_ci if (!ppace) 7528c2ecf20Sopenharmony_ci return; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci for (i = 0; i < num_aces; ++i) { 7558c2ecf20Sopenharmony_ci ppace[i] = (struct cifs_ace *) (acl_base + acl_size); 7568c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG2 7578c2ecf20Sopenharmony_ci dump_ace(ppace[i], end_of_acl); 7588c2ecf20Sopenharmony_ci#endif 7598c2ecf20Sopenharmony_ci if (mode_from_special_sid && 7608c2ecf20Sopenharmony_ci (compare_sids(&(ppace[i]->sid), 7618c2ecf20Sopenharmony_ci &sid_unix_NFS_mode) == 0)) { 7628c2ecf20Sopenharmony_ci /* 7638c2ecf20Sopenharmony_ci * Full permissions are: 7648c2ecf20Sopenharmony_ci * 07777 = S_ISUID | S_ISGID | S_ISVTX | 7658c2ecf20Sopenharmony_ci * S_IRWXU | S_IRWXG | S_IRWXO 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_ci fattr->cf_mode &= ~07777; 7688c2ecf20Sopenharmony_ci fattr->cf_mode |= 7698c2ecf20Sopenharmony_ci le32_to_cpu(ppace[i]->sid.sub_auth[2]); 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci } else if (compare_sids(&(ppace[i]->sid), pownersid) == 0) 7728c2ecf20Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 7738c2ecf20Sopenharmony_ci ppace[i]->type, 7748c2ecf20Sopenharmony_ci &fattr->cf_mode, 7758c2ecf20Sopenharmony_ci &user_mask); 7768c2ecf20Sopenharmony_ci else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) 7778c2ecf20Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 7788c2ecf20Sopenharmony_ci ppace[i]->type, 7798c2ecf20Sopenharmony_ci &fattr->cf_mode, 7808c2ecf20Sopenharmony_ci &group_mask); 7818c2ecf20Sopenharmony_ci else if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) 7828c2ecf20Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 7838c2ecf20Sopenharmony_ci ppace[i]->type, 7848c2ecf20Sopenharmony_ci &fattr->cf_mode, 7858c2ecf20Sopenharmony_ci &other_mask); 7868c2ecf20Sopenharmony_ci else if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0) 7878c2ecf20Sopenharmony_ci access_flags_to_mode(ppace[i]->access_req, 7888c2ecf20Sopenharmony_ci ppace[i]->type, 7898c2ecf20Sopenharmony_ci &fattr->cf_mode, 7908c2ecf20Sopenharmony_ci &other_mask); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* memcpy((void *)(&(cifscred->aces[i])), 7948c2ecf20Sopenharmony_ci (void *)ppace[i], 7958c2ecf20Sopenharmony_ci sizeof(struct cifs_ace)); */ 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci acl_base = (char *)ppace[i]; 7988c2ecf20Sopenharmony_ci acl_size = le16_to_cpu(ppace[i]->size); 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci kfree(ppace); 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciunsigned int setup_authusers_ACE(struct cifs_ace *pntace) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci int i; 8108c2ecf20Sopenharmony_ci unsigned int ace_size = 20; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci pntace->type = ACCESS_ALLOWED_ACE_TYPE; 8138c2ecf20Sopenharmony_ci pntace->flags = 0x0; 8148c2ecf20Sopenharmony_ci pntace->access_req = cpu_to_le32(GENERIC_ALL); 8158c2ecf20Sopenharmony_ci pntace->sid.num_subauth = 1; 8168c2ecf20Sopenharmony_ci pntace->sid.revision = 1; 8178c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 8188c2ecf20Sopenharmony_ci pntace->sid.authority[i] = sid_authusers.authority[i]; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0]; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ 8238c2ecf20Sopenharmony_ci pntace->size = cpu_to_le16(ace_size); 8248c2ecf20Sopenharmony_ci return ace_size; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci/* 8288c2ecf20Sopenharmony_ci * Fill in the special SID based on the mode. See 8298c2ecf20Sopenharmony_ci * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx 8308c2ecf20Sopenharmony_ci */ 8318c2ecf20Sopenharmony_ciunsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci int i; 8348c2ecf20Sopenharmony_ci unsigned int ace_size = 28; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci pntace->type = ACCESS_DENIED_ACE_TYPE; 8378c2ecf20Sopenharmony_ci pntace->flags = 0x0; 8388c2ecf20Sopenharmony_ci pntace->access_req = 0; 8398c2ecf20Sopenharmony_ci pntace->sid.num_subauth = 3; 8408c2ecf20Sopenharmony_ci pntace->sid.revision = 1; 8418c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 8428c2ecf20Sopenharmony_ci pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i]; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0]; 8458c2ecf20Sopenharmony_ci pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1]; 8468c2ecf20Sopenharmony_ci pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ 8498c2ecf20Sopenharmony_ci pntace->size = cpu_to_le16(ace_size); 8508c2ecf20Sopenharmony_ci return ace_size; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ciunsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci int i; 8568c2ecf20Sopenharmony_ci unsigned int ace_size = 28; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci pntace->type = ACCESS_ALLOWED_ACE_TYPE; 8598c2ecf20Sopenharmony_ci pntace->flags = 0x0; 8608c2ecf20Sopenharmony_ci pntace->access_req = cpu_to_le32(GENERIC_ALL); 8618c2ecf20Sopenharmony_ci pntace->sid.num_subauth = 3; 8628c2ecf20Sopenharmony_ci pntace->sid.revision = 1; 8638c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTHS; i++) 8648c2ecf20Sopenharmony_ci pntace->sid.authority[i] = sid_unix_NFS_users.authority[i]; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0]; 8678c2ecf20Sopenharmony_ci pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1]; 8688c2ecf20Sopenharmony_ci pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */ 8718c2ecf20Sopenharmony_ci pntace->size = cpu_to_le16(ace_size); 8728c2ecf20Sopenharmony_ci return ace_size; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid, 8768c2ecf20Sopenharmony_ci struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci u16 size = 0; 8798c2ecf20Sopenharmony_ci u32 num_aces = 0; 8808c2ecf20Sopenharmony_ci struct cifs_acl *pnndacl; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl)); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci if (modefromsid) { 8858c2ecf20Sopenharmony_ci struct cifs_ace *pntace = 8868c2ecf20Sopenharmony_ci (struct cifs_ace *)((char *)pnndacl + size); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci size += setup_special_mode_ACE(pntace, nmode); 8898c2ecf20Sopenharmony_ci num_aces++; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size), 8938c2ecf20Sopenharmony_ci pownersid, nmode, S_IRWXU); 8948c2ecf20Sopenharmony_ci num_aces++; 8958c2ecf20Sopenharmony_ci size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 8968c2ecf20Sopenharmony_ci pgrpsid, nmode, S_IRWXG); 8978c2ecf20Sopenharmony_ci num_aces++; 8988c2ecf20Sopenharmony_ci size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size), 8998c2ecf20Sopenharmony_ci &sid_everyone, nmode, S_IRWXO); 9008c2ecf20Sopenharmony_ci num_aces++; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci pndacl->num_aces = cpu_to_le32(num_aces); 9038c2ecf20Sopenharmony_ci pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl)); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci return 0; 9068c2ecf20Sopenharmony_ci} 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic int parse_sid(struct cifs_sid *psid, char *end_of_acl) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci /* BB need to add parm so we can store the SID BB */ 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* validate that we do not go past end of ACL - sid must be at least 8 9148c2ecf20Sopenharmony_ci bytes long (assuming no sub-auths - e.g. the null SID */ 9158c2ecf20Sopenharmony_ci if (end_of_acl < (char *)psid + 8) { 9168c2ecf20Sopenharmony_ci cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid); 9178c2ecf20Sopenharmony_ci return -EINVAL; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci#ifdef CONFIG_CIFS_DEBUG2 9218c2ecf20Sopenharmony_ci if (psid->num_subauth) { 9228c2ecf20Sopenharmony_ci int i; 9238c2ecf20Sopenharmony_ci cifs_dbg(FYI, "SID revision %d num_auth %d\n", 9248c2ecf20Sopenharmony_ci psid->revision, psid->num_subauth); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci for (i = 0; i < psid->num_subauth; i++) { 9278c2ecf20Sopenharmony_ci cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n", 9288c2ecf20Sopenharmony_ci i, le32_to_cpu(psid->sub_auth[i])); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* BB add length check to make sure that we do not have huge 9328c2ecf20Sopenharmony_ci num auths and therefore go off the end */ 9338c2ecf20Sopenharmony_ci cifs_dbg(FYI, "RID 0x%x\n", 9348c2ecf20Sopenharmony_ci le32_to_cpu(psid->sub_auth[psid->num_subauth-1])); 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci#endif 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return 0; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/* Convert CIFS ACL to POSIX form */ 9438c2ecf20Sopenharmony_cistatic int parse_sec_desc(struct cifs_sb_info *cifs_sb, 9448c2ecf20Sopenharmony_ci struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr, 9458c2ecf20Sopenharmony_ci bool get_mode_from_special_sid) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci int rc = 0; 9488c2ecf20Sopenharmony_ci struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 9498c2ecf20Sopenharmony_ci struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ 9508c2ecf20Sopenharmony_ci char *end_of_acl = ((char *)pntsd) + acl_len; 9518c2ecf20Sopenharmony_ci __u32 dacloffset; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (pntsd == NULL) 9548c2ecf20Sopenharmony_ci return -EIO; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 9578c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->osidoffset)); 9588c2ecf20Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 9598c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset)); 9608c2ecf20Sopenharmony_ci dacloffset = le32_to_cpu(pntsd->dacloffset); 9618c2ecf20Sopenharmony_ci dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 9628c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", 9638c2ecf20Sopenharmony_ci pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), 9648c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset), 9658c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->sacloffset), dacloffset); 9668c2ecf20Sopenharmony_ci/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */ 9678c2ecf20Sopenharmony_ci rc = parse_sid(owner_sid_ptr, end_of_acl); 9688c2ecf20Sopenharmony_ci if (rc) { 9698c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc); 9708c2ecf20Sopenharmony_ci return rc; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER); 9738c2ecf20Sopenharmony_ci if (rc) { 9748c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n", 9758c2ecf20Sopenharmony_ci __func__, rc); 9768c2ecf20Sopenharmony_ci return rc; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci rc = parse_sid(group_sid_ptr, end_of_acl); 9808c2ecf20Sopenharmony_ci if (rc) { 9818c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n", 9828c2ecf20Sopenharmony_ci __func__, rc); 9838c2ecf20Sopenharmony_ci return rc; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP); 9868c2ecf20Sopenharmony_ci if (rc) { 9878c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n", 9888c2ecf20Sopenharmony_ci __func__, rc); 9898c2ecf20Sopenharmony_ci return rc; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (dacloffset) 9938c2ecf20Sopenharmony_ci parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, 9948c2ecf20Sopenharmony_ci group_sid_ptr, fattr, get_mode_from_special_sid); 9958c2ecf20Sopenharmony_ci else 9968c2ecf20Sopenharmony_ci cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */ 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci return rc; 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci/* Convert permission bits from mode to equivalent CIFS ACL */ 10028c2ecf20Sopenharmony_cistatic int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, 10038c2ecf20Sopenharmony_ci __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, 10048c2ecf20Sopenharmony_ci bool mode_from_sid, bool id_from_sid, int *aclflag) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci int rc = 0; 10078c2ecf20Sopenharmony_ci __u32 dacloffset; 10088c2ecf20Sopenharmony_ci __u32 ndacloffset; 10098c2ecf20Sopenharmony_ci __u32 sidsoffset; 10108c2ecf20Sopenharmony_ci struct cifs_sid *owner_sid_ptr, *group_sid_ptr; 10118c2ecf20Sopenharmony_ci struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr; 10128c2ecf20Sopenharmony_ci struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */ 10138c2ecf20Sopenharmony_ci struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */ 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (nmode != NO_CHANGE_64) { /* chmod */ 10168c2ecf20Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + 10178c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->osidoffset)); 10188c2ecf20Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pntsd + 10198c2ecf20Sopenharmony_ci le32_to_cpu(pntsd->gsidoffset)); 10208c2ecf20Sopenharmony_ci dacloffset = le32_to_cpu(pntsd->dacloffset); 10218c2ecf20Sopenharmony_ci dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset); 10228c2ecf20Sopenharmony_ci ndacloffset = sizeof(struct cifs_ntsd); 10238c2ecf20Sopenharmony_ci ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset); 10248c2ecf20Sopenharmony_ci ndacl_ptr->revision = dacl_ptr->revision; 10258c2ecf20Sopenharmony_ci ndacl_ptr->size = 0; 10268c2ecf20Sopenharmony_ci ndacl_ptr->num_aces = 0; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, 10298c2ecf20Sopenharmony_ci nmode, mode_from_sid); 10308c2ecf20Sopenharmony_ci sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size); 10318c2ecf20Sopenharmony_ci /* copy sec desc control portion & owner and group sids */ 10328c2ecf20Sopenharmony_ci copy_sec_desc(pntsd, pnntsd, sidsoffset); 10338c2ecf20Sopenharmony_ci *aclflag = CIFS_ACL_DACL; 10348c2ecf20Sopenharmony_ci } else { 10358c2ecf20Sopenharmony_ci memcpy(pnntsd, pntsd, secdesclen); 10368c2ecf20Sopenharmony_ci if (uid_valid(uid)) { /* chown */ 10378c2ecf20Sopenharmony_ci uid_t id; 10388c2ecf20Sopenharmony_ci owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + 10398c2ecf20Sopenharmony_ci le32_to_cpu(pnntsd->osidoffset)); 10408c2ecf20Sopenharmony_ci nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid), 10418c2ecf20Sopenharmony_ci GFP_KERNEL); 10428c2ecf20Sopenharmony_ci if (!nowner_sid_ptr) 10438c2ecf20Sopenharmony_ci return -ENOMEM; 10448c2ecf20Sopenharmony_ci id = from_kuid(&init_user_ns, uid); 10458c2ecf20Sopenharmony_ci if (id_from_sid) { 10468c2ecf20Sopenharmony_ci struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr; 10478c2ecf20Sopenharmony_ci /* Populate the user ownership fields S-1-5-88-1 */ 10488c2ecf20Sopenharmony_ci osid->Revision = 1; 10498c2ecf20Sopenharmony_ci osid->NumAuth = 3; 10508c2ecf20Sopenharmony_ci osid->Authority[5] = 5; 10518c2ecf20Sopenharmony_ci osid->SubAuthorities[0] = cpu_to_le32(88); 10528c2ecf20Sopenharmony_ci osid->SubAuthorities[1] = cpu_to_le32(1); 10538c2ecf20Sopenharmony_ci osid->SubAuthorities[2] = cpu_to_le32(id); 10548c2ecf20Sopenharmony_ci } else { /* lookup sid with upcall */ 10558c2ecf20Sopenharmony_ci rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); 10568c2ecf20Sopenharmony_ci if (rc) { 10578c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n", 10588c2ecf20Sopenharmony_ci __func__, rc, id); 10598c2ecf20Sopenharmony_ci kfree(nowner_sid_ptr); 10608c2ecf20Sopenharmony_ci return rc; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr); 10648c2ecf20Sopenharmony_ci kfree(nowner_sid_ptr); 10658c2ecf20Sopenharmony_ci *aclflag = CIFS_ACL_OWNER; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci if (gid_valid(gid)) { /* chgrp */ 10688c2ecf20Sopenharmony_ci gid_t id; 10698c2ecf20Sopenharmony_ci group_sid_ptr = (struct cifs_sid *)((char *)pnntsd + 10708c2ecf20Sopenharmony_ci le32_to_cpu(pnntsd->gsidoffset)); 10718c2ecf20Sopenharmony_ci ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid), 10728c2ecf20Sopenharmony_ci GFP_KERNEL); 10738c2ecf20Sopenharmony_ci if (!ngroup_sid_ptr) 10748c2ecf20Sopenharmony_ci return -ENOMEM; 10758c2ecf20Sopenharmony_ci id = from_kgid(&init_user_ns, gid); 10768c2ecf20Sopenharmony_ci if (id_from_sid) { 10778c2ecf20Sopenharmony_ci struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr; 10788c2ecf20Sopenharmony_ci /* Populate the group ownership fields S-1-5-88-2 */ 10798c2ecf20Sopenharmony_ci gsid->Revision = 1; 10808c2ecf20Sopenharmony_ci gsid->NumAuth = 3; 10818c2ecf20Sopenharmony_ci gsid->Authority[5] = 5; 10828c2ecf20Sopenharmony_ci gsid->SubAuthorities[0] = cpu_to_le32(88); 10838c2ecf20Sopenharmony_ci gsid->SubAuthorities[1] = cpu_to_le32(2); 10848c2ecf20Sopenharmony_ci gsid->SubAuthorities[2] = cpu_to_le32(id); 10858c2ecf20Sopenharmony_ci } else { /* lookup sid with upcall */ 10868c2ecf20Sopenharmony_ci rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); 10878c2ecf20Sopenharmony_ci if (rc) { 10888c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n", 10898c2ecf20Sopenharmony_ci __func__, rc, id); 10908c2ecf20Sopenharmony_ci kfree(ngroup_sid_ptr); 10918c2ecf20Sopenharmony_ci return rc; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr); 10958c2ecf20Sopenharmony_ci kfree(ngroup_sid_ptr); 10968c2ecf20Sopenharmony_ci *aclflag = CIFS_ACL_GROUP; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci return rc; 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistruct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, 11048c2ecf20Sopenharmony_ci const struct cifs_fid *cifsfid, u32 *pacllen) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 11078c2ecf20Sopenharmony_ci unsigned int xid; 11088c2ecf20Sopenharmony_ci int rc; 11098c2ecf20Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) 11128c2ecf20Sopenharmony_ci return ERR_CAST(tlink); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci xid = get_xid(); 11158c2ecf20Sopenharmony_ci rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd, 11168c2ecf20Sopenharmony_ci pacllen); 11178c2ecf20Sopenharmony_ci free_xid(xid); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen); 11228c2ecf20Sopenharmony_ci if (rc) 11238c2ecf20Sopenharmony_ci return ERR_PTR(rc); 11248c2ecf20Sopenharmony_ci return pntsd; 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, 11288c2ecf20Sopenharmony_ci const char *path, u32 *pacllen) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 11318c2ecf20Sopenharmony_ci int oplock = 0; 11328c2ecf20Sopenharmony_ci unsigned int xid; 11338c2ecf20Sopenharmony_ci int rc; 11348c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 11358c2ecf20Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 11368c2ecf20Sopenharmony_ci struct cifs_fid fid; 11378c2ecf20Sopenharmony_ci struct cifs_open_parms oparms; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) 11408c2ecf20Sopenharmony_ci return ERR_CAST(tlink); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci tcon = tlink_tcon(tlink); 11438c2ecf20Sopenharmony_ci xid = get_xid(); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci oparms.tcon = tcon; 11468c2ecf20Sopenharmony_ci oparms.cifs_sb = cifs_sb; 11478c2ecf20Sopenharmony_ci oparms.desired_access = READ_CONTROL; 11488c2ecf20Sopenharmony_ci oparms.create_options = cifs_create_options(cifs_sb, 0); 11498c2ecf20Sopenharmony_ci oparms.disposition = FILE_OPEN; 11508c2ecf20Sopenharmony_ci oparms.path = path; 11518c2ecf20Sopenharmony_ci oparms.fid = &fid; 11528c2ecf20Sopenharmony_ci oparms.reconnect = false; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci rc = CIFS_open(xid, &oparms, &oplock, NULL); 11558c2ecf20Sopenharmony_ci if (!rc) { 11568c2ecf20Sopenharmony_ci rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen); 11578c2ecf20Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 11618c2ecf20Sopenharmony_ci free_xid(xid); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen); 11648c2ecf20Sopenharmony_ci if (rc) 11658c2ecf20Sopenharmony_ci return ERR_PTR(rc); 11668c2ecf20Sopenharmony_ci return pntsd; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci/* Retrieve an ACL from the server */ 11708c2ecf20Sopenharmony_cistruct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, 11718c2ecf20Sopenharmony_ci struct inode *inode, const char *path, 11728c2ecf20Sopenharmony_ci u32 *pacllen) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 11758c2ecf20Sopenharmony_ci struct cifsFileInfo *open_file = NULL; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (inode) 11788c2ecf20Sopenharmony_ci open_file = find_readable_file(CIFS_I(inode), true); 11798c2ecf20Sopenharmony_ci if (!open_file) 11808c2ecf20Sopenharmony_ci return get_cifs_acl_by_path(cifs_sb, path, pacllen); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen); 11838c2ecf20Sopenharmony_ci cifsFileInfo_put(open_file); 11848c2ecf20Sopenharmony_ci return pntsd; 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci /* Set an ACL on the server */ 11888c2ecf20Sopenharmony_ciint set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen, 11898c2ecf20Sopenharmony_ci struct inode *inode, const char *path, int aclflag) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci int oplock = 0; 11928c2ecf20Sopenharmony_ci unsigned int xid; 11938c2ecf20Sopenharmony_ci int rc, access_flags; 11948c2ecf20Sopenharmony_ci struct cifs_tcon *tcon; 11958c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 11968c2ecf20Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 11978c2ecf20Sopenharmony_ci struct cifs_fid fid; 11988c2ecf20Sopenharmony_ci struct cifs_open_parms oparms; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) 12018c2ecf20Sopenharmony_ci return PTR_ERR(tlink); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci tcon = tlink_tcon(tlink); 12048c2ecf20Sopenharmony_ci xid = get_xid(); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP) 12078c2ecf20Sopenharmony_ci access_flags = WRITE_OWNER; 12088c2ecf20Sopenharmony_ci else 12098c2ecf20Sopenharmony_ci access_flags = WRITE_DAC; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci oparms.tcon = tcon; 12128c2ecf20Sopenharmony_ci oparms.cifs_sb = cifs_sb; 12138c2ecf20Sopenharmony_ci oparms.desired_access = access_flags; 12148c2ecf20Sopenharmony_ci oparms.create_options = cifs_create_options(cifs_sb, 0); 12158c2ecf20Sopenharmony_ci oparms.disposition = FILE_OPEN; 12168c2ecf20Sopenharmony_ci oparms.path = path; 12178c2ecf20Sopenharmony_ci oparms.fid = &fid; 12188c2ecf20Sopenharmony_ci oparms.reconnect = false; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci rc = CIFS_open(xid, &oparms, &oplock, NULL); 12218c2ecf20Sopenharmony_ci if (rc) { 12228c2ecf20Sopenharmony_ci cifs_dbg(VFS, "Unable to open file to set ACL\n"); 12238c2ecf20Sopenharmony_ci goto out; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag); 12278c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci CIFSSMBClose(xid, tcon, fid.netfid); 12308c2ecf20Sopenharmony_ciout: 12318c2ecf20Sopenharmony_ci free_xid(xid); 12328c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 12338c2ecf20Sopenharmony_ci return rc; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */ 12378c2ecf20Sopenharmony_ciint 12388c2ecf20Sopenharmony_cicifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, 12398c2ecf20Sopenharmony_ci struct inode *inode, bool mode_from_special_sid, 12408c2ecf20Sopenharmony_ci const char *path, const struct cifs_fid *pfid) 12418c2ecf20Sopenharmony_ci{ 12428c2ecf20Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; 12438c2ecf20Sopenharmony_ci u32 acllen = 0; 12448c2ecf20Sopenharmony_ci int rc = 0; 12458c2ecf20Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 12468c2ecf20Sopenharmony_ci struct smb_version_operations *ops; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "converting ACL to mode for %s\n", path); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) 12518c2ecf20Sopenharmony_ci return PTR_ERR(tlink); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci ops = tlink_tcon(tlink)->ses->server->ops; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (pfid && (ops->get_acl_by_fid)) 12568c2ecf20Sopenharmony_ci pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen); 12578c2ecf20Sopenharmony_ci else if (ops->get_acl) 12588c2ecf20Sopenharmony_ci pntsd = ops->get_acl(cifs_sb, inode, path, &acllen); 12598c2ecf20Sopenharmony_ci else { 12608c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 12618c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ 12648c2ecf20Sopenharmony_ci if (IS_ERR(pntsd)) { 12658c2ecf20Sopenharmony_ci rc = PTR_ERR(pntsd); 12668c2ecf20Sopenharmony_ci cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); 12678c2ecf20Sopenharmony_ci } else if (mode_from_special_sid) { 12688c2ecf20Sopenharmony_ci rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true); 12698c2ecf20Sopenharmony_ci kfree(pntsd); 12708c2ecf20Sopenharmony_ci } else { 12718c2ecf20Sopenharmony_ci /* get approximated mode from ACL */ 12728c2ecf20Sopenharmony_ci rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false); 12738c2ecf20Sopenharmony_ci kfree(pntsd); 12748c2ecf20Sopenharmony_ci if (rc) 12758c2ecf20Sopenharmony_ci cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc); 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci return rc; 12818c2ecf20Sopenharmony_ci} 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci/* Convert mode bits to an ACL so we can update the ACL on the server */ 12848c2ecf20Sopenharmony_ciint 12858c2ecf20Sopenharmony_ciid_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, 12868c2ecf20Sopenharmony_ci kuid_t uid, kgid_t gid) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci int rc = 0; 12898c2ecf20Sopenharmony_ci int aclflag = CIFS_ACL_DACL; /* default flag to set */ 12908c2ecf20Sopenharmony_ci __u32 secdesclen = 0; 12918c2ecf20Sopenharmony_ci struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */ 12928c2ecf20Sopenharmony_ci struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */ 12938c2ecf20Sopenharmony_ci struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); 12948c2ecf20Sopenharmony_ci struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); 12958c2ecf20Sopenharmony_ci struct smb_version_operations *ops; 12968c2ecf20Sopenharmony_ci bool mode_from_sid, id_from_sid; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci if (IS_ERR(tlink)) 12998c2ecf20Sopenharmony_ci return PTR_ERR(tlink); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci ops = tlink_tcon(tlink)->ses->server->ops; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "set ACL from mode for %s\n", path); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* Get the security descriptor */ 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if (ops->get_acl == NULL) { 13088c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 13098c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen); 13138c2ecf20Sopenharmony_ci if (IS_ERR(pntsd)) { 13148c2ecf20Sopenharmony_ci rc = PTR_ERR(pntsd); 13158c2ecf20Sopenharmony_ci cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc); 13168c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 13178c2ecf20Sopenharmony_ci return rc; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci /* 13218c2ecf20Sopenharmony_ci * Add three ACEs for owner, group, everyone getting rid of other ACEs 13228c2ecf20Sopenharmony_ci * as chmod disables ACEs and set the security descriptor. Allocate 13238c2ecf20Sopenharmony_ci * memory for the smb header, set security descriptor request security 13248c2ecf20Sopenharmony_ci * descriptor parameters, and secuirty descriptor itself 13258c2ecf20Sopenharmony_ci */ 13268c2ecf20Sopenharmony_ci secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN); 13278c2ecf20Sopenharmony_ci pnntsd = kmalloc(secdesclen, GFP_KERNEL); 13288c2ecf20Sopenharmony_ci if (!pnntsd) { 13298c2ecf20Sopenharmony_ci kfree(pntsd); 13308c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 13318c2ecf20Sopenharmony_ci return -ENOMEM; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) 13358c2ecf20Sopenharmony_ci mode_from_sid = true; 13368c2ecf20Sopenharmony_ci else 13378c2ecf20Sopenharmony_ci mode_from_sid = false; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) 13408c2ecf20Sopenharmony_ci id_from_sid = true; 13418c2ecf20Sopenharmony_ci else 13428c2ecf20Sopenharmony_ci id_from_sid = false; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid, 13458c2ecf20Sopenharmony_ci mode_from_sid, id_from_sid, &aclflag); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (ops->set_acl == NULL) 13508c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (!rc) { 13538c2ecf20Sopenharmony_ci /* Set the security descriptor */ 13548c2ecf20Sopenharmony_ci rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag); 13558c2ecf20Sopenharmony_ci cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci cifs_put_tlink(tlink); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci kfree(pnntsd); 13608c2ecf20Sopenharmony_ci kfree(pntsd); 13618c2ecf20Sopenharmony_ci return rc; 13628c2ecf20Sopenharmony_ci} 1363