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