blob: bbc439710c6ca4e1a0f790d60411db20923f519c [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
Steve French8b1327f2008-03-14 22:37:16 +00004 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050026#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
Steve French65874002007-09-25 19:53:44 +000030#include "cifspdu.h"
31#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000032#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000033#include "cifsproto.h"
34#include "cifs_debug.h"
Ronnie Sahlberg8401e932020-12-12 13:40:50 -060035#include "fs_context.h"
Steve French65874002007-09-25 19:53:44 +000036
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060037/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000038static const struct cifs_sid sid_everyone = {
39 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060040/* security id for Authenticated Users system group */
41static const struct cifs_sid sid_authusers = {
Fabian Frederickbc09d142014-12-10 15:41:15 -080042 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000043
Steve French3514de32016-10-13 19:06:23 -050044/* S-1-22-1 Unmapped Unix users */
45static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
46 {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
47
48/* S-1-22-2 Unmapped Unix groups */
49static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
50 {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
51
52/*
Alexander A. Klimovcba22b12020-06-27 12:31:25 +020053 * See https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve French3514de32016-10-13 19:06:23 -050054 */
55
56/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
57
58/* S-1-5-88-1 Unix uid */
59static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
60 {cpu_to_le32(88),
61 cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
62
63/* S-1-5-88-2 Unix gid */
64static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
65 {cpu_to_le32(88),
66 cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
67
68/* S-1-5-88-3 Unix mode */
69static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
70 {cpu_to_le32(88),
71 cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
72
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050073static const struct cred *root_cred;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050074
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050075static int
David Howellscf7f6012012-09-13 13:06:29 +010076cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050077{
78 char *payload;
79
Jeff Layton41a9f1f2012-12-03 06:05:29 -050080 /*
81 * If the payload is less than or equal to the size of a pointer, then
82 * an allocation here is wasteful. Just copy the data directly to the
83 * payload.value union member instead.
84 *
85 * With this however, you must check the datalen before trying to
86 * dereference payload.data!
87 */
Jeff Layton1f630682012-12-03 06:05:31 -050088 if (prep->datalen <= sizeof(key->payload)) {
David Howells146aa8b2015-10-21 14:04:48 +010089 key->payload.data[0] = NULL;
90 memcpy(&key->payload, prep->data, prep->datalen);
91 } else {
92 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
93 if (!payload)
94 return -ENOMEM;
95 key->payload.data[0] = payload;
Jeff Layton41a9f1f2012-12-03 06:05:29 -050096 }
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050097
David Howellscf7f6012012-09-13 13:06:29 +010098 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050099 return 0;
100}
101
102static inline void
103cifs_idmap_key_destroy(struct key *key)
104{
Jeff Layton1f630682012-12-03 06:05:31 -0500105 if (key->datalen > sizeof(key->payload))
David Howells146aa8b2015-10-21 14:04:48 +0100106 kfree(key->payload.data[0]);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500107}
108
Jeff Laytonb1a6dc22012-11-25 08:00:38 -0500109static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -0500110 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500111 .instantiate = cifs_idmap_key_instantiate,
112 .destroy = cifs_idmap_key_destroy,
113 .describe = user_describe,
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500114};
115
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500116static char *
117sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500118{
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500119 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500120 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500121 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -0500122 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500123
124 /* 3 bytes for prefix */
125 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
126 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
127 GFP_KERNEL);
128 if (!sidstr)
129 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500130
131 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500132 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
133 sidptr->revision);
134 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500135
Jeff Layton193cdd82012-12-10 06:10:44 -0500136 /* The authority field is a single 48-bit number */
137 id_auth_val = (unsigned long long)sidptr->authority[5];
138 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
139 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
140 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
141 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
142 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
143
144 /*
145 * MS-DTYP states that if the authority is >= 2^32, then it should be
146 * expressed as a hex value.
147 */
148 if (id_auth_val <= UINT_MAX)
149 len = sprintf(strptr, "-%llu", id_auth_val);
150 else
151 len = sprintf(strptr, "-0x%llx", id_auth_val);
152
153 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500154
155 for (i = 0; i < sidptr->num_subauth; ++i) {
156 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500157 len = sprintf(strptr, "-%u", saval);
158 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500159 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500160
161 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500162}
163
Jeff Layton436bb432012-11-25 08:00:36 -0500164/*
165 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
166 * the same returns zero, if they do not match returns non-zero.
167 */
168static int
169compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
170{
171 int i;
172 int num_subauth, num_sat, num_saw;
173
174 if ((!ctsid) || (!cwsid))
175 return 1;
176
177 /* compare the revision */
178 if (ctsid->revision != cwsid->revision) {
179 if (ctsid->revision > cwsid->revision)
180 return 1;
181 else
182 return -1;
183 }
184
185 /* compare all of the six auth values */
186 for (i = 0; i < NUM_AUTHS; ++i) {
187 if (ctsid->authority[i] != cwsid->authority[i]) {
188 if (ctsid->authority[i] > cwsid->authority[i])
189 return 1;
190 else
191 return -1;
192 }
193 }
194
195 /* compare all of the subauth values if any */
196 num_sat = ctsid->num_subauth;
197 num_saw = cwsid->num_subauth;
198 num_subauth = num_sat < num_saw ? num_sat : num_saw;
199 if (num_subauth) {
200 for (i = 0; i < num_subauth; ++i) {
201 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
202 if (le32_to_cpu(ctsid->sub_auth[i]) >
203 le32_to_cpu(cwsid->sub_auth[i]))
204 return 1;
205 else
206 return -1;
207 }
208 }
209 }
210
211 return 0; /* sids compare/match */
212}
213
Steve French3514de32016-10-13 19:06:23 -0500214static bool
215is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
216{
217 int i;
218 int num_subauth;
219 const struct cifs_sid *pwell_known_sid;
220
221 if (!psid || (puid == NULL))
222 return false;
223
224 num_subauth = psid->num_subauth;
225
226 /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
227 if (num_subauth == 2) {
228 if (is_group)
229 pwell_known_sid = &sid_unix_groups;
230 else
231 pwell_known_sid = &sid_unix_users;
232 } else if (num_subauth == 3) {
233 if (is_group)
234 pwell_known_sid = &sid_unix_NFS_groups;
235 else
236 pwell_known_sid = &sid_unix_NFS_users;
237 } else
238 return false;
239
240 /* compare the revision */
241 if (psid->revision != pwell_known_sid->revision)
242 return false;
243
244 /* compare all of the six auth values */
245 for (i = 0; i < NUM_AUTHS; ++i) {
246 if (psid->authority[i] != pwell_known_sid->authority[i]) {
247 cifs_dbg(FYI, "auth %d did not match\n", i);
248 return false;
249 }
250 }
251
252 if (num_subauth == 2) {
253 if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
254 return false;
255
256 *puid = le32_to_cpu(psid->sub_auth[1]);
257 } else /* 3 subauths, ie Windows/Mac style */ {
258 *puid = le32_to_cpu(psid->sub_auth[0]);
259 if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
260 (psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
261 return false;
262
263 *puid = le32_to_cpu(psid->sub_auth[2]);
264 }
265
266 cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
267 return true; /* well known sid found, uid returned */
268}
269
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800270static __u16
Jeff Layton36960e42012-11-03 09:37:28 -0400271cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
272{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500273 int i;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800274 __u16 size = 1 + 1 + 6;
Jeff Layton36f87ee2012-11-25 08:00:37 -0500275
276 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500277 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500278 for (i = 0; i < NUM_AUTHS; ++i)
279 dst->authority[i] = src->authority[i];
280 for (i = 0; i < dst->num_subauth; ++i)
281 dst->sub_auth[i] = src->sub_auth[i];
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800282 size += (dst->num_subauth * 4);
283
284 return size;
Jeff Layton36960e42012-11-03 09:37:28 -0400285}
286
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500287static int
288id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500289{
290 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500291 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500292 struct cifs_sid *ksid;
293 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500294 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500295 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500296
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500297 rc = snprintf(desc, sizeof(desc), "%ci:%u",
298 sidtype == SIDOWNER ? 'o' : 'g', cid);
299 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500300 return -EINVAL;
301
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500302 rc = 0;
303 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700304 sidkey = request_key(&cifs_idmap_key_type, desc, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500305 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500306 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500307 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
308 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500309 goto out_revert_creds;
310 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
311 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500312 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
313 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500314 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500315 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500316
Jeff Layton1f630682012-12-03 06:05:31 -0500317 /*
318 * A sid is usually too large to be embedded in payload.value, but if
319 * there are no subauthorities and the host has 8-byte pointers, then
320 * it could be.
321 */
322 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
David Howells146aa8b2015-10-21 14:04:48 +0100323 (struct cifs_sid *)&sidkey->payload :
324 (struct cifs_sid *)sidkey->payload.data[0];
Jeff Layton1f630682012-12-03 06:05:31 -0500325
Jeff Layton2ae03022012-12-03 06:05:30 -0500326 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
327 if (ksid_size > sidkey->datalen) {
328 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500329 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
330 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500331 goto invalidate_key;
332 }
Jeff Layton1f630682012-12-03 06:05:31 -0500333
Jeff Layton2ae03022012-12-03 06:05:30 -0500334 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500335out_key_put:
336 key_put(sidkey);
337out_revert_creds:
338 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500339 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500340
341invalidate_key:
342 key_invalidate(sidkey);
343 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500344}
345
Steve French99344302020-10-20 02:02:02 -0500346int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500347sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
348 struct cifs_fattr *fattr, uint sidtype)
349{
Qiujun Huangf2d67932020-03-04 15:42:51 +0800350 int rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500351 struct key *sidkey;
352 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500353 const struct cred *saved_cred;
Ronnie Sahlberg8401e932020-12-12 13:40:50 -0600354 kuid_t fuid = cifs_sb->ctx->linux_uid;
355 kgid_t fgid = cifs_sb->ctx->linux_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500356
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500357 /*
358 * If we have too many subauthorities, then something is really wrong.
359 * Just return an error.
360 */
361 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500362 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
363 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500364 return -EIO;
365 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500366
Steve French99344302020-10-20 02:02:02 -0500367 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
368 (cifs_sb_master_tcon(cifs_sb)->posix_extensions)) {
Steve French3514de32016-10-13 19:06:23 -0500369 uint32_t unix_id;
370 bool is_group;
371
372 if (sidtype != SIDOWNER)
373 is_group = true;
374 else
375 is_group = false;
376
377 if (is_well_known_sid(psid, &unix_id, is_group) == false)
378 goto try_upcall_to_get_id;
379
380 if (is_group) {
381 kgid_t gid;
382 gid_t id;
383
384 id = (gid_t)unix_id;
385 gid = make_kgid(&init_user_ns, id);
386 if (gid_valid(gid)) {
387 fgid = gid;
388 goto got_valid_id;
389 }
390 } else {
391 kuid_t uid;
392 uid_t id;
393
394 id = (uid_t)unix_id;
395 uid = make_kuid(&init_user_ns, id);
396 if (uid_valid(uid)) {
397 fuid = uid;
398 goto got_valid_id;
399 }
400 }
401 /* If unable to find uid/gid easily from SID try via upcall */
402 }
403
404try_upcall_to_get_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500405 sidstr = sid_to_key_str(psid, sidtype);
406 if (!sidstr)
407 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500408
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500409 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700410 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500411 if (IS_ERR(sidkey)) {
412 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500413 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
414 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500415 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500416 }
417
418 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500419 * FIXME: Here we assume that uid_t and gid_t are same size. It's
420 * probably a safe assumption but might be better to check based on
421 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500422 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800423 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500424 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500425 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500426 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
427 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500428 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500429 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500430 }
431
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800432 if (sidtype == SIDOWNER) {
433 kuid_t uid;
434 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100435 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800436 uid = make_kuid(&init_user_ns, id);
437 if (uid_valid(uid))
438 fuid = uid;
439 } else {
440 kgid_t gid;
441 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100442 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800443 gid = make_kgid(&init_user_ns, id);
444 if (gid_valid(gid))
445 fgid = gid;
446 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500447
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500448out_key_put:
449 key_put(sidkey);
450out_revert_creds:
451 revert_creds(saved_cred);
452 kfree(sidstr);
453
454 /*
455 * Note that we return 0 here unconditionally. If the mapping
Ronnie Sahlberg8401e932020-12-12 13:40:50 -0600456 * fails then we just fall back to using the ctx->linux_uid/linux_gid.
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500457 */
Steve French3514de32016-10-13 19:06:23 -0500458got_valid_id:
Qiujun Huangf2d67932020-03-04 15:42:51 +0800459 rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500460 if (sidtype == SIDOWNER)
461 fattr->cf_uid = fuid;
462 else
463 fattr->cf_gid = fgid;
Qiujun Huangf2d67932020-03-04 15:42:51 +0800464 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500465}
466
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500467int
468init_cifs_idmap(void)
469{
470 struct cred *cred;
471 struct key *keyring;
472 int ret;
473
Joe Perchesf96637b2013-05-04 22:12:25 -0500474 cifs_dbg(FYI, "Registering the %s key type\n",
475 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500476
477 /* create an override credential set with a special thread keyring in
478 * which requests are cached
479 *
480 * this is used to prevent malicious redirections from being installed
481 * with add_key().
482 */
483 cred = prepare_kernel_cred(NULL);
484 if (!cred)
485 return -ENOMEM;
486
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800487 keyring = keyring_alloc(".cifs_idmap",
488 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
Linus Torvalds028db3e2019-07-10 18:43:43 -0700489 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
490 KEY_USR_VIEW | KEY_USR_READ,
David Howells5ac7eac2016-04-06 16:14:24 +0100491 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500492 if (IS_ERR(keyring)) {
493 ret = PTR_ERR(keyring);
494 goto failed_put_cred;
495 }
496
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500497 ret = register_key_type(&cifs_idmap_key_type);
498 if (ret < 0)
499 goto failed_put_key;
500
501 /* instruct request_key() to use this special keyring as a cache for
502 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000503 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500504 cred->thread_keyring = keyring;
505 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
506 root_cred = cred;
507
Joe Perchesf96637b2013-05-04 22:12:25 -0500508 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500509 return 0;
510
511failed_put_key:
512 key_put(keyring);
513failed_put_cred:
514 put_cred(cred);
515 return ret;
516}
517
518void
519exit_cifs_idmap(void)
520{
521 key_revoke(root_cred->thread_keyring);
522 unregister_key_type(&cifs_idmap_key_type);
523 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500524 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500525}
526
Steve French97837582007-12-31 07:47:21 +0000527/* copy ntsd, owner sid, and group sid from a security descriptor to another */
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000528static __u32 copy_sec_desc(const struct cifs_ntsd *pntsd,
529 struct cifs_ntsd *pnntsd,
530 __u32 sidsoffset,
531 struct cifs_sid *pownersid,
532 struct cifs_sid *pgrpsid)
Steve French97837582007-12-31 07:47:21 +0000533{
Steve French97837582007-12-31 07:47:21 +0000534 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
535 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
536
537 /* copy security descriptor control portion */
538 pnntsd->revision = pntsd->revision;
539 pnntsd->type = pntsd->type;
540 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
541 pnntsd->sacloffset = 0;
542 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
543 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
544
545 /* copy owner sid */
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000546 if (pownersid)
547 owner_sid_ptr = pownersid;
548 else
549 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000550 le32_to_cpu(pntsd->osidoffset));
551 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400552 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000553
554 /* copy group sid */
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000555 if (pgrpsid)
556 group_sid_ptr = pgrpsid;
557 else
558 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000559 le32_to_cpu(pntsd->gsidoffset));
560 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
561 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400562 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000563
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000564 return sidsoffset + (2 * sizeof(struct cifs_sid));
Steve French97837582007-12-31 07:47:21 +0000565}
566
567
Steve French630f3f0c2007-10-25 21:17:17 +0000568/*
569 change posix mode to reflect permissions
570 pmode is the existing mode (we only want to overwrite part of this
571 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
572*/
Al Viro9b5e6852007-12-05 08:24:38 +0000573static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Shyam Prasad N0f220532020-08-17 03:23:12 -0700574 umode_t *pdenied, umode_t mask)
Steve French4879b442007-10-19 21:57:39 +0000575{
Al Viro9b5e6852007-12-05 08:24:38 +0000576 __u32 flags = le32_to_cpu(ace_flags);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700577 /*
578 * Do not assume "preferred" or "canonical" order.
579 * The first DENY or ALLOW ACE which matches perfectly is
580 * the permission to be used. Once allowed or denied, same
581 * permission in later ACEs do not matter.
582 */
Steve French15b03952007-11-08 17:57:40 +0000583
Shyam Prasad N0f220532020-08-17 03:23:12 -0700584 /* If not already allowed, deny these bits */
Steve French15b03952007-11-08 17:57:40 +0000585 if (type == ACCESS_DENIED) {
Shyam Prasad N0f220532020-08-17 03:23:12 -0700586 if (flags & GENERIC_ALL &&
587 !(*pmode & mask & 0777))
588 *pdenied |= mask & 0777;
Steve Frenchad7a2922008-02-07 23:25:02 +0000589
Shyam Prasad N0f220532020-08-17 03:23:12 -0700590 if (((flags & GENERIC_WRITE) ||
591 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) &&
592 !(*pmode & mask & 0222))
593 *pdenied |= mask & 0222;
594
595 if (((flags & GENERIC_READ) ||
596 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) &&
597 !(*pmode & mask & 0444))
598 *pdenied |= mask & 0444;
599
600 if (((flags & GENERIC_EXECUTE) ||
601 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) &&
602 !(*pmode & mask & 0111))
603 *pdenied |= mask & 0111;
604
Steve French15b03952007-11-08 17:57:40 +0000605 return;
606 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500607 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000608 return;
609 }
610 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000611
Shyam Prasad N0f220532020-08-17 03:23:12 -0700612 if ((flags & GENERIC_ALL) &&
613 !(*pdenied & mask & 0777)) {
614 *pmode |= mask & 0777;
Joe Perchesf96637b2013-05-04 22:12:25 -0500615 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000616 return;
617 }
Shyam Prasad N0f220532020-08-17 03:23:12 -0700618
619 if (((flags & GENERIC_WRITE) ||
620 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) &&
621 !(*pdenied & mask & 0222))
622 *pmode |= mask & 0222;
623
624 if (((flags & GENERIC_READ) ||
625 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) &&
626 !(*pdenied & mask & 0444))
627 *pmode |= mask & 0444;
628
629 if (((flags & GENERIC_EXECUTE) ||
630 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) &&
631 !(*pdenied & mask & 0111))
632 *pmode |= mask & 0111;
Steve Frenchd61e5802007-10-26 04:32:43 +0000633
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800634 /* If DELETE_CHILD is set only on an owner ACE, set sticky bit */
635 if (flags & FILE_DELETE_CHILD) {
636 if (mask == ACL_OWNER_MASK) {
637 if (!(*pdenied & 01000))
638 *pmode |= 01000;
639 } else if (!(*pdenied & 01000)) {
640 *pmode &= ~01000;
641 *pdenied |= 01000;
642 }
643 }
644
Frank Sorensonf52aa792020-02-12 15:31:48 -0600645 cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000646 return;
647}
648
Steve Frenchce06c9f2007-11-08 21:12:01 +0000649/*
650 Generate access flags to reflect permissions mode is the existing mode.
651 This function is called for every ACE in the DACL whose SID matches
652 with either owner or group or everyone.
653*/
654
655static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
656 __u32 *pace_flags)
657{
658 /* reset access mask */
659 *pace_flags = 0x0;
660
661 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
662 mode &= bits_to_use;
663
664 /* check for R/W/X UGO since we do not know whose flags
665 is this but we have cleared all the bits sans RWX for
666 either user or group or other as per bits_to_use */
667 if (mode & S_IRUGO)
668 *pace_flags |= SET_FILE_READ_RIGHTS;
669 if (mode & S_IWUGO)
670 *pace_flags |= SET_FILE_WRITE_RIGHTS;
671 if (mode & S_IXUGO)
672 *pace_flags |= SET_FILE_EXEC_RIGHTS;
673
Frank Sorensonf52aa792020-02-12 15:31:48 -0600674 cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n",
Joe Perchesf96637b2013-05-04 22:12:25 -0500675 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000676 return;
677}
678
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000679static __u16 cifs_copy_ace(struct cifs_ace *dst, struct cifs_ace *src, struct cifs_sid *psid)
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800680{
681 __u16 size = 1 + 1 + 2 + 4;
682
683 dst->type = src->type;
684 dst->flags = src->flags;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800685 dst->access_req = src->access_req;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000686
687 /* Check if there's a replacement sid specified */
688 if (psid)
689 size += cifs_copy_sid(&dst->sid, psid);
690 else
691 size += cifs_copy_sid(&dst->sid, &src->sid);
692
693 dst->size = cpu_to_le16(size);
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800694
695 return size;
696}
697
Al Viro2b210ad2008-03-29 03:09:18 +0000698static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800699 const struct cifs_sid *psid, __u64 nmode,
700 umode_t bits, __u8 access_type,
701 bool allow_delete_child)
Steve French97837582007-12-31 07:47:21 +0000702{
703 int i;
704 __u16 size = 0;
705 __u32 access_req = 0;
706
Shyam Prasad N0f220532020-08-17 03:23:12 -0700707 pntace->type = access_type;
Steve French97837582007-12-31 07:47:21 +0000708 pntace->flags = 0x0;
709 mode_to_access_flags(nmode, bits, &access_req);
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800710
711 if (access_type == ACCESS_ALLOWED && allow_delete_child)
712 access_req |= FILE_DELETE_CHILD;
713
Shyam Prasad N0f220532020-08-17 03:23:12 -0700714 if (access_type == ACCESS_ALLOWED && !access_req)
Steve French97837582007-12-31 07:47:21 +0000715 access_req = SET_MINIMUM_RIGHTS;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700716 else if (access_type == ACCESS_DENIED)
717 access_req &= ~SET_MINIMUM_RIGHTS;
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800718
Steve French97837582007-12-31 07:47:21 +0000719 pntace->access_req = cpu_to_le32(access_req);
720
721 pntace->sid.revision = psid->revision;
722 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500723 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000724 pntace->sid.authority[i] = psid->authority[i];
725 for (i = 0; i < psid->num_subauth; i++)
726 pntace->sid.sub_auth[i] = psid->sub_auth[i];
727
728 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
729 pntace->size = cpu_to_le16(size);
730
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000731 return size;
Steve French97837582007-12-31 07:47:21 +0000732}
733
Steve French297647c2007-10-12 04:11:59 +0000734
Steve French953f8682007-10-31 04:54:42 +0000735#ifdef CONFIG_CIFS_DEBUG2
736static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000737{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000738 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000739
740 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000741
Steve French44093ca2007-10-23 21:22:55 +0000742 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500743 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000744 return;
745 }
746
747 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500748 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000749 return;
Steve French44093ca2007-10-23 21:22:55 +0000750 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000751
Steve French44093ca2007-10-23 21:22:55 +0000752 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000753 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000754 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500755 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
756 pace->sid.revision, pace->sid.num_subauth, pace->type,
757 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000758 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500759 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
760 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000761 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000762
Steve Frenchd12fd122007-10-03 19:43:19 +0000763 /* BB add length check to make sure that we do not have huge
764 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000765 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000766
Steve Frenchd12fd122007-10-03 19:43:19 +0000767 return;
768}
Steve French953f8682007-10-31 04:54:42 +0000769#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000770
Steve Frencha750e772007-10-17 22:50:39 +0000771static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000772 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000773 struct cifs_fattr *fattr, bool mode_from_special_sid)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000774{
775 int i;
776 int num_aces = 0;
777 int acl_size;
778 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000779 struct cifs_ace **ppace;
780
781 /* BB need to add parm so we can store the SID BB */
782
Steve French2b834572007-11-25 10:01:00 +0000783 if (!pdacl) {
784 /* no DACL in the security descriptor, set
785 all the permissions for user/group/other */
Shyam Prasad N0f220532020-08-17 03:23:12 -0700786 fattr->cf_mode |= 0777;
Steve French2b834572007-11-25 10:01:00 +0000787 return;
788 }
789
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000790 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000791 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500792 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000793 return;
794 }
795
Joe Perchesf96637b2013-05-04 22:12:25 -0500796 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
797 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
798 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000799
Steve French7505e052007-11-01 18:03:01 +0000800 /* reset rwx permissions for user/group/other.
801 Also, if num_aces is 0 i.e. DACL has no ACEs,
802 user/group/other have no permissions */
Shyam Prasad N0f220532020-08-17 03:23:12 -0700803 fattr->cf_mode &= ~(0777);
Steve French7505e052007-11-01 18:03:01 +0000804
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000805 acl_base = (char *)pdacl;
806 acl_size = sizeof(struct cifs_acl);
807
Steve Frenchadbc0352007-10-17 02:12:46 +0000808 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500809 if (num_aces > 0) {
Shyam Prasad N0f220532020-08-17 03:23:12 -0700810 umode_t denied_mode = 0;
Steve French15b03952007-11-08 17:57:40 +0000811
Dan Carpenter72501702012-01-11 10:46:27 +0300812 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
813 return;
Kees Cook6da2ec52018-06-12 13:55:00 -0700814 ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
815 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500816 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300817 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000818
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000819 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000820 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000821#ifdef CONFIG_CIFS_DEBUG2
822 dump_ace(ppace[i], end_of_acl);
823#endif
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000824 if (mode_from_special_sid &&
825 (compare_sids(&(ppace[i]->sid),
826 &sid_unix_NFS_mode) == 0)) {
827 /*
828 * Full permissions are:
829 * 07777 = S_ISUID | S_ISGID | S_ISVTX |
830 * S_IRWXU | S_IRWXG | S_IRWXO
831 */
832 fattr->cf_mode &= ~07777;
833 fattr->cf_mode |=
834 le32_to_cpu(ppace[i]->sid.sub_auth[2]);
835 break;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700836 } else {
837 if (compare_sids(&(ppace[i]->sid), pownersid) == 0) {
838 access_flags_to_mode(ppace[i]->access_req,
839 ppace[i]->type,
840 &fattr->cf_mode,
841 &denied_mode,
842 ACL_OWNER_MASK);
843 } else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) {
844 access_flags_to_mode(ppace[i]->access_req,
845 ppace[i]->type,
846 &fattr->cf_mode,
847 &denied_mode,
848 ACL_GROUP_MASK);
849 } else if ((compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) ||
850 (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)) {
851 access_flags_to_mode(ppace[i]->access_req,
852 ppace[i]->type,
853 &fattr->cf_mode,
854 &denied_mode,
855 ACL_EVERYONE_MASK);
856 }
857 }
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600858
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000859
Steve French44093ca2007-10-23 21:22:55 +0000860/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000861 (void *)ppace[i],
862 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000863
Steve French44093ca2007-10-23 21:22:55 +0000864 acl_base = (char *)ppace[i];
865 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000866 }
867
868 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000869 }
870
871 return;
872}
873
Steve French643fbce2020-01-16 19:55:33 -0600874unsigned int setup_authusers_ACE(struct cifs_ace *pntace)
875{
876 int i;
877 unsigned int ace_size = 20;
878
879 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
880 pntace->flags = 0x0;
881 pntace->access_req = cpu_to_le32(GENERIC_ALL);
882 pntace->sid.num_subauth = 1;
883 pntace->sid.revision = 1;
884 for (i = 0; i < NUM_AUTHS; i++)
885 pntace->sid.authority[i] = sid_authusers.authority[i];
886
887 pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0];
888
889 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
890 pntace->size = cpu_to_le16(ace_size);
891 return ace_size;
892}
893
Steve Frenchfdef6652019-12-06 02:02:38 -0600894/*
895 * Fill in the special SID based on the mode. See
Alexander A. Klimovcba22b12020-06-27 12:31:25 +0200896 * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve Frenchfdef6652019-12-06 02:02:38 -0600897 */
898unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
899{
900 int i;
901 unsigned int ace_size = 28;
902
903 pntace->type = ACCESS_DENIED_ACE_TYPE;
904 pntace->flags = 0x0;
905 pntace->access_req = 0;
906 pntace->sid.num_subauth = 3;
907 pntace->sid.revision = 1;
908 for (i = 0; i < NUM_AUTHS; i++)
909 pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
910
911 pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
912 pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
913 pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
914
915 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
916 pntace->size = cpu_to_le16(ace_size);
917 return ace_size;
918}
Steve Frenchbcb02032007-09-25 16:17:24 +0000919
Steve French975221e2020-06-12 09:25:21 -0500920unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace)
921{
922 int i;
923 unsigned int ace_size = 28;
924
925 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
926 pntace->flags = 0x0;
927 pntace->access_req = cpu_to_le32(GENERIC_ALL);
928 pntace->sid.num_subauth = 3;
929 pntace->sid.revision = 1;
930 for (i = 0; i < NUM_AUTHS; i++)
931 pntace->sid.authority[i] = sid_unix_NFS_users.authority[i];
932
933 pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0];
934 pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1];
935 pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val);
936
937 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
938 pntace->size = cpu_to_le16(ace_size);
939 return ace_size;
940}
941
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800942static void populate_new_aces(char *nacl_base,
943 struct cifs_sid *pownersid,
944 struct cifs_sid *pgrpsid,
945 __u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
946 bool modefromsid)
Steve French97837582007-12-31 07:47:21 +0000947{
Shyam Prasad N0f220532020-08-17 03:23:12 -0700948 __u64 nmode;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800949 u32 num_aces = 0;
950 u16 nsize = 0;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700951 __u64 user_mode;
952 __u64 group_mode;
953 __u64 other_mode;
954 __u64 deny_user_mode = 0;
955 __u64 deny_group_mode = 0;
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800956 bool sticky_set = false;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800957 struct cifs_ace *pnntace = NULL;
Steve French97837582007-12-31 07:47:21 +0000958
Shyam Prasad N0f220532020-08-17 03:23:12 -0700959 nmode = *pnmode;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800960 num_aces = *pnum_aces;
961 nsize = *pnsize;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700962
Steve French22442172019-07-19 08:15:55 +0000963 if (modefromsid) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800964 pnntace = (struct cifs_ace *) (nacl_base + nsize);
965 nsize += setup_special_mode_ACE(pnntace, nmode);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200966 num_aces++;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700967 goto set_size;
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200968 }
Steve French22442172019-07-19 08:15:55 +0000969
Shyam Prasad N0f220532020-08-17 03:23:12 -0700970 /*
971 * We'll try to keep the mode as requested by the user.
972 * But in cases where we cannot meaningfully convert that
973 * into ACL, return back the updated mode, so that it is
974 * updated in the inode.
975 */
976
977 if (!memcmp(pownersid, pgrpsid, sizeof(struct cifs_sid))) {
978 /*
979 * Case when owner and group SIDs are the same.
980 * Set the more restrictive of the two modes.
981 */
982 user_mode = nmode & (nmode << 3) & 0700;
983 group_mode = nmode & (nmode >> 3) & 0070;
984 } else {
985 user_mode = nmode & 0700;
986 group_mode = nmode & 0070;
987 }
988
989 other_mode = nmode & 0007;
990
991 /* We need DENY ACE when the perm is more restrictive than the next sets. */
992 deny_user_mode = ~(user_mode) & ((group_mode << 3) | (other_mode << 6)) & 0700;
993 deny_group_mode = ~(group_mode) & (other_mode << 3) & 0070;
994
995 *pnmode = user_mode | group_mode | other_mode | (nmode & ~0777);
996
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800997 /* This tells if we should allow delete child for group and everyone. */
998 if (nmode & 01000)
999 sticky_set = true;
1000
Shyam Prasad N0f220532020-08-17 03:23:12 -07001001 if (deny_user_mode) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001002 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1003 nsize += fill_ace_for_sid(pnntace, pownersid, deny_user_mode,
1004 0700, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -07001005 num_aces++;
1006 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001007
Shyam Prasad N0f220532020-08-17 03:23:12 -07001008 /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/
1009 if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001010 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1011 nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode,
1012 0070, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -07001013 num_aces++;
1014 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001015
1016 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1017 nsize += fill_ace_for_sid(pnntace, pownersid, user_mode,
1018 0700, ACCESS_ALLOWED, true);
Shyam Prasad N0f220532020-08-17 03:23:12 -07001019 num_aces++;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001020
Shyam Prasad N0f220532020-08-17 03:23:12 -07001021 /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */
1022 if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001023 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1024 nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode,
1025 0070, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -07001026 num_aces++;
1027 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001028
1029 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1030 nsize += fill_ace_for_sid(pnntace, pgrpsid, group_mode,
1031 0070, ACCESS_ALLOWED, !sticky_set);
Aurelien Aptele37a02c2019-09-17 01:47:27 +02001032 num_aces++;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001033
1034 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1035 nsize += fill_ace_for_sid(pnntace, &sid_everyone, other_mode,
1036 0007, ACCESS_ALLOWED, !sticky_set);
Aurelien Aptele37a02c2019-09-17 01:47:27 +02001037 num_aces++;
1038
Shyam Prasad N0f220532020-08-17 03:23:12 -07001039set_size:
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001040 *pnum_aces = num_aces;
1041 *pnsize = nsize;
1042}
1043
1044static __u16 replace_sids_and_copy_aces(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
1045 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
1046 struct cifs_sid *pnownersid, struct cifs_sid *pngrpsid)
1047{
1048 int i;
1049 u16 size = 0;
1050 struct cifs_ace *pntace = NULL;
1051 char *acl_base = NULL;
1052 u32 src_num_aces = 0;
1053 u16 nsize = 0;
1054 struct cifs_ace *pnntace = NULL;
1055 char *nacl_base = NULL;
1056 u16 ace_size = 0;
1057
1058 acl_base = (char *)pdacl;
1059 size = sizeof(struct cifs_acl);
1060 src_num_aces = le32_to_cpu(pdacl->num_aces);
1061
1062 nacl_base = (char *)pndacl;
1063 nsize = sizeof(struct cifs_acl);
1064
1065 /* Go through all the ACEs */
1066 for (i = 0; i < src_num_aces; ++i) {
1067 pntace = (struct cifs_ace *) (acl_base + size);
1068 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1069
1070 if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0)
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001071 ace_size = cifs_copy_ace(pnntace, pntace, pnownersid);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001072 else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0)
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001073 ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001074 else
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001075 ace_size = cifs_copy_ace(pnntace, pntace, NULL);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001076
1077 size += le16_to_cpu(pntace->size);
1078 nsize += ace_size;
1079 }
1080
1081 return nsize;
1082}
1083
1084static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
1085 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
1086 __u64 *pnmode, bool mode_from_sid)
1087{
1088 int i;
1089 u16 size = 0;
1090 struct cifs_ace *pntace = NULL;
1091 char *acl_base = NULL;
1092 u32 src_num_aces = 0;
1093 u16 nsize = 0;
1094 struct cifs_ace *pnntace = NULL;
1095 char *nacl_base = NULL;
1096 u32 num_aces = 0;
1097 __u64 nmode;
1098 bool new_aces_set = false;
1099
1100 /* Assuming that pndacl and pnmode are never NULL */
1101 nmode = *pnmode;
1102 nacl_base = (char *)pndacl;
1103 nsize = sizeof(struct cifs_acl);
1104
1105 /* If pdacl is NULL, we don't have a src. Simply populate new ACL. */
1106 if (!pdacl) {
1107 populate_new_aces(nacl_base,
1108 pownersid, pgrpsid,
1109 pnmode, &num_aces, &nsize,
1110 mode_from_sid);
1111 goto finalize_dacl;
1112 }
1113
1114 acl_base = (char *)pdacl;
1115 size = sizeof(struct cifs_acl);
1116 src_num_aces = le32_to_cpu(pdacl->num_aces);
1117
1118 /* Retain old ACEs which we can retain */
1119 for (i = 0; i < src_num_aces; ++i) {
1120 pntace = (struct cifs_ace *) (acl_base + size);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001121
1122 if (!new_aces_set && (pntace->flags & INHERITED_ACE)) {
1123 /* Place the new ACEs in between existing explicit and inherited */
1124 populate_new_aces(nacl_base,
1125 pownersid, pgrpsid,
1126 pnmode, &num_aces, &nsize,
1127 mode_from_sid);
1128
1129 new_aces_set = true;
1130 }
1131
1132 /* If it's any one of the ACE we're replacing, skip! */
Shyam Prasad N3bffbe92021-03-26 10:28:16 +00001133 if (((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) ||
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001134 (compare_sids(&pntace->sid, pownersid) == 0) ||
1135 (compare_sids(&pntace->sid, pgrpsid) == 0) ||
1136 (compare_sids(&pntace->sid, &sid_everyone) == 0) ||
Shyam Prasad N51713172021-03-10 10:22:27 +00001137 (compare_sids(&pntace->sid, &sid_authusers) == 0))) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001138 goto next_ace;
1139 }
1140
Shyam Prasad N51713172021-03-10 10:22:27 +00001141 /* update the pointer to the next ACE to populate*/
1142 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1143
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001144 nsize += cifs_copy_ace(pnntace, pntace, NULL);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001145 num_aces++;
1146
1147next_ace:
Steve French23bda5e2021-02-22 14:40:43 -06001148 size += le16_to_cpu(pntace->size);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001149 }
1150
1151 /* If inherited ACEs are not present, place the new ones at the tail */
1152 if (!new_aces_set) {
1153 populate_new_aces(nacl_base,
1154 pownersid, pgrpsid,
1155 pnmode, &num_aces, &nsize,
1156 mode_from_sid);
1157
1158 new_aces_set = true;
1159 }
1160
1161finalize_dacl:
Aurelien Aptele37a02c2019-09-17 01:47:27 +02001162 pndacl->num_aces = cpu_to_le32(num_aces);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001163 pndacl->size = cpu_to_le16(nsize);
Steve French97837582007-12-31 07:47:21 +00001164
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001165 return 0;
Steve French97837582007-12-31 07:47:21 +00001166}
1167
Steve Frenchbcb02032007-09-25 16:17:24 +00001168static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
1169{
1170 /* BB need to add parm so we can store the SID BB */
1171
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001172 /* validate that we do not go past end of ACL - sid must be at least 8
1173 bytes long (assuming no sub-auths - e.g. the null SID */
1174 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001175 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +00001176 return -EINVAL;
1177 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001178
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001179#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001180 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +00001181 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -05001182 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
1183 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001184
Steve Frenchaf6f4612007-10-16 18:40:37 +00001185 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001186 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
1187 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001188 }
1189
Steve Frenchd12fd122007-10-03 19:43:19 +00001190 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001191 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -05001192 cifs_dbg(FYI, "RID 0x%x\n",
1193 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001194 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001195#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001196
Steve Frenchbcb02032007-09-25 16:17:24 +00001197 return 0;
1198}
1199
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001200
Steve Frenchbcb02032007-09-25 16:17:24 +00001201/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001202static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001203 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
1204 bool get_mode_from_special_sid)
Steve Frenchbcb02032007-09-25 16:17:24 +00001205{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001206 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001207 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1208 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001209 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001210 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001211
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001212 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001213 return -EIO;
1214
Steve Frenchbcb02032007-09-25 16:17:24 +00001215 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001216 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001217 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001218 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001219 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001220 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05001221 cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
Steve Frenchaf6f4612007-10-16 18:40:37 +00001222 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1223 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001224 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001225/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001226 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001227 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001228 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001229 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001230 }
1231 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1232 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001233 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
1234 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001235 return rc;
1236 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001237
1238 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001239 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001240 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
1241 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001242 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001243 }
1244 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1245 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001246 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
1247 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001248 return rc;
1249 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001250
Steve French7505e052007-11-01 18:03:01 +00001251 if (dacloffset)
1252 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001253 group_sid_ptr, fattr, get_mode_from_special_sid);
Steve French7505e052007-11-01 18:03:01 +00001254 else
Joe Perchesf96637b2013-05-04 22:12:25 -05001255 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001256
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001257 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001258}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001259
Steve French97837582007-12-31 07:47:21 +00001260/* Convert permission bits from mode to equivalent CIFS ACL */
1261static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001262 __u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
Steve Frencha6603392020-06-12 10:36:37 -05001263 bool mode_from_sid, bool id_from_sid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001264{
1265 int rc = 0;
1266 __u32 dacloffset;
1267 __u32 ndacloffset;
1268 __u32 sidsoffset;
1269 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001270 struct cifs_sid *nowner_sid_ptr = NULL, *ngroup_sid_ptr = NULL;
Steve French97837582007-12-31 07:47:21 +00001271 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1272 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001273 char *end_of_acl = ((char *)pntsd) + secdesclen;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001274 u16 size = 0;
1275
1276 dacloffset = le32_to_cpu(pntsd->dacloffset);
1277 if (dacloffset) {
1278 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1279 if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
Shyam Prasad Nf1ebe482021-02-24 15:04:02 +00001280 cifs_dbg(VFS, "Server returned illegal ACL size\n");
1281 return -EINVAL;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001282 }
1283 }
1284
1285 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1286 le32_to_cpu(pntsd->osidoffset));
1287 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1288 le32_to_cpu(pntsd->gsidoffset));
Steve French97837582007-12-31 07:47:21 +00001289
Shyam Prasad N0f220532020-08-17 03:23:12 -07001290 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001291 ndacloffset = sizeof(struct cifs_ntsd);
1292 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001293 ndacl_ptr->revision =
1294 dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
Steve French97837582007-12-31 07:47:21 +00001295
Steve French23bda5e2021-02-22 14:40:43 -06001296 ndacl_ptr->size = cpu_to_le16(0);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001297 ndacl_ptr->num_aces = cpu_to_le32(0);
1298
1299 rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Shyam Prasad N0f220532020-08-17 03:23:12 -07001300 pnmode, mode_from_sid);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001301
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001302 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001303 /* copy the non-dacl portion of secdesc */
1304 *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
1305 NULL, NULL);
1306
1307 *aclflag |= CIFS_ACL_DACL;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001308 } else {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001309 ndacloffset = sizeof(struct cifs_ntsd);
1310 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1311 ndacl_ptr->revision =
1312 dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
1313 ndacl_ptr->num_aces = dacl_ptr->num_aces;
1314
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001315 if (uid_valid(uid)) { /* chown */
1316 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001317 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1318 GFP_KERNEL);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001319 if (!nowner_sid_ptr) {
1320 rc = -ENOMEM;
1321 goto chown_chgrp_exit;
1322 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001323 id = from_kuid(&init_user_ns, uid);
Steve Frencha6603392020-06-12 10:36:37 -05001324 if (id_from_sid) {
1325 struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
1326 /* Populate the user ownership fields S-1-5-88-1 */
1327 osid->Revision = 1;
1328 osid->NumAuth = 3;
1329 osid->Authority[5] = 5;
1330 osid->SubAuthorities[0] = cpu_to_le32(88);
1331 osid->SubAuthorities[1] = cpu_to_le32(1);
1332 osid->SubAuthorities[2] = cpu_to_le32(id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001333
Steve Frencha6603392020-06-12 10:36:37 -05001334 } else { /* lookup sid with upcall */
1335 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
1336 if (rc) {
1337 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
1338 __func__, rc, id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001339 goto chown_chgrp_exit;
Steve Frencha6603392020-06-12 10:36:37 -05001340 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001341 }
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001342 *aclflag |= CIFS_ACL_OWNER;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001343 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001344 if (gid_valid(gid)) { /* chgrp */
1345 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001346 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1347 GFP_KERNEL);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001348 if (!ngroup_sid_ptr) {
1349 rc = -ENOMEM;
1350 goto chown_chgrp_exit;
1351 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001352 id = from_kgid(&init_user_ns, gid);
Steve Frencha6603392020-06-12 10:36:37 -05001353 if (id_from_sid) {
1354 struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
1355 /* Populate the group ownership fields S-1-5-88-2 */
1356 gsid->Revision = 1;
1357 gsid->NumAuth = 3;
1358 gsid->Authority[5] = 5;
1359 gsid->SubAuthorities[0] = cpu_to_le32(88);
1360 gsid->SubAuthorities[1] = cpu_to_le32(2);
1361 gsid->SubAuthorities[2] = cpu_to_le32(id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001362
Steve Frencha6603392020-06-12 10:36:37 -05001363 } else { /* lookup sid with upcall */
1364 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
1365 if (rc) {
1366 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
1367 __func__, rc, id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001368 goto chown_chgrp_exit;
Steve Frencha6603392020-06-12 10:36:37 -05001369 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001370 }
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001371 *aclflag |= CIFS_ACL_GROUP;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001372 }
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001373
1374 if (dacloffset) {
1375 /* Replace ACEs for old owner with new one */
1376 size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
1377 owner_sid_ptr, group_sid_ptr,
1378 nowner_sid_ptr, ngroup_sid_ptr);
1379 ndacl_ptr->size = cpu_to_le16(size);
1380 }
1381
1382 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1383 /* copy the non-dacl portion of secdesc */
1384 *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
1385 nowner_sid_ptr, ngroup_sid_ptr);
1386
1387chown_chgrp_exit:
1388 /* errors could jump here. So make sure we return soon after this */
1389 kfree(nowner_sid_ptr);
1390 kfree(ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001391 }
Steve French97837582007-12-31 07:47:21 +00001392
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001393 return rc;
Steve French97837582007-12-31 07:47:21 +00001394}
1395
Steve French42eacf92014-02-10 14:08:16 -06001396struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
Boris Protopopov3970acf2020-12-18 11:30:12 -06001397 const struct cifs_fid *cifsfid, u32 *pacllen,
1398 u32 __maybe_unused unused)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001399{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001400 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001401 unsigned int xid;
1402 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001403 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1404
1405 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001406 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001407
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001408 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001409 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1410 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001411 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001412
Jeff Layton7ffec372010-09-29 19:51:11 -04001413 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001414
Joe Perchesf96637b2013-05-04 22:12:25 -05001415 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001416 if (rc)
1417 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001418 return pntsd;
1419}
1420
1421static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1422 const char *path, u32 *pacllen)
1423{
1424 struct cifs_ntsd *pntsd = NULL;
1425 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001426 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001427 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00001428 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001429 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001430 struct cifs_fid fid;
1431 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001432
Jeff Layton7ffec372010-09-29 19:51:11 -04001433 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001434 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001435
1436 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001437 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001438
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001439 oparms.tcon = tcon;
1440 oparms.cifs_sb = cifs_sb;
1441 oparms.desired_access = READ_CONTROL;
Amir Goldstein0f060932020-02-03 21:46:43 +02001442 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001443 oparms.disposition = FILE_OPEN;
1444 oparms.path = path;
1445 oparms.fid = &fid;
1446 oparms.reconnect = false;
1447
1448 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001449 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001450 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1451 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001452 }
1453
Jeff Layton7ffec372010-09-29 19:51:11 -04001454 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001455 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001456
Joe Perchesf96637b2013-05-04 22:12:25 -05001457 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001458 if (rc)
1459 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001460 return pntsd;
1461}
1462
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001463/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001464struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001465 struct inode *inode, const char *path,
Boris Protopopov3970acf2020-12-18 11:30:12 -06001466 u32 *pacllen, u32 info)
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001467{
1468 struct cifs_ntsd *pntsd = NULL;
1469 struct cifsFileInfo *open_file = NULL;
1470
1471 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001472 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001473 if (!open_file)
1474 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1475
Boris Protopopov3970acf2020-12-18 11:30:12 -06001476 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001477 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001478 return pntsd;
1479}
1480
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001481 /* Set an ACL on the server */
1482int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1483 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001484{
1485 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001486 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001487 int rc, access_flags;
Steve French96daf2b2011-05-27 04:34:02 +00001488 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001489 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001490 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001491 struct cifs_fid fid;
1492 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001493
Jeff Layton7ffec372010-09-29 19:51:11 -04001494 if (IS_ERR(tlink))
1495 return PTR_ERR(tlink);
1496
1497 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001498 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001499
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001500 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1501 access_flags = WRITE_OWNER;
1502 else
1503 access_flags = WRITE_DAC;
1504
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001505 oparms.tcon = tcon;
1506 oparms.cifs_sb = cifs_sb;
1507 oparms.desired_access = access_flags;
Amir Goldstein0f060932020-02-03 21:46:43 +02001508 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001509 oparms.disposition = FILE_OPEN;
1510 oparms.path = path;
1511 oparms.fid = &fid;
1512 oparms.reconnect = false;
1513
1514 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001515 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001516 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001517 goto out;
Steve French97837582007-12-31 07:47:21 +00001518 }
1519
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001520 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001521 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001522
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001523 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001524out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001525 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001526 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001527 return rc;
1528}
Steve French97837582007-12-31 07:47:21 +00001529
Achilles Gaikwad36c7ce42018-01-28 13:39:48 +05301530/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001531int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001532cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001533 struct inode *inode, bool mode_from_special_sid,
1534 const char *path, const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001535{
1536 struct cifs_ntsd *pntsd = NULL;
1537 u32 acllen = 0;
1538 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001539 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001540 struct smb_version_operations *ops;
Boris Protopopov3970acf2020-12-18 11:30:12 -06001541 const u32 info = 0;
Steve French7505e052007-11-01 18:03:01 +00001542
Joe Perchesf96637b2013-05-04 22:12:25 -05001543 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001544
Steve French42eacf92014-02-10 14:08:16 -06001545 if (IS_ERR(tlink))
1546 return PTR_ERR(tlink);
Steve French7505e052007-11-01 18:03:01 +00001547
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001548 ops = tlink_tcon(tlink)->ses->server->ops;
1549
1550 if (pfid && (ops->get_acl_by_fid))
Boris Protopopov3970acf2020-12-18 11:30:12 -06001551 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001552 else if (ops->get_acl)
Boris Protopopov3970acf2020-12-18 11:30:12 -06001553 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info);
Steve French42eacf92014-02-10 14:08:16 -06001554 else {
1555 cifs_put_tlink(tlink);
1556 return -EOPNOTSUPP;
1557 }
Steve French7505e052007-11-01 18:03:01 +00001558 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001559 if (IS_ERR(pntsd)) {
1560 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001561 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001562 } else if (mode_from_special_sid) {
1563 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
Namjae Jeon98128572020-11-09 17:35:33 +09001564 kfree(pntsd);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001565 } else {
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001566 /* get approximated mode from ACL */
1567 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001568 kfree(pntsd);
1569 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001570 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001571 }
Steve French7505e052007-11-01 18:03:01 +00001572
Steve French42eacf92014-02-10 14:08:16 -06001573 cifs_put_tlink(tlink);
1574
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001575 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001576}
Steve French953f8682007-10-31 04:54:42 +00001577
Steve French7505e052007-11-01 18:03:01 +00001578/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001579int
Shyam Prasad N0f220532020-08-17 03:23:12 -07001580id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001581 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001582{
1583 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001584 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001585 __u32 secdesclen = 0;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001586 __u32 nsecdesclen = 0;
1587 __u32 dacloffset = 0;
1588 struct cifs_acl *dacl_ptr = NULL;
Steve French97837582007-12-31 07:47:21 +00001589 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1590 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001591 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1592 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001593 struct smb_version_operations *ops;
Steve Frencha6603392020-06-12 10:36:37 -05001594 bool mode_from_sid, id_from_sid;
Boris Protopopov3970acf2020-12-18 11:30:12 -06001595 const u32 info = 0;
Steve French83e3bc22014-02-02 23:31:47 -06001596
1597 if (IS_ERR(tlink))
1598 return PTR_ERR(tlink);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001599
1600 ops = tlink_tcon(tlink)->ses->server->ops;
Steve French953f8682007-10-31 04:54:42 +00001601
Joe Perchesf96637b2013-05-04 22:12:25 -05001602 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001603
1604 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001605
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001606 if (ops->get_acl == NULL) {
Steve French83e3bc22014-02-02 23:31:47 -06001607 cifs_put_tlink(tlink);
1608 return -EOPNOTSUPP;
1609 }
1610
Boris Protopopov3970acf2020-12-18 11:30:12 -06001611 pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001612 if (IS_ERR(pntsd)) {
1613 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001614 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001615 cifs_put_tlink(tlink);
1616 return rc;
Steve French97837582007-12-31 07:47:21 +00001617 }
1618
Steve French22442172019-07-19 08:15:55 +00001619 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
1620 mode_from_sid = true;
1621 else
1622 mode_from_sid = false;
1623
Steve Frencha6603392020-06-12 10:36:37 -05001624 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
1625 id_from_sid = true;
1626 else
1627 id_from_sid = false;
1628
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001629 /* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
1630 nsecdesclen = secdesclen;
1631 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
1632 if (mode_from_sid)
1633 nsecdesclen += sizeof(struct cifs_ace);
1634 else /* cifsacl */
1635 nsecdesclen += 5 * sizeof(struct cifs_ace);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001636 } else { /* chown */
1637 /* When ownership changes, changes new owner sid length could be different */
1638 nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2);
1639 dacloffset = le32_to_cpu(pntsd->dacloffset);
1640 if (dacloffset) {
1641 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1642 if (mode_from_sid)
1643 nsecdesclen +=
Steve French23bda5e2021-02-22 14:40:43 -06001644 le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001645 else /* cifsacl */
1646 nsecdesclen += le16_to_cpu(dacl_ptr->size);
1647 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001648 }
1649
1650 /*
1651 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1652 * as chmod disables ACEs and set the security descriptor. Allocate
1653 * memory for the smb header, set security descriptor request security
jack1.li_cpc45adff2021-04-09 22:00:37 -05001654 * descriptor parameters, and security descriptor itself
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001655 */
1656 nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN);
1657 pnntsd = kmalloc(nsecdesclen, GFP_KERNEL);
1658 if (!pnntsd) {
1659 kfree(pntsd);
1660 cifs_put_tlink(tlink);
1661 return -ENOMEM;
1662 }
1663
1664 rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid,
Steve Frencha6603392020-06-12 10:36:37 -05001665 mode_from_sid, id_from_sid, &aclflag);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001666
Joe Perchesf96637b2013-05-04 22:12:25 -05001667 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001668
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001669 if (ops->set_acl == NULL)
Steve French83e3bc22014-02-02 23:31:47 -06001670 rc = -EOPNOTSUPP;
1671
Jeff Laytonc78cd832012-11-25 08:00:35 -05001672 if (!rc) {
1673 /* Set the security descriptor */
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001674 rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001675 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001676 }
Steve French83e3bc22014-02-02 23:31:47 -06001677 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001678
1679 kfree(pnntsd);
1680 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001681 return rc;
Steve French953f8682007-10-31 04:54:42 +00001682}