blob: 388eb536cff15967ba64c12ab017a68ae9cdd72d [file] [log] [blame]
Steve French929be902021-06-18 00:31:49 -05001// SPDX-License-Identifier: LGPL-2.1
Steve Frenchbcb02032007-09-25 16:17:24 +00002/*
3 * fs/cifs/cifsacl.c
4 *
Steve French8b1327f2008-03-14 22:37:16 +00005 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00006 * Author(s): Steve French (sfrench@us.ibm.com)
7 *
8 * Contains the routines for mapping CIFS/NTFS ACLs
9 *
Steve Frenchbcb02032007-09-25 16:17:24 +000010 */
11
Steve French65874002007-09-25 19:53:44 +000012#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090013#include <linux/slab.h>
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050014#include <linux/string.h>
15#include <linux/keyctl.h>
16#include <linux/key-type.h>
17#include <keys/user-type.h>
Steve French65874002007-09-25 19:53:44 +000018#include "cifspdu.h"
19#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000020#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000021#include "cifsproto.h"
22#include "cifs_debug.h"
Ronnie Sahlberg8401e932020-12-12 13:40:50 -060023#include "fs_context.h"
Steve French65874002007-09-25 19:53:44 +000024
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060025/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000026static const struct cifs_sid sid_everyone = {
27 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060028/* security id for Authenticated Users system group */
29static const struct cifs_sid sid_authusers = {
Fabian Frederickbc09d142014-12-10 15:41:15 -080030 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000031
Steve French3514de32016-10-13 19:06:23 -050032/* S-1-22-1 Unmapped Unix users */
33static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
34 {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
35
36/* S-1-22-2 Unmapped Unix groups */
37static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
38 {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
39
40/*
Alexander A. Klimovcba22b12020-06-27 12:31:25 +020041 * See https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve French3514de32016-10-13 19:06:23 -050042 */
43
44/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
45
46/* S-1-5-88-1 Unix uid */
47static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
48 {cpu_to_le32(88),
49 cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
50
51/* S-1-5-88-2 Unix gid */
52static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
53 {cpu_to_le32(88),
54 cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
55
56/* S-1-5-88-3 Unix mode */
57static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
58 {cpu_to_le32(88),
59 cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
60
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050061static const struct cred *root_cred;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050062
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050063static int
David Howellscf7f6012012-09-13 13:06:29 +010064cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050065{
66 char *payload;
67
Jeff Layton41a9f1f2012-12-03 06:05:29 -050068 /*
69 * If the payload is less than or equal to the size of a pointer, then
70 * an allocation here is wasteful. Just copy the data directly to the
71 * payload.value union member instead.
72 *
73 * With this however, you must check the datalen before trying to
74 * dereference payload.data!
75 */
Jeff Layton1f630682012-12-03 06:05:31 -050076 if (prep->datalen <= sizeof(key->payload)) {
David Howells146aa8b2015-10-21 14:04:48 +010077 key->payload.data[0] = NULL;
78 memcpy(&key->payload, prep->data, prep->datalen);
79 } else {
80 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
81 if (!payload)
82 return -ENOMEM;
83 key->payload.data[0] = payload;
Jeff Layton41a9f1f2012-12-03 06:05:29 -050084 }
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050085
David Howellscf7f6012012-09-13 13:06:29 +010086 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050087 return 0;
88}
89
90static inline void
91cifs_idmap_key_destroy(struct key *key)
92{
Jeff Layton1f630682012-12-03 06:05:31 -050093 if (key->datalen > sizeof(key->payload))
David Howells146aa8b2015-10-21 14:04:48 +010094 kfree(key->payload.data[0]);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050095}
96
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050097static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -050098 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050099 .instantiate = cifs_idmap_key_instantiate,
100 .destroy = cifs_idmap_key_destroy,
101 .describe = user_describe,
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500102};
103
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500104static char *
105sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500106{
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500107 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500108 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500109 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -0500110 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500111
112 /* 3 bytes for prefix */
113 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
114 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
115 GFP_KERNEL);
116 if (!sidstr)
117 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500118
119 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500120 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
121 sidptr->revision);
122 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500123
Jeff Layton193cdd82012-12-10 06:10:44 -0500124 /* The authority field is a single 48-bit number */
125 id_auth_val = (unsigned long long)sidptr->authority[5];
126 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
127 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
128 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
129 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
130 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
131
132 /*
133 * MS-DTYP states that if the authority is >= 2^32, then it should be
134 * expressed as a hex value.
135 */
136 if (id_auth_val <= UINT_MAX)
137 len = sprintf(strptr, "-%llu", id_auth_val);
138 else
139 len = sprintf(strptr, "-0x%llx", id_auth_val);
140
141 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500142
143 for (i = 0; i < sidptr->num_subauth; ++i) {
144 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500145 len = sprintf(strptr, "-%u", saval);
146 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500147 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500148
149 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500150}
151
Jeff Layton436bb432012-11-25 08:00:36 -0500152/*
153 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
154 * the same returns zero, if they do not match returns non-zero.
155 */
156static int
157compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
158{
159 int i;
160 int num_subauth, num_sat, num_saw;
161
162 if ((!ctsid) || (!cwsid))
163 return 1;
164
165 /* compare the revision */
166 if (ctsid->revision != cwsid->revision) {
167 if (ctsid->revision > cwsid->revision)
168 return 1;
169 else
170 return -1;
171 }
172
173 /* compare all of the six auth values */
174 for (i = 0; i < NUM_AUTHS; ++i) {
175 if (ctsid->authority[i] != cwsid->authority[i]) {
176 if (ctsid->authority[i] > cwsid->authority[i])
177 return 1;
178 else
179 return -1;
180 }
181 }
182
183 /* compare all of the subauth values if any */
184 num_sat = ctsid->num_subauth;
185 num_saw = cwsid->num_subauth;
186 num_subauth = num_sat < num_saw ? num_sat : num_saw;
187 if (num_subauth) {
188 for (i = 0; i < num_subauth; ++i) {
189 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
190 if (le32_to_cpu(ctsid->sub_auth[i]) >
191 le32_to_cpu(cwsid->sub_auth[i]))
192 return 1;
193 else
194 return -1;
195 }
196 }
197 }
198
199 return 0; /* sids compare/match */
200}
201
Steve French3514de32016-10-13 19:06:23 -0500202static bool
203is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
204{
205 int i;
206 int num_subauth;
207 const struct cifs_sid *pwell_known_sid;
208
209 if (!psid || (puid == NULL))
210 return false;
211
212 num_subauth = psid->num_subauth;
213
214 /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
215 if (num_subauth == 2) {
216 if (is_group)
217 pwell_known_sid = &sid_unix_groups;
218 else
219 pwell_known_sid = &sid_unix_users;
220 } else if (num_subauth == 3) {
221 if (is_group)
222 pwell_known_sid = &sid_unix_NFS_groups;
223 else
224 pwell_known_sid = &sid_unix_NFS_users;
225 } else
226 return false;
227
228 /* compare the revision */
229 if (psid->revision != pwell_known_sid->revision)
230 return false;
231
232 /* compare all of the six auth values */
233 for (i = 0; i < NUM_AUTHS; ++i) {
234 if (psid->authority[i] != pwell_known_sid->authority[i]) {
235 cifs_dbg(FYI, "auth %d did not match\n", i);
236 return false;
237 }
238 }
239
240 if (num_subauth == 2) {
241 if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
242 return false;
243
244 *puid = le32_to_cpu(psid->sub_auth[1]);
245 } else /* 3 subauths, ie Windows/Mac style */ {
246 *puid = le32_to_cpu(psid->sub_auth[0]);
247 if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
248 (psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
249 return false;
250
251 *puid = le32_to_cpu(psid->sub_auth[2]);
252 }
253
254 cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
255 return true; /* well known sid found, uid returned */
256}
257
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800258static __u16
Jeff Layton36960e42012-11-03 09:37:28 -0400259cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
260{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500261 int i;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800262 __u16 size = 1 + 1 + 6;
Jeff Layton36f87ee2012-11-25 08:00:37 -0500263
264 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500265 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500266 for (i = 0; i < NUM_AUTHS; ++i)
267 dst->authority[i] = src->authority[i];
268 for (i = 0; i < dst->num_subauth; ++i)
269 dst->sub_auth[i] = src->sub_auth[i];
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800270 size += (dst->num_subauth * 4);
271
272 return size;
Jeff Layton36960e42012-11-03 09:37:28 -0400273}
274
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500275static int
276id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500277{
278 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500279 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500280 struct cifs_sid *ksid;
281 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500282 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500283 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500284
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500285 rc = snprintf(desc, sizeof(desc), "%ci:%u",
286 sidtype == SIDOWNER ? 'o' : 'g', cid);
287 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500288 return -EINVAL;
289
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500290 rc = 0;
291 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700292 sidkey = request_key(&cifs_idmap_key_type, desc, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500293 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500294 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500295 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
296 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500297 goto out_revert_creds;
298 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
299 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500300 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
301 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500302 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500303 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500304
Jeff Layton1f630682012-12-03 06:05:31 -0500305 /*
306 * A sid is usually too large to be embedded in payload.value, but if
307 * there are no subauthorities and the host has 8-byte pointers, then
308 * it could be.
309 */
310 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
David Howells146aa8b2015-10-21 14:04:48 +0100311 (struct cifs_sid *)&sidkey->payload :
312 (struct cifs_sid *)sidkey->payload.data[0];
Jeff Layton1f630682012-12-03 06:05:31 -0500313
Jeff Layton2ae03022012-12-03 06:05:30 -0500314 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
315 if (ksid_size > sidkey->datalen) {
316 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500317 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
318 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500319 goto invalidate_key;
320 }
Jeff Layton1f630682012-12-03 06:05:31 -0500321
Jeff Layton2ae03022012-12-03 06:05:30 -0500322 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500323out_key_put:
324 key_put(sidkey);
325out_revert_creds:
326 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500327 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500328
329invalidate_key:
330 key_invalidate(sidkey);
331 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500332}
333
Steve French99344302020-10-20 02:02:02 -0500334int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500335sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
336 struct cifs_fattr *fattr, uint sidtype)
337{
Qiujun Huangf2d67932020-03-04 15:42:51 +0800338 int rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500339 struct key *sidkey;
340 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500341 const struct cred *saved_cred;
Ronnie Sahlberg8401e932020-12-12 13:40:50 -0600342 kuid_t fuid = cifs_sb->ctx->linux_uid;
343 kgid_t fgid = cifs_sb->ctx->linux_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500344
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500345 /*
346 * If we have too many subauthorities, then something is really wrong.
347 * Just return an error.
348 */
349 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500350 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
351 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500352 return -EIO;
353 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500354
Steve French99344302020-10-20 02:02:02 -0500355 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
356 (cifs_sb_master_tcon(cifs_sb)->posix_extensions)) {
Steve French3514de32016-10-13 19:06:23 -0500357 uint32_t unix_id;
358 bool is_group;
359
360 if (sidtype != SIDOWNER)
361 is_group = true;
362 else
363 is_group = false;
364
365 if (is_well_known_sid(psid, &unix_id, is_group) == false)
366 goto try_upcall_to_get_id;
367
368 if (is_group) {
369 kgid_t gid;
370 gid_t id;
371
372 id = (gid_t)unix_id;
373 gid = make_kgid(&init_user_ns, id);
374 if (gid_valid(gid)) {
375 fgid = gid;
376 goto got_valid_id;
377 }
378 } else {
379 kuid_t uid;
380 uid_t id;
381
382 id = (uid_t)unix_id;
383 uid = make_kuid(&init_user_ns, id);
384 if (uid_valid(uid)) {
385 fuid = uid;
386 goto got_valid_id;
387 }
388 }
389 /* If unable to find uid/gid easily from SID try via upcall */
390 }
391
392try_upcall_to_get_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500393 sidstr = sid_to_key_str(psid, sidtype);
394 if (!sidstr)
395 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500396
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500397 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700398 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500399 if (IS_ERR(sidkey)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500400 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
401 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500402 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500403 }
404
405 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500406 * FIXME: Here we assume that uid_t and gid_t are same size. It's
407 * probably a safe assumption but might be better to check based on
408 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500409 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800410 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500411 if (sidkey->datalen != sizeof(uid_t)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500412 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
413 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500414 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500415 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500416 }
417
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800418 if (sidtype == SIDOWNER) {
419 kuid_t uid;
420 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100421 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800422 uid = make_kuid(&init_user_ns, id);
423 if (uid_valid(uid))
424 fuid = uid;
425 } else {
426 kgid_t gid;
427 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100428 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800429 gid = make_kgid(&init_user_ns, id);
430 if (gid_valid(gid))
431 fgid = gid;
432 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500433
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500434out_key_put:
435 key_put(sidkey);
436out_revert_creds:
437 revert_creds(saved_cred);
438 kfree(sidstr);
439
440 /*
441 * Note that we return 0 here unconditionally. If the mapping
Ronnie Sahlberg8401e932020-12-12 13:40:50 -0600442 * fails then we just fall back to using the ctx->linux_uid/linux_gid.
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500443 */
Steve French3514de32016-10-13 19:06:23 -0500444got_valid_id:
Qiujun Huangf2d67932020-03-04 15:42:51 +0800445 rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500446 if (sidtype == SIDOWNER)
447 fattr->cf_uid = fuid;
448 else
449 fattr->cf_gid = fgid;
Qiujun Huangf2d67932020-03-04 15:42:51 +0800450 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500451}
452
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500453int
454init_cifs_idmap(void)
455{
456 struct cred *cred;
457 struct key *keyring;
458 int ret;
459
Joe Perchesf96637b2013-05-04 22:12:25 -0500460 cifs_dbg(FYI, "Registering the %s key type\n",
461 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500462
463 /* create an override credential set with a special thread keyring in
464 * which requests are cached
465 *
466 * this is used to prevent malicious redirections from being installed
467 * with add_key().
468 */
469 cred = prepare_kernel_cred(NULL);
470 if (!cred)
471 return -ENOMEM;
472
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800473 keyring = keyring_alloc(".cifs_idmap",
474 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
Linus Torvalds028db3e2019-07-10 18:43:43 -0700475 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
476 KEY_USR_VIEW | KEY_USR_READ,
David Howells5ac7eac2016-04-06 16:14:24 +0100477 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500478 if (IS_ERR(keyring)) {
479 ret = PTR_ERR(keyring);
480 goto failed_put_cred;
481 }
482
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500483 ret = register_key_type(&cifs_idmap_key_type);
484 if (ret < 0)
485 goto failed_put_key;
486
487 /* instruct request_key() to use this special keyring as a cache for
488 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000489 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500490 cred->thread_keyring = keyring;
491 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
492 root_cred = cred;
493
Joe Perchesf96637b2013-05-04 22:12:25 -0500494 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500495 return 0;
496
497failed_put_key:
498 key_put(keyring);
499failed_put_cred:
500 put_cred(cred);
501 return ret;
502}
503
504void
505exit_cifs_idmap(void)
506{
507 key_revoke(root_cred->thread_keyring);
508 unregister_key_type(&cifs_idmap_key_type);
509 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500510 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500511}
512
Steve French97837582007-12-31 07:47:21 +0000513/* copy ntsd, owner sid, and group sid from a security descriptor to another */
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000514static __u32 copy_sec_desc(const struct cifs_ntsd *pntsd,
515 struct cifs_ntsd *pnntsd,
516 __u32 sidsoffset,
517 struct cifs_sid *pownersid,
518 struct cifs_sid *pgrpsid)
Steve French97837582007-12-31 07:47:21 +0000519{
Steve French97837582007-12-31 07:47:21 +0000520 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
521 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
522
523 /* copy security descriptor control portion */
524 pnntsd->revision = pntsd->revision;
525 pnntsd->type = pntsd->type;
526 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
527 pnntsd->sacloffset = 0;
528 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
529 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
530
531 /* copy owner sid */
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000532 if (pownersid)
533 owner_sid_ptr = pownersid;
534 else
535 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000536 le32_to_cpu(pntsd->osidoffset));
537 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400538 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000539
540 /* copy group sid */
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000541 if (pgrpsid)
542 group_sid_ptr = pgrpsid;
543 else
544 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000545 le32_to_cpu(pntsd->gsidoffset));
546 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
547 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400548 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000549
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000550 return sidsoffset + (2 * sizeof(struct cifs_sid));
Steve French97837582007-12-31 07:47:21 +0000551}
552
553
Steve French630f3f0c2007-10-25 21:17:17 +0000554/*
555 change posix mode to reflect permissions
556 pmode is the existing mode (we only want to overwrite part of this
557 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
558*/
Al Viro9b5e6852007-12-05 08:24:38 +0000559static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Shyam Prasad N0f220532020-08-17 03:23:12 -0700560 umode_t *pdenied, umode_t mask)
Steve French4879b442007-10-19 21:57:39 +0000561{
Al Viro9b5e6852007-12-05 08:24:38 +0000562 __u32 flags = le32_to_cpu(ace_flags);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700563 /*
564 * Do not assume "preferred" or "canonical" order.
565 * The first DENY or ALLOW ACE which matches perfectly is
566 * the permission to be used. Once allowed or denied, same
567 * permission in later ACEs do not matter.
568 */
Steve French15b03952007-11-08 17:57:40 +0000569
Shyam Prasad N0f220532020-08-17 03:23:12 -0700570 /* If not already allowed, deny these bits */
Steve French15b03952007-11-08 17:57:40 +0000571 if (type == ACCESS_DENIED) {
Shyam Prasad N0f220532020-08-17 03:23:12 -0700572 if (flags & GENERIC_ALL &&
573 !(*pmode & mask & 0777))
574 *pdenied |= mask & 0777;
Steve Frenchad7a2922008-02-07 23:25:02 +0000575
Shyam Prasad N0f220532020-08-17 03:23:12 -0700576 if (((flags & GENERIC_WRITE) ||
577 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) &&
578 !(*pmode & mask & 0222))
579 *pdenied |= mask & 0222;
580
581 if (((flags & GENERIC_READ) ||
582 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) &&
583 !(*pmode & mask & 0444))
584 *pdenied |= mask & 0444;
585
586 if (((flags & GENERIC_EXECUTE) ||
587 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) &&
588 !(*pmode & mask & 0111))
589 *pdenied |= mask & 0111;
590
Steve French15b03952007-11-08 17:57:40 +0000591 return;
592 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500593 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000594 return;
595 }
596 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000597
Shyam Prasad N0f220532020-08-17 03:23:12 -0700598 if ((flags & GENERIC_ALL) &&
599 !(*pdenied & mask & 0777)) {
600 *pmode |= mask & 0777;
Joe Perchesf96637b2013-05-04 22:12:25 -0500601 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000602 return;
603 }
Shyam Prasad N0f220532020-08-17 03:23:12 -0700604
605 if (((flags & GENERIC_WRITE) ||
606 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) &&
607 !(*pdenied & mask & 0222))
608 *pmode |= mask & 0222;
609
610 if (((flags & GENERIC_READ) ||
611 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) &&
612 !(*pdenied & mask & 0444))
613 *pmode |= mask & 0444;
614
615 if (((flags & GENERIC_EXECUTE) ||
616 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) &&
617 !(*pdenied & mask & 0111))
618 *pmode |= mask & 0111;
Steve Frenchd61e5802007-10-26 04:32:43 +0000619
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800620 /* If DELETE_CHILD is set only on an owner ACE, set sticky bit */
621 if (flags & FILE_DELETE_CHILD) {
622 if (mask == ACL_OWNER_MASK) {
623 if (!(*pdenied & 01000))
624 *pmode |= 01000;
625 } else if (!(*pdenied & 01000)) {
626 *pmode &= ~01000;
627 *pdenied |= 01000;
628 }
629 }
630
Frank Sorensonf52aa792020-02-12 15:31:48 -0600631 cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000632 return;
633}
634
Steve Frenchce06c9f2007-11-08 21:12:01 +0000635/*
636 Generate access flags to reflect permissions mode is the existing mode.
637 This function is called for every ACE in the DACL whose SID matches
638 with either owner or group or everyone.
639*/
640
641static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
642 __u32 *pace_flags)
643{
644 /* reset access mask */
645 *pace_flags = 0x0;
646
647 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
648 mode &= bits_to_use;
649
650 /* check for R/W/X UGO since we do not know whose flags
651 is this but we have cleared all the bits sans RWX for
652 either user or group or other as per bits_to_use */
653 if (mode & S_IRUGO)
654 *pace_flags |= SET_FILE_READ_RIGHTS;
655 if (mode & S_IWUGO)
656 *pace_flags |= SET_FILE_WRITE_RIGHTS;
657 if (mode & S_IXUGO)
658 *pace_flags |= SET_FILE_EXEC_RIGHTS;
659
Frank Sorensonf52aa792020-02-12 15:31:48 -0600660 cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n",
Joe Perchesf96637b2013-05-04 22:12:25 -0500661 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000662 return;
663}
664
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000665static __u16 cifs_copy_ace(struct cifs_ace *dst, struct cifs_ace *src, struct cifs_sid *psid)
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800666{
667 __u16 size = 1 + 1 + 2 + 4;
668
669 dst->type = src->type;
670 dst->flags = src->flags;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800671 dst->access_req = src->access_req;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +0000672
673 /* Check if there's a replacement sid specified */
674 if (psid)
675 size += cifs_copy_sid(&dst->sid, psid);
676 else
677 size += cifs_copy_sid(&dst->sid, &src->sid);
678
679 dst->size = cpu_to_le16(size);
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800680
681 return size;
682}
683
Al Viro2b210ad2008-03-29 03:09:18 +0000684static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800685 const struct cifs_sid *psid, __u64 nmode,
686 umode_t bits, __u8 access_type,
687 bool allow_delete_child)
Steve French97837582007-12-31 07:47:21 +0000688{
689 int i;
690 __u16 size = 0;
691 __u32 access_req = 0;
692
Shyam Prasad N0f220532020-08-17 03:23:12 -0700693 pntace->type = access_type;
Steve French97837582007-12-31 07:47:21 +0000694 pntace->flags = 0x0;
695 mode_to_access_flags(nmode, bits, &access_req);
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800696
697 if (access_type == ACCESS_ALLOWED && allow_delete_child)
698 access_req |= FILE_DELETE_CHILD;
699
Shyam Prasad N0f220532020-08-17 03:23:12 -0700700 if (access_type == ACCESS_ALLOWED && !access_req)
Steve French97837582007-12-31 07:47:21 +0000701 access_req = SET_MINIMUM_RIGHTS;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700702 else if (access_type == ACCESS_DENIED)
703 access_req &= ~SET_MINIMUM_RIGHTS;
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800704
Steve French97837582007-12-31 07:47:21 +0000705 pntace->access_req = cpu_to_le32(access_req);
706
707 pntace->sid.revision = psid->revision;
708 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500709 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000710 pntace->sid.authority[i] = psid->authority[i];
711 for (i = 0; i < psid->num_subauth; i++)
712 pntace->sid.sub_auth[i] = psid->sub_auth[i];
713
714 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
715 pntace->size = cpu_to_le16(size);
716
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000717 return size;
Steve French97837582007-12-31 07:47:21 +0000718}
719
Steve French297647c2007-10-12 04:11:59 +0000720
Steve French953f8682007-10-31 04:54:42 +0000721#ifdef CONFIG_CIFS_DEBUG2
722static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000723{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000724 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000725
726 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000727
Steve French44093ca2007-10-23 21:22:55 +0000728 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500729 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000730 return;
731 }
732
733 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500734 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000735 return;
Steve French44093ca2007-10-23 21:22:55 +0000736 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000737
Steve French44093ca2007-10-23 21:22:55 +0000738 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000739 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000740 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500741 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
742 pace->sid.revision, pace->sid.num_subauth, pace->type,
743 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000744 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500745 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
746 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000747 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000748
Steve Frenchd12fd122007-10-03 19:43:19 +0000749 /* BB add length check to make sure that we do not have huge
750 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000751 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000752
Steve Frenchd12fd122007-10-03 19:43:19 +0000753 return;
754}
Steve French953f8682007-10-31 04:54:42 +0000755#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000756
Steve Frencha750e772007-10-17 22:50:39 +0000757static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000758 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000759 struct cifs_fattr *fattr, bool mode_from_special_sid)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000760{
761 int i;
762 int num_aces = 0;
763 int acl_size;
764 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000765 struct cifs_ace **ppace;
766
767 /* BB need to add parm so we can store the SID BB */
768
Steve French2b834572007-11-25 10:01:00 +0000769 if (!pdacl) {
770 /* no DACL in the security descriptor, set
771 all the permissions for user/group/other */
Shyam Prasad N0f220532020-08-17 03:23:12 -0700772 fattr->cf_mode |= 0777;
Steve French2b834572007-11-25 10:01:00 +0000773 return;
774 }
775
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000776 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000777 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500778 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000779 return;
780 }
781
Joe Perchesf96637b2013-05-04 22:12:25 -0500782 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
783 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
784 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000785
Steve French7505e052007-11-01 18:03:01 +0000786 /* reset rwx permissions for user/group/other.
787 Also, if num_aces is 0 i.e. DACL has no ACEs,
788 user/group/other have no permissions */
Shyam Prasad N0f220532020-08-17 03:23:12 -0700789 fattr->cf_mode &= ~(0777);
Steve French7505e052007-11-01 18:03:01 +0000790
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000791 acl_base = (char *)pdacl;
792 acl_size = sizeof(struct cifs_acl);
793
Steve Frenchadbc0352007-10-17 02:12:46 +0000794 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500795 if (num_aces > 0) {
Shyam Prasad N0f220532020-08-17 03:23:12 -0700796 umode_t denied_mode = 0;
Steve French15b03952007-11-08 17:57:40 +0000797
Dan Carpenter72501702012-01-11 10:46:27 +0300798 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
799 return;
Kees Cook6da2ec52018-06-12 13:55:00 -0700800 ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
801 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500802 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300803 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000804
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000805 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000806 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000807#ifdef CONFIG_CIFS_DEBUG2
808 dump_ace(ppace[i], end_of_acl);
809#endif
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000810 if (mode_from_special_sid &&
811 (compare_sids(&(ppace[i]->sid),
812 &sid_unix_NFS_mode) == 0)) {
813 /*
814 * Full permissions are:
815 * 07777 = S_ISUID | S_ISGID | S_ISVTX |
816 * S_IRWXU | S_IRWXG | S_IRWXO
817 */
818 fattr->cf_mode &= ~07777;
819 fattr->cf_mode |=
820 le32_to_cpu(ppace[i]->sid.sub_auth[2]);
821 break;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700822 } else {
823 if (compare_sids(&(ppace[i]->sid), pownersid) == 0) {
824 access_flags_to_mode(ppace[i]->access_req,
825 ppace[i]->type,
826 &fattr->cf_mode,
827 &denied_mode,
828 ACL_OWNER_MASK);
829 } else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) {
830 access_flags_to_mode(ppace[i]->access_req,
831 ppace[i]->type,
832 &fattr->cf_mode,
833 &denied_mode,
834 ACL_GROUP_MASK);
835 } else if ((compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) ||
836 (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)) {
837 access_flags_to_mode(ppace[i]->access_req,
838 ppace[i]->type,
839 &fattr->cf_mode,
840 &denied_mode,
841 ACL_EVERYONE_MASK);
842 }
843 }
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600844
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000845
Steve French44093ca2007-10-23 21:22:55 +0000846/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000847 (void *)ppace[i],
848 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000849
Steve French44093ca2007-10-23 21:22:55 +0000850 acl_base = (char *)ppace[i];
851 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000852 }
853
854 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000855 }
856
857 return;
858}
859
Steve French643fbce2020-01-16 19:55:33 -0600860unsigned int setup_authusers_ACE(struct cifs_ace *pntace)
861{
862 int i;
863 unsigned int ace_size = 20;
864
865 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
866 pntace->flags = 0x0;
867 pntace->access_req = cpu_to_le32(GENERIC_ALL);
868 pntace->sid.num_subauth = 1;
869 pntace->sid.revision = 1;
870 for (i = 0; i < NUM_AUTHS; i++)
871 pntace->sid.authority[i] = sid_authusers.authority[i];
872
873 pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0];
874
875 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
876 pntace->size = cpu_to_le16(ace_size);
877 return ace_size;
878}
879
Steve Frenchfdef6652019-12-06 02:02:38 -0600880/*
881 * Fill in the special SID based on the mode. See
Alexander A. Klimovcba22b12020-06-27 12:31:25 +0200882 * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve Frenchfdef6652019-12-06 02:02:38 -0600883 */
884unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
885{
886 int i;
887 unsigned int ace_size = 28;
888
889 pntace->type = ACCESS_DENIED_ACE_TYPE;
890 pntace->flags = 0x0;
891 pntace->access_req = 0;
892 pntace->sid.num_subauth = 3;
893 pntace->sid.revision = 1;
894 for (i = 0; i < NUM_AUTHS; i++)
895 pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
896
897 pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
898 pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
899 pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
900
901 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
902 pntace->size = cpu_to_le16(ace_size);
903 return ace_size;
904}
Steve Frenchbcb02032007-09-25 16:17:24 +0000905
Steve French975221e2020-06-12 09:25:21 -0500906unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace)
907{
908 int i;
909 unsigned int ace_size = 28;
910
911 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
912 pntace->flags = 0x0;
913 pntace->access_req = cpu_to_le32(GENERIC_ALL);
914 pntace->sid.num_subauth = 3;
915 pntace->sid.revision = 1;
916 for (i = 0; i < NUM_AUTHS; i++)
917 pntace->sid.authority[i] = sid_unix_NFS_users.authority[i];
918
919 pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0];
920 pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1];
921 pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val);
922
923 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
924 pntace->size = cpu_to_le16(ace_size);
925 return ace_size;
926}
927
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800928static void populate_new_aces(char *nacl_base,
929 struct cifs_sid *pownersid,
930 struct cifs_sid *pgrpsid,
931 __u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
932 bool modefromsid)
Steve French97837582007-12-31 07:47:21 +0000933{
Shyam Prasad N0f220532020-08-17 03:23:12 -0700934 __u64 nmode;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800935 u32 num_aces = 0;
936 u16 nsize = 0;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700937 __u64 user_mode;
938 __u64 group_mode;
939 __u64 other_mode;
940 __u64 deny_user_mode = 0;
941 __u64 deny_group_mode = 0;
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800942 bool sticky_set = false;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800943 struct cifs_ace *pnntace = NULL;
Steve French97837582007-12-31 07:47:21 +0000944
Shyam Prasad N0f220532020-08-17 03:23:12 -0700945 nmode = *pnmode;
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800946 num_aces = *pnum_aces;
947 nsize = *pnsize;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700948
Steve French22442172019-07-19 08:15:55 +0000949 if (modefromsid) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800950 pnntace = (struct cifs_ace *) (nacl_base + nsize);
951 nsize += setup_special_mode_ACE(pnntace, nmode);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200952 num_aces++;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700953 goto set_size;
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200954 }
Steve French22442172019-07-19 08:15:55 +0000955
Shyam Prasad N0f220532020-08-17 03:23:12 -0700956 /*
957 * We'll try to keep the mode as requested by the user.
958 * But in cases where we cannot meaningfully convert that
959 * into ACL, return back the updated mode, so that it is
960 * updated in the inode.
961 */
962
963 if (!memcmp(pownersid, pgrpsid, sizeof(struct cifs_sid))) {
964 /*
965 * Case when owner and group SIDs are the same.
966 * Set the more restrictive of the two modes.
967 */
968 user_mode = nmode & (nmode << 3) & 0700;
969 group_mode = nmode & (nmode >> 3) & 0070;
970 } else {
971 user_mode = nmode & 0700;
972 group_mode = nmode & 0070;
973 }
974
975 other_mode = nmode & 0007;
976
977 /* We need DENY ACE when the perm is more restrictive than the next sets. */
978 deny_user_mode = ~(user_mode) & ((group_mode << 3) | (other_mode << 6)) & 0700;
979 deny_group_mode = ~(group_mode) & (other_mode << 3) & 0070;
980
981 *pnmode = user_mode | group_mode | other_mode | (nmode & ~0777);
982
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800983 /* This tells if we should allow delete child for group and everyone. */
984 if (nmode & 01000)
985 sticky_set = true;
986
Shyam Prasad N0f220532020-08-17 03:23:12 -0700987 if (deny_user_mode) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800988 pnntace = (struct cifs_ace *) (nacl_base + nsize);
989 nsize += fill_ace_for_sid(pnntace, pownersid, deny_user_mode,
990 0700, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700991 num_aces++;
992 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800993
Shyam Prasad N0f220532020-08-17 03:23:12 -0700994 /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/
995 if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -0800996 pnntace = (struct cifs_ace *) (nacl_base + nsize);
997 nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode,
998 0070, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700999 num_aces++;
1000 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001001
1002 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1003 nsize += fill_ace_for_sid(pnntace, pownersid, user_mode,
1004 0700, ACCESS_ALLOWED, true);
Shyam Prasad N0f220532020-08-17 03:23:12 -07001005 num_aces++;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001006
Shyam Prasad N0f220532020-08-17 03:23:12 -07001007 /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */
1008 if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001009 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1010 nsize += fill_ace_for_sid(pnntace, pgrpsid, deny_group_mode,
1011 0070, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -07001012 num_aces++;
1013 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001014
1015 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1016 nsize += fill_ace_for_sid(pnntace, pgrpsid, group_mode,
1017 0070, ACCESS_ALLOWED, !sticky_set);
Aurelien Aptele37a02c2019-09-17 01:47:27 +02001018 num_aces++;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001019
1020 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1021 nsize += fill_ace_for_sid(pnntace, &sid_everyone, other_mode,
1022 0007, ACCESS_ALLOWED, !sticky_set);
Aurelien Aptele37a02c2019-09-17 01:47:27 +02001023 num_aces++;
1024
Shyam Prasad N0f220532020-08-17 03:23:12 -07001025set_size:
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001026 *pnum_aces = num_aces;
1027 *pnsize = nsize;
1028}
1029
1030static __u16 replace_sids_and_copy_aces(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
1031 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
1032 struct cifs_sid *pnownersid, struct cifs_sid *pngrpsid)
1033{
1034 int i;
1035 u16 size = 0;
1036 struct cifs_ace *pntace = NULL;
1037 char *acl_base = NULL;
1038 u32 src_num_aces = 0;
1039 u16 nsize = 0;
1040 struct cifs_ace *pnntace = NULL;
1041 char *nacl_base = NULL;
1042 u16 ace_size = 0;
1043
1044 acl_base = (char *)pdacl;
1045 size = sizeof(struct cifs_acl);
1046 src_num_aces = le32_to_cpu(pdacl->num_aces);
1047
1048 nacl_base = (char *)pndacl;
1049 nsize = sizeof(struct cifs_acl);
1050
1051 /* Go through all the ACEs */
1052 for (i = 0; i < src_num_aces; ++i) {
1053 pntace = (struct cifs_ace *) (acl_base + size);
1054 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1055
1056 if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0)
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001057 ace_size = cifs_copy_ace(pnntace, pntace, pnownersid);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001058 else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0)
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001059 ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001060 else
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001061 ace_size = cifs_copy_ace(pnntace, pntace, NULL);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001062
1063 size += le16_to_cpu(pntace->size);
1064 nsize += ace_size;
1065 }
1066
1067 return nsize;
1068}
1069
1070static int set_chmod_dacl(struct cifs_acl *pdacl, struct cifs_acl *pndacl,
1071 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
1072 __u64 *pnmode, bool mode_from_sid)
1073{
1074 int i;
1075 u16 size = 0;
1076 struct cifs_ace *pntace = NULL;
1077 char *acl_base = NULL;
1078 u32 src_num_aces = 0;
1079 u16 nsize = 0;
1080 struct cifs_ace *pnntace = NULL;
1081 char *nacl_base = NULL;
1082 u32 num_aces = 0;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001083 bool new_aces_set = false;
1084
1085 /* Assuming that pndacl and pnmode are never NULL */
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001086 nacl_base = (char *)pndacl;
1087 nsize = sizeof(struct cifs_acl);
1088
1089 /* If pdacl is NULL, we don't have a src. Simply populate new ACL. */
1090 if (!pdacl) {
1091 populate_new_aces(nacl_base,
1092 pownersid, pgrpsid,
1093 pnmode, &num_aces, &nsize,
1094 mode_from_sid);
1095 goto finalize_dacl;
1096 }
1097
1098 acl_base = (char *)pdacl;
1099 size = sizeof(struct cifs_acl);
1100 src_num_aces = le32_to_cpu(pdacl->num_aces);
1101
1102 /* Retain old ACEs which we can retain */
1103 for (i = 0; i < src_num_aces; ++i) {
1104 pntace = (struct cifs_ace *) (acl_base + size);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001105
1106 if (!new_aces_set && (pntace->flags & INHERITED_ACE)) {
1107 /* Place the new ACEs in between existing explicit and inherited */
1108 populate_new_aces(nacl_base,
1109 pownersid, pgrpsid,
1110 pnmode, &num_aces, &nsize,
1111 mode_from_sid);
1112
1113 new_aces_set = true;
1114 }
1115
1116 /* If it's any one of the ACE we're replacing, skip! */
Shyam Prasad N3bffbe92021-03-26 10:28:16 +00001117 if (((compare_sids(&pntace->sid, &sid_unix_NFS_mode) == 0) ||
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001118 (compare_sids(&pntace->sid, pownersid) == 0) ||
1119 (compare_sids(&pntace->sid, pgrpsid) == 0) ||
1120 (compare_sids(&pntace->sid, &sid_everyone) == 0) ||
Shyam Prasad N51713172021-03-10 10:22:27 +00001121 (compare_sids(&pntace->sid, &sid_authusers) == 0))) {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001122 goto next_ace;
1123 }
1124
Shyam Prasad N51713172021-03-10 10:22:27 +00001125 /* update the pointer to the next ACE to populate*/
1126 pnntace = (struct cifs_ace *) (nacl_base + nsize);
1127
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001128 nsize += cifs_copy_ace(pnntace, pntace, NULL);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001129 num_aces++;
1130
1131next_ace:
Steve French23bda5e2021-02-22 14:40:43 -06001132 size += le16_to_cpu(pntace->size);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001133 }
1134
1135 /* If inherited ACEs are not present, place the new ones at the tail */
1136 if (!new_aces_set) {
1137 populate_new_aces(nacl_base,
1138 pownersid, pgrpsid,
1139 pnmode, &num_aces, &nsize,
1140 mode_from_sid);
1141
1142 new_aces_set = true;
1143 }
1144
1145finalize_dacl:
Aurelien Aptele37a02c2019-09-17 01:47:27 +02001146 pndacl->num_aces = cpu_to_le32(num_aces);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001147 pndacl->size = cpu_to_le16(nsize);
Steve French97837582007-12-31 07:47:21 +00001148
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001149 return 0;
Steve French97837582007-12-31 07:47:21 +00001150}
1151
Steve Frenchbcb02032007-09-25 16:17:24 +00001152static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
1153{
1154 /* BB need to add parm so we can store the SID BB */
1155
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001156 /* validate that we do not go past end of ACL - sid must be at least 8
1157 bytes long (assuming no sub-auths - e.g. the null SID */
1158 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001159 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +00001160 return -EINVAL;
1161 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001162
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001163#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001164 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +00001165 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -05001166 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
1167 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001168
Steve Frenchaf6f4612007-10-16 18:40:37 +00001169 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001170 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
1171 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001172 }
1173
Steve Frenchd12fd122007-10-03 19:43:19 +00001174 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001175 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -05001176 cifs_dbg(FYI, "RID 0x%x\n",
1177 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001178 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001179#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001180
Steve Frenchbcb02032007-09-25 16:17:24 +00001181 return 0;
1182}
1183
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001184
Steve Frenchbcb02032007-09-25 16:17:24 +00001185/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001186static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001187 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
1188 bool get_mode_from_special_sid)
Steve Frenchbcb02032007-09-25 16:17:24 +00001189{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001190 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001191 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1192 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001193 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001194 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001195
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001196 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001197 return -EIO;
1198
Steve Frenchbcb02032007-09-25 16:17:24 +00001199 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001200 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001201 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001202 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001203 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001204 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05001205 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 +00001206 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1207 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001208 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001209/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001210 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001211 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001212 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001213 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001214 }
1215 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1216 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001217 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
1218 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001219 return rc;
1220 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001221
1222 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001223 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001224 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
1225 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001226 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001227 }
1228 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1229 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001230 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
1231 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001232 return rc;
1233 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001234
Steve French7505e052007-11-01 18:03:01 +00001235 if (dacloffset)
1236 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001237 group_sid_ptr, fattr, get_mode_from_special_sid);
Steve French7505e052007-11-01 18:03:01 +00001238 else
Joe Perchesf96637b2013-05-04 22:12:25 -05001239 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001240
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001241 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001242}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001243
Steve French97837582007-12-31 07:47:21 +00001244/* Convert permission bits from mode to equivalent CIFS ACL */
1245static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001246 __u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
Steve Frencha6603392020-06-12 10:36:37 -05001247 bool mode_from_sid, bool id_from_sid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001248{
1249 int rc = 0;
1250 __u32 dacloffset;
1251 __u32 ndacloffset;
1252 __u32 sidsoffset;
1253 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001254 struct cifs_sid *nowner_sid_ptr = NULL, *ngroup_sid_ptr = NULL;
Steve French97837582007-12-31 07:47:21 +00001255 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1256 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001257 char *end_of_acl = ((char *)pntsd) + secdesclen;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001258 u16 size = 0;
1259
1260 dacloffset = le32_to_cpu(pntsd->dacloffset);
1261 if (dacloffset) {
1262 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1263 if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) {
Shyam Prasad Nf1ebe482021-02-24 15:04:02 +00001264 cifs_dbg(VFS, "Server returned illegal ACL size\n");
1265 return -EINVAL;
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001266 }
1267 }
1268
1269 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1270 le32_to_cpu(pntsd->osidoffset));
1271 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
1272 le32_to_cpu(pntsd->gsidoffset));
Steve French97837582007-12-31 07:47:21 +00001273
Shyam Prasad N0f220532020-08-17 03:23:12 -07001274 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001275 ndacloffset = sizeof(struct cifs_ntsd);
1276 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001277 ndacl_ptr->revision =
1278 dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
Steve French97837582007-12-31 07:47:21 +00001279
Steve French23bda5e2021-02-22 14:40:43 -06001280 ndacl_ptr->size = cpu_to_le16(0);
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001281 ndacl_ptr->num_aces = cpu_to_le32(0);
1282
1283 rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Shyam Prasad N0f220532020-08-17 03:23:12 -07001284 pnmode, mode_from_sid);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001285
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001286 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001287 /* copy the non-dacl portion of secdesc */
1288 *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
1289 NULL, NULL);
1290
1291 *aclflag |= CIFS_ACL_DACL;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001292 } else {
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001293 ndacloffset = sizeof(struct cifs_ntsd);
1294 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1295 ndacl_ptr->revision =
1296 dacloffset ? dacl_ptr->revision : cpu_to_le16(ACL_REVISION);
Steve Frencha5628262021-06-22 17:54:50 -05001297 ndacl_ptr->num_aces = dacl_ptr ? dacl_ptr->num_aces : 0;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001298
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001299 if (uid_valid(uid)) { /* chown */
1300 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001301 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1302 GFP_KERNEL);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001303 if (!nowner_sid_ptr) {
1304 rc = -ENOMEM;
1305 goto chown_chgrp_exit;
1306 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001307 id = from_kuid(&init_user_ns, uid);
Steve Frencha6603392020-06-12 10:36:37 -05001308 if (id_from_sid) {
1309 struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
1310 /* Populate the user ownership fields S-1-5-88-1 */
1311 osid->Revision = 1;
1312 osid->NumAuth = 3;
1313 osid->Authority[5] = 5;
1314 osid->SubAuthorities[0] = cpu_to_le32(88);
1315 osid->SubAuthorities[1] = cpu_to_le32(1);
1316 osid->SubAuthorities[2] = cpu_to_le32(id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001317
Steve Frencha6603392020-06-12 10:36:37 -05001318 } else { /* lookup sid with upcall */
1319 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
1320 if (rc) {
1321 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
1322 __func__, rc, id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001323 goto chown_chgrp_exit;
Steve Frencha6603392020-06-12 10:36:37 -05001324 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001325 }
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001326 *aclflag |= CIFS_ACL_OWNER;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001327 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001328 if (gid_valid(gid)) { /* chgrp */
1329 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001330 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1331 GFP_KERNEL);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001332 if (!ngroup_sid_ptr) {
1333 rc = -ENOMEM;
1334 goto chown_chgrp_exit;
1335 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001336 id = from_kgid(&init_user_ns, gid);
Steve Frencha6603392020-06-12 10:36:37 -05001337 if (id_from_sid) {
1338 struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
1339 /* Populate the group ownership fields S-1-5-88-2 */
1340 gsid->Revision = 1;
1341 gsid->NumAuth = 3;
1342 gsid->Authority[5] = 5;
1343 gsid->SubAuthorities[0] = cpu_to_le32(88);
1344 gsid->SubAuthorities[1] = cpu_to_le32(2);
1345 gsid->SubAuthorities[2] = cpu_to_le32(id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001346
Steve Frencha6603392020-06-12 10:36:37 -05001347 } else { /* lookup sid with upcall */
1348 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
1349 if (rc) {
1350 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
1351 __func__, rc, id);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001352 goto chown_chgrp_exit;
Steve Frencha6603392020-06-12 10:36:37 -05001353 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001354 }
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001355 *aclflag |= CIFS_ACL_GROUP;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001356 }
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001357
1358 if (dacloffset) {
1359 /* Replace ACEs for old owner with new one */
1360 size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
1361 owner_sid_ptr, group_sid_ptr,
1362 nowner_sid_ptr, ngroup_sid_ptr);
1363 ndacl_ptr->size = cpu_to_le16(size);
1364 }
1365
1366 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1367 /* copy the non-dacl portion of secdesc */
1368 *pnsecdesclen = copy_sec_desc(pntsd, pnntsd, sidsoffset,
1369 nowner_sid_ptr, ngroup_sid_ptr);
1370
1371chown_chgrp_exit:
1372 /* errors could jump here. So make sure we return soon after this */
1373 kfree(nowner_sid_ptr);
1374 kfree(ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001375 }
Steve French97837582007-12-31 07:47:21 +00001376
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001377 return rc;
Steve French97837582007-12-31 07:47:21 +00001378}
1379
Steve French42eacf92014-02-10 14:08:16 -06001380struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
Boris Protopopov3970acf2020-12-18 11:30:12 -06001381 const struct cifs_fid *cifsfid, u32 *pacllen,
1382 u32 __maybe_unused unused)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001383{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001384 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001385 unsigned int xid;
1386 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001387 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1388
1389 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001390 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001391
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001392 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001393 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1394 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001395 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001396
Jeff Layton7ffec372010-09-29 19:51:11 -04001397 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001398
Joe Perchesf96637b2013-05-04 22:12:25 -05001399 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001400 if (rc)
1401 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001402 return pntsd;
1403}
1404
1405static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1406 const char *path, u32 *pacllen)
1407{
1408 struct cifs_ntsd *pntsd = NULL;
1409 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001410 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001411 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00001412 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001413 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001414 struct cifs_fid fid;
1415 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001416
Jeff Layton7ffec372010-09-29 19:51:11 -04001417 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001418 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001419
1420 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001421 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001422
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001423 oparms.tcon = tcon;
1424 oparms.cifs_sb = cifs_sb;
1425 oparms.desired_access = READ_CONTROL;
Amir Goldstein0f060932020-02-03 21:46:43 +02001426 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001427 oparms.disposition = FILE_OPEN;
1428 oparms.path = path;
1429 oparms.fid = &fid;
1430 oparms.reconnect = false;
1431
1432 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001433 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001434 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1435 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001436 }
1437
Jeff Layton7ffec372010-09-29 19:51:11 -04001438 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001439 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001440
Joe Perchesf96637b2013-05-04 22:12:25 -05001441 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001442 if (rc)
1443 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001444 return pntsd;
1445}
1446
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001447/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001448struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001449 struct inode *inode, const char *path,
Boris Protopopov3970acf2020-12-18 11:30:12 -06001450 u32 *pacllen, u32 info)
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001451{
1452 struct cifs_ntsd *pntsd = NULL;
1453 struct cifsFileInfo *open_file = NULL;
1454
1455 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001456 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001457 if (!open_file)
1458 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1459
Boris Protopopov3970acf2020-12-18 11:30:12 -06001460 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001461 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001462 return pntsd;
1463}
1464
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001465 /* Set an ACL on the server */
1466int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1467 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001468{
1469 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001470 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001471 int rc, access_flags;
Steve French96daf2b2011-05-27 04:34:02 +00001472 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001473 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001474 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001475 struct cifs_fid fid;
1476 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001477
Jeff Layton7ffec372010-09-29 19:51:11 -04001478 if (IS_ERR(tlink))
1479 return PTR_ERR(tlink);
1480
1481 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001482 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001483
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001484 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1485 access_flags = WRITE_OWNER;
1486 else
1487 access_flags = WRITE_DAC;
1488
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001489 oparms.tcon = tcon;
1490 oparms.cifs_sb = cifs_sb;
1491 oparms.desired_access = access_flags;
Amir Goldstein0f060932020-02-03 21:46:43 +02001492 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001493 oparms.disposition = FILE_OPEN;
1494 oparms.path = path;
1495 oparms.fid = &fid;
1496 oparms.reconnect = false;
1497
1498 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001499 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001500 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001501 goto out;
Steve French97837582007-12-31 07:47:21 +00001502 }
1503
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001504 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001505 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001506
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001507 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001508out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001509 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001510 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001511 return rc;
1512}
Steve French97837582007-12-31 07:47:21 +00001513
Achilles Gaikwad36c7ce42018-01-28 13:39:48 +05301514/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001515int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001516cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001517 struct inode *inode, bool mode_from_special_sid,
1518 const char *path, const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001519{
1520 struct cifs_ntsd *pntsd = NULL;
1521 u32 acllen = 0;
1522 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001523 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001524 struct smb_version_operations *ops;
Boris Protopopov3970acf2020-12-18 11:30:12 -06001525 const u32 info = 0;
Steve French7505e052007-11-01 18:03:01 +00001526
Joe Perchesf96637b2013-05-04 22:12:25 -05001527 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001528
Steve French42eacf92014-02-10 14:08:16 -06001529 if (IS_ERR(tlink))
1530 return PTR_ERR(tlink);
Steve French7505e052007-11-01 18:03:01 +00001531
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001532 ops = tlink_tcon(tlink)->ses->server->ops;
1533
1534 if (pfid && (ops->get_acl_by_fid))
Boris Protopopov3970acf2020-12-18 11:30:12 -06001535 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001536 else if (ops->get_acl)
Boris Protopopov3970acf2020-12-18 11:30:12 -06001537 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info);
Steve French42eacf92014-02-10 14:08:16 -06001538 else {
1539 cifs_put_tlink(tlink);
1540 return -EOPNOTSUPP;
1541 }
Steve French7505e052007-11-01 18:03:01 +00001542 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001543 if (IS_ERR(pntsd)) {
1544 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001545 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001546 } else if (mode_from_special_sid) {
1547 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
Namjae Jeon98128572020-11-09 17:35:33 +09001548 kfree(pntsd);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001549 } else {
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001550 /* get approximated mode from ACL */
1551 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001552 kfree(pntsd);
1553 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001554 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001555 }
Steve French7505e052007-11-01 18:03:01 +00001556
Steve French42eacf92014-02-10 14:08:16 -06001557 cifs_put_tlink(tlink);
1558
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001559 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001560}
Steve French953f8682007-10-31 04:54:42 +00001561
Steve French7505e052007-11-01 18:03:01 +00001562/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001563int
Shyam Prasad N0f220532020-08-17 03:23:12 -07001564id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001565 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001566{
1567 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001568 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001569 __u32 secdesclen = 0;
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001570 __u32 nsecdesclen = 0;
1571 __u32 dacloffset = 0;
1572 struct cifs_acl *dacl_ptr = NULL;
Steve French97837582007-12-31 07:47:21 +00001573 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1574 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001575 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1576 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001577 struct smb_version_operations *ops;
Steve Frencha6603392020-06-12 10:36:37 -05001578 bool mode_from_sid, id_from_sid;
Boris Protopopov3970acf2020-12-18 11:30:12 -06001579 const u32 info = 0;
Steve French83e3bc22014-02-02 23:31:47 -06001580
1581 if (IS_ERR(tlink))
1582 return PTR_ERR(tlink);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001583
1584 ops = tlink_tcon(tlink)->ses->server->ops;
Steve French953f8682007-10-31 04:54:42 +00001585
Joe Perchesf96637b2013-05-04 22:12:25 -05001586 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001587
1588 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001589
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001590 if (ops->get_acl == NULL) {
Steve French83e3bc22014-02-02 23:31:47 -06001591 cifs_put_tlink(tlink);
1592 return -EOPNOTSUPP;
1593 }
1594
Boris Protopopov3970acf2020-12-18 11:30:12 -06001595 pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001596 if (IS_ERR(pntsd)) {
1597 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001598 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001599 cifs_put_tlink(tlink);
1600 return rc;
Steve French97837582007-12-31 07:47:21 +00001601 }
1602
Steve French22442172019-07-19 08:15:55 +00001603 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
1604 mode_from_sid = true;
1605 else
1606 mode_from_sid = false;
1607
Steve Frencha6603392020-06-12 10:36:37 -05001608 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
1609 id_from_sid = true;
1610 else
1611 id_from_sid = false;
1612
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001613 /* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
1614 nsecdesclen = secdesclen;
1615 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
1616 if (mode_from_sid)
1617 nsecdesclen += sizeof(struct cifs_ace);
1618 else /* cifsacl */
1619 nsecdesclen += 5 * sizeof(struct cifs_ace);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001620 } else { /* chown */
1621 /* When ownership changes, changes new owner sid length could be different */
1622 nsecdesclen = sizeof(struct cifs_ntsd) + (sizeof(struct cifs_sid) * 2);
1623 dacloffset = le32_to_cpu(pntsd->dacloffset);
1624 if (dacloffset) {
1625 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1626 if (mode_from_sid)
1627 nsecdesclen +=
Steve French23bda5e2021-02-22 14:40:43 -06001628 le32_to_cpu(dacl_ptr->num_aces) * sizeof(struct cifs_ace);
Shyam Prasad Nbc3e9dd2021-02-18 13:03:23 +00001629 else /* cifsacl */
1630 nsecdesclen += le16_to_cpu(dacl_ptr->size);
1631 }
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001632 }
1633
1634 /*
1635 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1636 * as chmod disables ACEs and set the security descriptor. Allocate
1637 * memory for the smb header, set security descriptor request security
jack1.li_cpc45adff2021-04-09 22:00:37 -05001638 * descriptor parameters, and security descriptor itself
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001639 */
1640 nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN);
1641 pnntsd = kmalloc(nsecdesclen, GFP_KERNEL);
1642 if (!pnntsd) {
1643 kfree(pntsd);
1644 cifs_put_tlink(tlink);
1645 return -ENOMEM;
1646 }
1647
1648 rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid,
Steve Frencha6603392020-06-12 10:36:37 -05001649 mode_from_sid, id_from_sid, &aclflag);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001650
Joe Perchesf96637b2013-05-04 22:12:25 -05001651 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001652
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001653 if (ops->set_acl == NULL)
Steve French83e3bc22014-02-02 23:31:47 -06001654 rc = -EOPNOTSUPP;
1655
Jeff Laytonc78cd832012-11-25 08:00:35 -05001656 if (!rc) {
1657 /* Set the security descriptor */
Shyam Prasad Nf5065502021-02-12 04:38:43 -08001658 rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001659 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001660 }
Steve French83e3bc22014-02-02 23:31:47 -06001661 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001662
1663 kfree(pnntsd);
1664 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001665 return rc;
Steve French953f8682007-10-31 04:54:42 +00001666}