blob: 562913e2b3f2e21d9718ed3aa8e9976d2982657b [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
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500270static void
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;
274
275 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500276 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500277 for (i = 0; i < NUM_AUTHS; ++i)
278 dst->authority[i] = src->authority[i];
279 for (i = 0; i < dst->num_subauth; ++i)
280 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400281}
282
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500283static int
284id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500285{
286 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500287 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500288 struct cifs_sid *ksid;
289 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500290 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500291 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500292
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500293 rc = snprintf(desc, sizeof(desc), "%ci:%u",
294 sidtype == SIDOWNER ? 'o' : 'g', cid);
295 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500296 return -EINVAL;
297
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500298 rc = 0;
299 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700300 sidkey = request_key(&cifs_idmap_key_type, desc, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500301 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500302 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500303 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
304 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500305 goto out_revert_creds;
306 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
307 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500308 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
309 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500310 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500311 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500312
Jeff Layton1f630682012-12-03 06:05:31 -0500313 /*
314 * A sid is usually too large to be embedded in payload.value, but if
315 * there are no subauthorities and the host has 8-byte pointers, then
316 * it could be.
317 */
318 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
David Howells146aa8b2015-10-21 14:04:48 +0100319 (struct cifs_sid *)&sidkey->payload :
320 (struct cifs_sid *)sidkey->payload.data[0];
Jeff Layton1f630682012-12-03 06:05:31 -0500321
Jeff Layton2ae03022012-12-03 06:05:30 -0500322 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
323 if (ksid_size > sidkey->datalen) {
324 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500325 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
326 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500327 goto invalidate_key;
328 }
Jeff Layton1f630682012-12-03 06:05:31 -0500329
Jeff Layton2ae03022012-12-03 06:05:30 -0500330 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500331out_key_put:
332 key_put(sidkey);
333out_revert_creds:
334 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500335 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500336
337invalidate_key:
338 key_invalidate(sidkey);
339 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500340}
341
Steve French99344302020-10-20 02:02:02 -0500342int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500343sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
344 struct cifs_fattr *fattr, uint sidtype)
345{
Qiujun Huangf2d67932020-03-04 15:42:51 +0800346 int rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500347 struct key *sidkey;
348 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500349 const struct cred *saved_cred;
Ronnie Sahlberg8401e932020-12-12 13:40:50 -0600350 kuid_t fuid = cifs_sb->ctx->linux_uid;
351 kgid_t fgid = cifs_sb->ctx->linux_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500352
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500353 /*
354 * If we have too many subauthorities, then something is really wrong.
355 * Just return an error.
356 */
357 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500358 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
359 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500360 return -EIO;
361 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500362
Steve French99344302020-10-20 02:02:02 -0500363 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
364 (cifs_sb_master_tcon(cifs_sb)->posix_extensions)) {
Steve French3514de32016-10-13 19:06:23 -0500365 uint32_t unix_id;
366 bool is_group;
367
368 if (sidtype != SIDOWNER)
369 is_group = true;
370 else
371 is_group = false;
372
373 if (is_well_known_sid(psid, &unix_id, is_group) == false)
374 goto try_upcall_to_get_id;
375
376 if (is_group) {
377 kgid_t gid;
378 gid_t id;
379
380 id = (gid_t)unix_id;
381 gid = make_kgid(&init_user_ns, id);
382 if (gid_valid(gid)) {
383 fgid = gid;
384 goto got_valid_id;
385 }
386 } else {
387 kuid_t uid;
388 uid_t id;
389
390 id = (uid_t)unix_id;
391 uid = make_kuid(&init_user_ns, id);
392 if (uid_valid(uid)) {
393 fuid = uid;
394 goto got_valid_id;
395 }
396 }
397 /* If unable to find uid/gid easily from SID try via upcall */
398 }
399
400try_upcall_to_get_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500401 sidstr = sid_to_key_str(psid, sidtype);
402 if (!sidstr)
403 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500404
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500405 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700406 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500407 if (IS_ERR(sidkey)) {
408 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500409 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
410 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500411 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500412 }
413
414 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500415 * FIXME: Here we assume that uid_t and gid_t are same size. It's
416 * probably a safe assumption but might be better to check based on
417 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500418 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800419 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500420 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500421 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500422 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
423 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500424 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500425 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500426 }
427
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800428 if (sidtype == SIDOWNER) {
429 kuid_t uid;
430 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100431 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800432 uid = make_kuid(&init_user_ns, id);
433 if (uid_valid(uid))
434 fuid = uid;
435 } else {
436 kgid_t gid;
437 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100438 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800439 gid = make_kgid(&init_user_ns, id);
440 if (gid_valid(gid))
441 fgid = gid;
442 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500443
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500444out_key_put:
445 key_put(sidkey);
446out_revert_creds:
447 revert_creds(saved_cred);
448 kfree(sidstr);
449
450 /*
451 * Note that we return 0 here unconditionally. If the mapping
Ronnie Sahlberg8401e932020-12-12 13:40:50 -0600452 * fails then we just fall back to using the ctx->linux_uid/linux_gid.
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500453 */
Steve French3514de32016-10-13 19:06:23 -0500454got_valid_id:
Qiujun Huangf2d67932020-03-04 15:42:51 +0800455 rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500456 if (sidtype == SIDOWNER)
457 fattr->cf_uid = fuid;
458 else
459 fattr->cf_gid = fgid;
Qiujun Huangf2d67932020-03-04 15:42:51 +0800460 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500461}
462
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500463int
464init_cifs_idmap(void)
465{
466 struct cred *cred;
467 struct key *keyring;
468 int ret;
469
Joe Perchesf96637b2013-05-04 22:12:25 -0500470 cifs_dbg(FYI, "Registering the %s key type\n",
471 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500472
473 /* create an override credential set with a special thread keyring in
474 * which requests are cached
475 *
476 * this is used to prevent malicious redirections from being installed
477 * with add_key().
478 */
479 cred = prepare_kernel_cred(NULL);
480 if (!cred)
481 return -ENOMEM;
482
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800483 keyring = keyring_alloc(".cifs_idmap",
484 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
Linus Torvalds028db3e2019-07-10 18:43:43 -0700485 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
486 KEY_USR_VIEW | KEY_USR_READ,
David Howells5ac7eac2016-04-06 16:14:24 +0100487 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500488 if (IS_ERR(keyring)) {
489 ret = PTR_ERR(keyring);
490 goto failed_put_cred;
491 }
492
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500493 ret = register_key_type(&cifs_idmap_key_type);
494 if (ret < 0)
495 goto failed_put_key;
496
497 /* instruct request_key() to use this special keyring as a cache for
498 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000499 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500500 cred->thread_keyring = keyring;
501 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
502 root_cred = cred;
503
Joe Perchesf96637b2013-05-04 22:12:25 -0500504 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500505 return 0;
506
507failed_put_key:
508 key_put(keyring);
509failed_put_cred:
510 put_cred(cred);
511 return ret;
512}
513
514void
515exit_cifs_idmap(void)
516{
517 key_revoke(root_cred->thread_keyring);
518 unregister_key_type(&cifs_idmap_key_type);
519 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500520 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500521}
522
Steve French97837582007-12-31 07:47:21 +0000523/* copy ntsd, owner sid, and group sid from a security descriptor to another */
524static void copy_sec_desc(const struct cifs_ntsd *pntsd,
525 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
526{
Steve French97837582007-12-31 07:47:21 +0000527 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
528 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
529
530 /* copy security descriptor control portion */
531 pnntsd->revision = pntsd->revision;
532 pnntsd->type = pntsd->type;
533 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
534 pnntsd->sacloffset = 0;
535 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
536 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
537
538 /* copy owner sid */
539 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
540 le32_to_cpu(pntsd->osidoffset));
541 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400542 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000543
544 /* copy group sid */
545 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
546 le32_to_cpu(pntsd->gsidoffset));
547 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
548 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400549 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000550
551 return;
552}
553
554
Steve French630f3f0c2007-10-25 21:17:17 +0000555/*
556 change posix mode to reflect permissions
557 pmode is the existing mode (we only want to overwrite part of this
558 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
559*/
Al Viro9b5e6852007-12-05 08:24:38 +0000560static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Shyam Prasad N0f220532020-08-17 03:23:12 -0700561 umode_t *pdenied, umode_t mask)
Steve French4879b442007-10-19 21:57:39 +0000562{
Al Viro9b5e6852007-12-05 08:24:38 +0000563 __u32 flags = le32_to_cpu(ace_flags);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700564 /*
565 * Do not assume "preferred" or "canonical" order.
566 * The first DENY or ALLOW ACE which matches perfectly is
567 * the permission to be used. Once allowed or denied, same
568 * permission in later ACEs do not matter.
569 */
Steve French15b03952007-11-08 17:57:40 +0000570
Shyam Prasad N0f220532020-08-17 03:23:12 -0700571 /* If not already allowed, deny these bits */
Steve French15b03952007-11-08 17:57:40 +0000572 if (type == ACCESS_DENIED) {
Shyam Prasad N0f220532020-08-17 03:23:12 -0700573 if (flags & GENERIC_ALL &&
574 !(*pmode & mask & 0777))
575 *pdenied |= mask & 0777;
Steve Frenchad7a2922008-02-07 23:25:02 +0000576
Shyam Prasad N0f220532020-08-17 03:23:12 -0700577 if (((flags & GENERIC_WRITE) ||
578 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) &&
579 !(*pmode & mask & 0222))
580 *pdenied |= mask & 0222;
581
582 if (((flags & GENERIC_READ) ||
583 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) &&
584 !(*pmode & mask & 0444))
585 *pdenied |= mask & 0444;
586
587 if (((flags & GENERIC_EXECUTE) ||
588 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) &&
589 !(*pmode & mask & 0111))
590 *pdenied |= mask & 0111;
591
Steve French15b03952007-11-08 17:57:40 +0000592 return;
593 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500594 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000595 return;
596 }
597 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000598
Shyam Prasad N0f220532020-08-17 03:23:12 -0700599 if ((flags & GENERIC_ALL) &&
600 !(*pdenied & mask & 0777)) {
601 *pmode |= mask & 0777;
Joe Perchesf96637b2013-05-04 22:12:25 -0500602 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000603 return;
604 }
Shyam Prasad N0f220532020-08-17 03:23:12 -0700605
606 if (((flags & GENERIC_WRITE) ||
607 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS)) &&
608 !(*pdenied & mask & 0222))
609 *pmode |= mask & 0222;
610
611 if (((flags & GENERIC_READ) ||
612 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS)) &&
613 !(*pdenied & mask & 0444))
614 *pmode |= mask & 0444;
615
616 if (((flags & GENERIC_EXECUTE) ||
617 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS)) &&
618 !(*pdenied & mask & 0111))
619 *pmode |= mask & 0111;
Steve Frenchd61e5802007-10-26 04:32:43 +0000620
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800621 /* If DELETE_CHILD is set only on an owner ACE, set sticky bit */
622 if (flags & FILE_DELETE_CHILD) {
623 if (mask == ACL_OWNER_MASK) {
624 if (!(*pdenied & 01000))
625 *pmode |= 01000;
626 } else if (!(*pdenied & 01000)) {
627 *pmode &= ~01000;
628 *pdenied |= 01000;
629 }
630 }
631
Frank Sorensonf52aa792020-02-12 15:31:48 -0600632 cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000633 return;
634}
635
Steve Frenchce06c9f2007-11-08 21:12:01 +0000636/*
637 Generate access flags to reflect permissions mode is the existing mode.
638 This function is called for every ACE in the DACL whose SID matches
639 with either owner or group or everyone.
640*/
641
642static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
643 __u32 *pace_flags)
644{
645 /* reset access mask */
646 *pace_flags = 0x0;
647
648 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
649 mode &= bits_to_use;
650
651 /* check for R/W/X UGO since we do not know whose flags
652 is this but we have cleared all the bits sans RWX for
653 either user or group or other as per bits_to_use */
654 if (mode & S_IRUGO)
655 *pace_flags |= SET_FILE_READ_RIGHTS;
656 if (mode & S_IWUGO)
657 *pace_flags |= SET_FILE_WRITE_RIGHTS;
658 if (mode & S_IXUGO)
659 *pace_flags |= SET_FILE_EXEC_RIGHTS;
660
Frank Sorensonf52aa792020-02-12 15:31:48 -0600661 cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n",
Joe Perchesf96637b2013-05-04 22:12:25 -0500662 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000663 return;
664}
665
Al Viro2b210ad2008-03-29 03:09:18 +0000666static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800667 const struct cifs_sid *psid, __u64 nmode,
668 umode_t bits, __u8 access_type,
669 bool allow_delete_child)
Steve French97837582007-12-31 07:47:21 +0000670{
671 int i;
672 __u16 size = 0;
673 __u32 access_req = 0;
674
Shyam Prasad N0f220532020-08-17 03:23:12 -0700675 pntace->type = access_type;
Steve French97837582007-12-31 07:47:21 +0000676 pntace->flags = 0x0;
677 mode_to_access_flags(nmode, bits, &access_req);
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800678
679 if (access_type == ACCESS_ALLOWED && allow_delete_child)
680 access_req |= FILE_DELETE_CHILD;
681
Shyam Prasad N0f220532020-08-17 03:23:12 -0700682 if (access_type == ACCESS_ALLOWED && !access_req)
Steve French97837582007-12-31 07:47:21 +0000683 access_req = SET_MINIMUM_RIGHTS;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700684 else if (access_type == ACCESS_DENIED)
685 access_req &= ~SET_MINIMUM_RIGHTS;
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800686
Steve French97837582007-12-31 07:47:21 +0000687 pntace->access_req = cpu_to_le32(access_req);
688
689 pntace->sid.revision = psid->revision;
690 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500691 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000692 pntace->sid.authority[i] = psid->authority[i];
693 for (i = 0; i < psid->num_subauth; i++)
694 pntace->sid.sub_auth[i] = psid->sub_auth[i];
695
696 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
697 pntace->size = cpu_to_le16(size);
698
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000699 return size;
Steve French97837582007-12-31 07:47:21 +0000700}
701
Steve French297647c2007-10-12 04:11:59 +0000702
Steve French953f8682007-10-31 04:54:42 +0000703#ifdef CONFIG_CIFS_DEBUG2
704static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000705{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000706 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000707
708 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000709
Steve French44093ca2007-10-23 21:22:55 +0000710 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500711 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000712 return;
713 }
714
715 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500716 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000717 return;
Steve French44093ca2007-10-23 21:22:55 +0000718 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000719
Steve French44093ca2007-10-23 21:22:55 +0000720 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000721 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000722 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500723 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
724 pace->sid.revision, pace->sid.num_subauth, pace->type,
725 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000726 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500727 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
728 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000729 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000730
Steve Frenchd12fd122007-10-03 19:43:19 +0000731 /* BB add length check to make sure that we do not have huge
732 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000733 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000734
Steve Frenchd12fd122007-10-03 19:43:19 +0000735 return;
736}
Steve French953f8682007-10-31 04:54:42 +0000737#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000738
Steve Frencha750e772007-10-17 22:50:39 +0000739static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000740 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000741 struct cifs_fattr *fattr, bool mode_from_special_sid)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000742{
743 int i;
744 int num_aces = 0;
745 int acl_size;
746 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000747 struct cifs_ace **ppace;
748
749 /* BB need to add parm so we can store the SID BB */
750
Steve French2b834572007-11-25 10:01:00 +0000751 if (!pdacl) {
752 /* no DACL in the security descriptor, set
753 all the permissions for user/group/other */
Shyam Prasad N0f220532020-08-17 03:23:12 -0700754 fattr->cf_mode |= 0777;
Steve French2b834572007-11-25 10:01:00 +0000755 return;
756 }
757
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000758 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000759 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500760 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000761 return;
762 }
763
Joe Perchesf96637b2013-05-04 22:12:25 -0500764 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
765 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
766 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000767
Steve French7505e052007-11-01 18:03:01 +0000768 /* reset rwx permissions for user/group/other.
769 Also, if num_aces is 0 i.e. DACL has no ACEs,
770 user/group/other have no permissions */
Shyam Prasad N0f220532020-08-17 03:23:12 -0700771 fattr->cf_mode &= ~(0777);
Steve French7505e052007-11-01 18:03:01 +0000772
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000773 acl_base = (char *)pdacl;
774 acl_size = sizeof(struct cifs_acl);
775
Steve Frenchadbc0352007-10-17 02:12:46 +0000776 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500777 if (num_aces > 0) {
Shyam Prasad N0f220532020-08-17 03:23:12 -0700778 umode_t denied_mode = 0;
Steve French15b03952007-11-08 17:57:40 +0000779
Dan Carpenter72501702012-01-11 10:46:27 +0300780 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
781 return;
Kees Cook6da2ec52018-06-12 13:55:00 -0700782 ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
783 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500784 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300785 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000786
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000787 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000788 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000789#ifdef CONFIG_CIFS_DEBUG2
790 dump_ace(ppace[i], end_of_acl);
791#endif
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000792 if (mode_from_special_sid &&
793 (compare_sids(&(ppace[i]->sid),
794 &sid_unix_NFS_mode) == 0)) {
795 /*
796 * Full permissions are:
797 * 07777 = S_ISUID | S_ISGID | S_ISVTX |
798 * S_IRWXU | S_IRWXG | S_IRWXO
799 */
800 fattr->cf_mode &= ~07777;
801 fattr->cf_mode |=
802 le32_to_cpu(ppace[i]->sid.sub_auth[2]);
803 break;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700804 } else {
805 if (compare_sids(&(ppace[i]->sid), pownersid) == 0) {
806 access_flags_to_mode(ppace[i]->access_req,
807 ppace[i]->type,
808 &fattr->cf_mode,
809 &denied_mode,
810 ACL_OWNER_MASK);
811 } else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0) {
812 access_flags_to_mode(ppace[i]->access_req,
813 ppace[i]->type,
814 &fattr->cf_mode,
815 &denied_mode,
816 ACL_GROUP_MASK);
817 } else if ((compare_sids(&(ppace[i]->sid), &sid_everyone) == 0) ||
818 (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)) {
819 access_flags_to_mode(ppace[i]->access_req,
820 ppace[i]->type,
821 &fattr->cf_mode,
822 &denied_mode,
823 ACL_EVERYONE_MASK);
824 }
825 }
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600826
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000827
Steve French44093ca2007-10-23 21:22:55 +0000828/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000829 (void *)ppace[i],
830 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000831
Steve French44093ca2007-10-23 21:22:55 +0000832 acl_base = (char *)ppace[i];
833 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000834 }
835
836 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000837 }
838
839 return;
840}
841
Steve French643fbce2020-01-16 19:55:33 -0600842unsigned int setup_authusers_ACE(struct cifs_ace *pntace)
843{
844 int i;
845 unsigned int ace_size = 20;
846
847 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
848 pntace->flags = 0x0;
849 pntace->access_req = cpu_to_le32(GENERIC_ALL);
850 pntace->sid.num_subauth = 1;
851 pntace->sid.revision = 1;
852 for (i = 0; i < NUM_AUTHS; i++)
853 pntace->sid.authority[i] = sid_authusers.authority[i];
854
855 pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0];
856
857 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
858 pntace->size = cpu_to_le16(ace_size);
859 return ace_size;
860}
861
Steve Frenchfdef6652019-12-06 02:02:38 -0600862/*
863 * Fill in the special SID based on the mode. See
Alexander A. Klimovcba22b12020-06-27 12:31:25 +0200864 * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve Frenchfdef6652019-12-06 02:02:38 -0600865 */
866unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
867{
868 int i;
869 unsigned int ace_size = 28;
870
871 pntace->type = ACCESS_DENIED_ACE_TYPE;
872 pntace->flags = 0x0;
873 pntace->access_req = 0;
874 pntace->sid.num_subauth = 3;
875 pntace->sid.revision = 1;
876 for (i = 0; i < NUM_AUTHS; i++)
877 pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
878
879 pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
880 pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
881 pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
882
883 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
884 pntace->size = cpu_to_le16(ace_size);
885 return ace_size;
886}
Steve Frenchbcb02032007-09-25 16:17:24 +0000887
Steve French975221e2020-06-12 09:25:21 -0500888unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace)
889{
890 int i;
891 unsigned int ace_size = 28;
892
893 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
894 pntace->flags = 0x0;
895 pntace->access_req = cpu_to_le32(GENERIC_ALL);
896 pntace->sid.num_subauth = 3;
897 pntace->sid.revision = 1;
898 for (i = 0; i < NUM_AUTHS; i++)
899 pntace->sid.authority[i] = sid_unix_NFS_users.authority[i];
900
901 pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0];
902 pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1];
903 pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val);
904
905 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
906 pntace->size = cpu_to_le16(ace_size);
907 return ace_size;
908}
909
Steve French97837582007-12-31 07:47:21 +0000910static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
Shyam Prasad N0f220532020-08-17 03:23:12 -0700911 struct cifs_sid *pgrpsid, __u64 *pnmode, bool modefromsid)
Steve French97837582007-12-31 07:47:21 +0000912{
Al Viro2b210ad2008-03-29 03:09:18 +0000913 u16 size = 0;
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200914 u32 num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000915 struct cifs_acl *pnndacl;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700916 __u64 nmode;
917 __u64 user_mode;
918 __u64 group_mode;
919 __u64 other_mode;
920 __u64 deny_user_mode = 0;
921 __u64 deny_group_mode = 0;
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800922 bool sticky_set = false;
Steve French97837582007-12-31 07:47:21 +0000923
924 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
925
Shyam Prasad N0f220532020-08-17 03:23:12 -0700926 nmode = *pnmode;
927
Steve French22442172019-07-19 08:15:55 +0000928 if (modefromsid) {
929 struct cifs_ace *pntace =
930 (struct cifs_ace *)((char *)pnndacl + size);
Steve French22442172019-07-19 08:15:55 +0000931
Steve Frenchfdef6652019-12-06 02:02:38 -0600932 size += setup_special_mode_ACE(pntace, nmode);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200933 num_aces++;
Shyam Prasad N0f220532020-08-17 03:23:12 -0700934 goto set_size;
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200935 }
Steve French22442172019-07-19 08:15:55 +0000936
Shyam Prasad N0f220532020-08-17 03:23:12 -0700937 /*
938 * We'll try to keep the mode as requested by the user.
939 * But in cases where we cannot meaningfully convert that
940 * into ACL, return back the updated mode, so that it is
941 * updated in the inode.
942 */
943
944 if (!memcmp(pownersid, pgrpsid, sizeof(struct cifs_sid))) {
945 /*
946 * Case when owner and group SIDs are the same.
947 * Set the more restrictive of the two modes.
948 */
949 user_mode = nmode & (nmode << 3) & 0700;
950 group_mode = nmode & (nmode >> 3) & 0070;
951 } else {
952 user_mode = nmode & 0700;
953 group_mode = nmode & 0070;
954 }
955
956 other_mode = nmode & 0007;
957
958 /* We need DENY ACE when the perm is more restrictive than the next sets. */
959 deny_user_mode = ~(user_mode) & ((group_mode << 3) | (other_mode << 6)) & 0700;
960 deny_group_mode = ~(group_mode) & (other_mode << 3) & 0070;
961
962 *pnmode = user_mode | group_mode | other_mode | (nmode & ~0777);
963
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800964 /* This tells if we should allow delete child for group and everyone. */
965 if (nmode & 01000)
966 sticky_set = true;
967
Shyam Prasad N0f220532020-08-17 03:23:12 -0700968 if (deny_user_mode) {
969 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800970 pownersid, deny_user_mode, 0700, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700971 num_aces++;
972 }
973 /* Group DENY ACE does not conflict with owner ALLOW ACE. Keep in preferred order*/
974 if (deny_group_mode && !(deny_group_mode & (user_mode >> 3))) {
975 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800976 pgrpsid, deny_group_mode, 0070, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700977 num_aces++;
978 }
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200979 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800980 pownersid, user_mode, 0700, ACCESS_ALLOWED, true);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700981 num_aces++;
982 /* Group DENY ACE conflicts with owner ALLOW ACE. So keep it after. */
983 if (deny_group_mode && (deny_group_mode & (user_mode >> 3))) {
984 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800985 pgrpsid, deny_group_mode, 0070, ACCESS_DENIED, false);
Shyam Prasad N0f220532020-08-17 03:23:12 -0700986 num_aces++;
987 }
988 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800989 pgrpsid, group_mode, 0070, ACCESS_ALLOWED, !sticky_set);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200990 num_aces++;
991 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
Shyam Prasad Nf2156d32020-11-09 06:12:49 -0800992 &sid_everyone, other_mode, 0007, ACCESS_ALLOWED, !sticky_set);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200993 num_aces++;
994
Shyam Prasad N0f220532020-08-17 03:23:12 -0700995set_size:
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200996 pndacl->num_aces = cpu_to_le32(num_aces);
Steve French97837582007-12-31 07:47:21 +0000997 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Steve French97837582007-12-31 07:47:21 +0000998
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000999 return 0;
Steve French97837582007-12-31 07:47:21 +00001000}
1001
1002
Steve Frenchbcb02032007-09-25 16:17:24 +00001003static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
1004{
1005 /* BB need to add parm so we can store the SID BB */
1006
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001007 /* validate that we do not go past end of ACL - sid must be at least 8
1008 bytes long (assuming no sub-auths - e.g. the null SID */
1009 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001010 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +00001011 return -EINVAL;
1012 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001013
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001014#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001015 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +00001016 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -05001017 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
1018 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001019
Steve Frenchaf6f4612007-10-16 18:40:37 +00001020 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001021 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
1022 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001023 }
1024
Steve Frenchd12fd122007-10-03 19:43:19 +00001025 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001026 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -05001027 cifs_dbg(FYI, "RID 0x%x\n",
1028 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001029 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001030#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001031
Steve Frenchbcb02032007-09-25 16:17:24 +00001032 return 0;
1033}
1034
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001035
Steve Frenchbcb02032007-09-25 16:17:24 +00001036/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001037static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001038 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
1039 bool get_mode_from_special_sid)
Steve Frenchbcb02032007-09-25 16:17:24 +00001040{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001041 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001042 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1043 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001044 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001045 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001046
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001047 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001048 return -EIO;
1049
Steve Frenchbcb02032007-09-25 16:17:24 +00001050 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001051 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001052 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001053 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001054 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001055 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -05001056 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 +00001057 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1058 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001059 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001060/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001061 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001062 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001063 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001064 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001065 }
1066 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1067 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001068 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
1069 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001070 return rc;
1071 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001072
1073 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001074 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001075 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
1076 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001077 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001078 }
1079 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1080 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001081 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
1082 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001083 return rc;
1084 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001085
Steve French7505e052007-11-01 18:03:01 +00001086 if (dacloffset)
1087 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001088 group_sid_ptr, fattr, get_mode_from_special_sid);
Steve French7505e052007-11-01 18:03:01 +00001089 else
Joe Perchesf96637b2013-05-04 22:12:25 -05001090 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001091
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001092 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001093}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001094
Steve French97837582007-12-31 07:47:21 +00001095/* Convert permission bits from mode to equivalent CIFS ACL */
1096static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shyam Prasad N0f220532020-08-17 03:23:12 -07001097 __u32 secdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
Steve Frencha6603392020-06-12 10:36:37 -05001098 bool mode_from_sid, bool id_from_sid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001099{
1100 int rc = 0;
1101 __u32 dacloffset;
1102 __u32 ndacloffset;
1103 __u32 sidsoffset;
1104 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001105 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001106 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1107 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1108
Shyam Prasad N0f220532020-08-17 03:23:12 -07001109 if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001110 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001111 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001112 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001113 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001114 dacloffset = le32_to_cpu(pntsd->dacloffset);
1115 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1116 ndacloffset = sizeof(struct cifs_ntsd);
1117 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1118 ndacl_ptr->revision = dacl_ptr->revision;
1119 ndacl_ptr->size = 0;
1120 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001121
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001122 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Shyam Prasad N0f220532020-08-17 03:23:12 -07001123 pnmode, mode_from_sid);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001124 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1125 /* copy sec desc control portion & owner and group sids */
1126 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1127 *aclflag = CIFS_ACL_DACL;
1128 } else {
1129 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001130 if (uid_valid(uid)) { /* chown */
1131 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001132 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1133 le32_to_cpu(pnntsd->osidoffset));
1134 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1135 GFP_KERNEL);
1136 if (!nowner_sid_ptr)
1137 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001138 id = from_kuid(&init_user_ns, uid);
Steve Frencha6603392020-06-12 10:36:37 -05001139 if (id_from_sid) {
1140 struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
1141 /* Populate the user ownership fields S-1-5-88-1 */
1142 osid->Revision = 1;
1143 osid->NumAuth = 3;
1144 osid->Authority[5] = 5;
1145 osid->SubAuthorities[0] = cpu_to_le32(88);
1146 osid->SubAuthorities[1] = cpu_to_le32(1);
1147 osid->SubAuthorities[2] = cpu_to_le32(id);
1148 } else { /* lookup sid with upcall */
1149 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
1150 if (rc) {
1151 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
1152 __func__, rc, id);
1153 kfree(nowner_sid_ptr);
1154 return rc;
1155 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001156 }
Jeff Layton36960e42012-11-03 09:37:28 -04001157 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001158 kfree(nowner_sid_ptr);
1159 *aclflag = CIFS_ACL_OWNER;
1160 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001161 if (gid_valid(gid)) { /* chgrp */
1162 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001163 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1164 le32_to_cpu(pnntsd->gsidoffset));
1165 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1166 GFP_KERNEL);
1167 if (!ngroup_sid_ptr)
1168 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001169 id = from_kgid(&init_user_ns, gid);
Steve Frencha6603392020-06-12 10:36:37 -05001170 if (id_from_sid) {
1171 struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
1172 /* Populate the group ownership fields S-1-5-88-2 */
1173 gsid->Revision = 1;
1174 gsid->NumAuth = 3;
1175 gsid->Authority[5] = 5;
1176 gsid->SubAuthorities[0] = cpu_to_le32(88);
1177 gsid->SubAuthorities[1] = cpu_to_le32(2);
1178 gsid->SubAuthorities[2] = cpu_to_le32(id);
1179 } else { /* lookup sid with upcall */
1180 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
1181 if (rc) {
1182 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
1183 __func__, rc, id);
1184 kfree(ngroup_sid_ptr);
1185 return rc;
1186 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001187 }
Jeff Layton36960e42012-11-03 09:37:28 -04001188 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001189 kfree(ngroup_sid_ptr);
1190 *aclflag = CIFS_ACL_GROUP;
1191 }
1192 }
Steve French97837582007-12-31 07:47:21 +00001193
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001194 return rc;
Steve French97837582007-12-31 07:47:21 +00001195}
1196
Steve French42eacf92014-02-10 14:08:16 -06001197struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
Boris Protopopov3970acf2020-12-18 11:30:12 -06001198 const struct cifs_fid *cifsfid, u32 *pacllen,
1199 u32 __maybe_unused unused)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001200{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001201 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001202 unsigned int xid;
1203 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001204 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1205
1206 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001207 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001208
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001209 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001210 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1211 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001212 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001213
Jeff Layton7ffec372010-09-29 19:51:11 -04001214 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001215
Joe Perchesf96637b2013-05-04 22:12:25 -05001216 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001217 if (rc)
1218 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001219 return pntsd;
1220}
1221
1222static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1223 const char *path, u32 *pacllen)
1224{
1225 struct cifs_ntsd *pntsd = NULL;
1226 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001227 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001228 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00001229 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001230 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001231 struct cifs_fid fid;
1232 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001233
Jeff Layton7ffec372010-09-29 19:51:11 -04001234 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001235 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001236
1237 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001238 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001239
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001240 oparms.tcon = tcon;
1241 oparms.cifs_sb = cifs_sb;
1242 oparms.desired_access = READ_CONTROL;
Amir Goldstein0f060932020-02-03 21:46:43 +02001243 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001244 oparms.disposition = FILE_OPEN;
1245 oparms.path = path;
1246 oparms.fid = &fid;
1247 oparms.reconnect = false;
1248
1249 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001250 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001251 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1252 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001253 }
1254
Jeff Layton7ffec372010-09-29 19:51:11 -04001255 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001256 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001257
Joe Perchesf96637b2013-05-04 22:12:25 -05001258 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001259 if (rc)
1260 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001261 return pntsd;
1262}
1263
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001264/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001265struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001266 struct inode *inode, const char *path,
Boris Protopopov3970acf2020-12-18 11:30:12 -06001267 u32 *pacllen, u32 info)
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001268{
1269 struct cifs_ntsd *pntsd = NULL;
1270 struct cifsFileInfo *open_file = NULL;
1271
1272 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001273 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001274 if (!open_file)
1275 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1276
Boris Protopopov3970acf2020-12-18 11:30:12 -06001277 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001278 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001279 return pntsd;
1280}
1281
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001282 /* Set an ACL on the server */
1283int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1284 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001285{
1286 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001287 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001288 int rc, access_flags;
Steve French96daf2b2011-05-27 04:34:02 +00001289 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001290 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001291 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001292 struct cifs_fid fid;
1293 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001294
Jeff Layton7ffec372010-09-29 19:51:11 -04001295 if (IS_ERR(tlink))
1296 return PTR_ERR(tlink);
1297
1298 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001299 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001300
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001301 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1302 access_flags = WRITE_OWNER;
1303 else
1304 access_flags = WRITE_DAC;
1305
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001306 oparms.tcon = tcon;
1307 oparms.cifs_sb = cifs_sb;
1308 oparms.desired_access = access_flags;
Amir Goldstein0f060932020-02-03 21:46:43 +02001309 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001310 oparms.disposition = FILE_OPEN;
1311 oparms.path = path;
1312 oparms.fid = &fid;
1313 oparms.reconnect = false;
1314
1315 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001316 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001317 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001318 goto out;
Steve French97837582007-12-31 07:47:21 +00001319 }
1320
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001321 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001322 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001323
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001324 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001325out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001326 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001327 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001328 return rc;
1329}
Steve French97837582007-12-31 07:47:21 +00001330
Achilles Gaikwad36c7ce42018-01-28 13:39:48 +05301331/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001332int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001333cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001334 struct inode *inode, bool mode_from_special_sid,
1335 const char *path, const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001336{
1337 struct cifs_ntsd *pntsd = NULL;
1338 u32 acllen = 0;
1339 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001340 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001341 struct smb_version_operations *ops;
Boris Protopopov3970acf2020-12-18 11:30:12 -06001342 const u32 info = 0;
Steve French7505e052007-11-01 18:03:01 +00001343
Joe Perchesf96637b2013-05-04 22:12:25 -05001344 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001345
Steve French42eacf92014-02-10 14:08:16 -06001346 if (IS_ERR(tlink))
1347 return PTR_ERR(tlink);
Steve French7505e052007-11-01 18:03:01 +00001348
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001349 ops = tlink_tcon(tlink)->ses->server->ops;
1350
1351 if (pfid && (ops->get_acl_by_fid))
Boris Protopopov3970acf2020-12-18 11:30:12 -06001352 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen, info);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001353 else if (ops->get_acl)
Boris Protopopov3970acf2020-12-18 11:30:12 -06001354 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen, info);
Steve French42eacf92014-02-10 14:08:16 -06001355 else {
1356 cifs_put_tlink(tlink);
1357 return -EOPNOTSUPP;
1358 }
Steve French7505e052007-11-01 18:03:01 +00001359 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001360 if (IS_ERR(pntsd)) {
1361 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001362 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001363 } else if (mode_from_special_sid) {
1364 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
Namjae Jeon98128572020-11-09 17:35:33 +09001365 kfree(pntsd);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001366 } else {
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001367 /* get approximated mode from ACL */
1368 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001369 kfree(pntsd);
1370 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001371 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001372 }
Steve French7505e052007-11-01 18:03:01 +00001373
Steve French42eacf92014-02-10 14:08:16 -06001374 cifs_put_tlink(tlink);
1375
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001376 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001377}
Steve French953f8682007-10-31 04:54:42 +00001378
Steve French7505e052007-11-01 18:03:01 +00001379/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001380int
Shyam Prasad N0f220532020-08-17 03:23:12 -07001381id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001382 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001383{
1384 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001385 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001386 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001387 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1388 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001389 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1390 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001391 struct smb_version_operations *ops;
Steve Frencha6603392020-06-12 10:36:37 -05001392 bool mode_from_sid, id_from_sid;
Boris Protopopov3970acf2020-12-18 11:30:12 -06001393 const u32 info = 0;
Steve French83e3bc22014-02-02 23:31:47 -06001394
1395 if (IS_ERR(tlink))
1396 return PTR_ERR(tlink);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001397
1398 ops = tlink_tcon(tlink)->ses->server->ops;
Steve French953f8682007-10-31 04:54:42 +00001399
Joe Perchesf96637b2013-05-04 22:12:25 -05001400 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001401
1402 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001403
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001404 if (ops->get_acl == NULL) {
Steve French83e3bc22014-02-02 23:31:47 -06001405 cifs_put_tlink(tlink);
1406 return -EOPNOTSUPP;
1407 }
1408
Boris Protopopov3970acf2020-12-18 11:30:12 -06001409 pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen, info);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001410 if (IS_ERR(pntsd)) {
1411 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001412 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001413 cifs_put_tlink(tlink);
1414 return rc;
Steve French97837582007-12-31 07:47:21 +00001415 }
1416
Jeff Laytonc78cd832012-11-25 08:00:35 -05001417 /*
1418 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1419 * as chmod disables ACEs and set the security descriptor. Allocate
1420 * memory for the smb header, set security descriptor request security
1421 * descriptor parameters, and secuirty descriptor itself
1422 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001423 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001424 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1425 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001426 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001427 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001428 return -ENOMEM;
1429 }
1430
Steve French22442172019-07-19 08:15:55 +00001431 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
1432 mode_from_sid = true;
1433 else
1434 mode_from_sid = false;
1435
Steve Frencha6603392020-06-12 10:36:37 -05001436 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
1437 id_from_sid = true;
1438 else
1439 id_from_sid = false;
1440
Shyam Prasad N0f220532020-08-17 03:23:12 -07001441 rc = build_sec_desc(pntsd, pnntsd, secdesclen, pnmode, uid, gid,
Steve Frencha6603392020-06-12 10:36:37 -05001442 mode_from_sid, id_from_sid, &aclflag);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001443
Joe Perchesf96637b2013-05-04 22:12:25 -05001444 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001445
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001446 if (ops->set_acl == NULL)
Steve French83e3bc22014-02-02 23:31:47 -06001447 rc = -EOPNOTSUPP;
1448
Jeff Laytonc78cd832012-11-25 08:00:35 -05001449 if (!rc) {
1450 /* Set the security descriptor */
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001451 rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001452 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001453 }
Steve French83e3bc22014-02-02 23:31:47 -06001454 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001455
1456 kfree(pnntsd);
1457 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001458 return rc;
Steve French953f8682007-10-31 04:54:42 +00001459}