blob: 2f21f89871ccbd1b2e878733166aea954e8ebdcb [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,
1198 const struct cifs_fid *cifsfid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001199{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001200 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001201 unsigned int xid;
1202 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001203 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1204
1205 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001206 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001207
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001208 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001209 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1210 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001211 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001212
Jeff Layton7ffec372010-09-29 19:51:11 -04001213 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001214
Joe Perchesf96637b2013-05-04 22:12:25 -05001215 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001216 if (rc)
1217 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001218 return pntsd;
1219}
1220
1221static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1222 const char *path, u32 *pacllen)
1223{
1224 struct cifs_ntsd *pntsd = NULL;
1225 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001226 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001227 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00001228 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001229 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001230 struct cifs_fid fid;
1231 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001232
Jeff Layton7ffec372010-09-29 19:51:11 -04001233 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001234 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001235
1236 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001237 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001238
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001239 oparms.tcon = tcon;
1240 oparms.cifs_sb = cifs_sb;
1241 oparms.desired_access = READ_CONTROL;
Amir Goldstein0f060932020-02-03 21:46:43 +02001242 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001243 oparms.disposition = FILE_OPEN;
1244 oparms.path = path;
1245 oparms.fid = &fid;
1246 oparms.reconnect = false;
1247
1248 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001249 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001250 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1251 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001252 }
1253
Jeff Layton7ffec372010-09-29 19:51:11 -04001254 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001255 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001256
Joe Perchesf96637b2013-05-04 22:12:25 -05001257 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001258 if (rc)
1259 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001260 return pntsd;
1261}
1262
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001263/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001264struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001265 struct inode *inode, const char *path,
1266 u32 *pacllen)
1267{
1268 struct cifs_ntsd *pntsd = NULL;
1269 struct cifsFileInfo *open_file = NULL;
1270
1271 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001272 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001273 if (!open_file)
1274 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1275
Steve French42eacf92014-02-10 14:08:16 -06001276 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001277 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001278 return pntsd;
1279}
1280
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001281 /* Set an ACL on the server */
1282int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1283 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001284{
1285 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001286 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001287 int rc, access_flags;
Steve French96daf2b2011-05-27 04:34:02 +00001288 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001289 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001290 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001291 struct cifs_fid fid;
1292 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001293
Jeff Layton7ffec372010-09-29 19:51:11 -04001294 if (IS_ERR(tlink))
1295 return PTR_ERR(tlink);
1296
1297 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001298 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001299
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001300 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1301 access_flags = WRITE_OWNER;
1302 else
1303 access_flags = WRITE_DAC;
1304
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001305 oparms.tcon = tcon;
1306 oparms.cifs_sb = cifs_sb;
1307 oparms.desired_access = access_flags;
Amir Goldstein0f060932020-02-03 21:46:43 +02001308 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001309 oparms.disposition = FILE_OPEN;
1310 oparms.path = path;
1311 oparms.fid = &fid;
1312 oparms.reconnect = false;
1313
1314 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001315 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001316 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001317 goto out;
Steve French97837582007-12-31 07:47:21 +00001318 }
1319
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001320 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001321 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001322
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001323 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001324out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001325 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001326 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001327 return rc;
1328}
Steve French97837582007-12-31 07:47:21 +00001329
Achilles Gaikwad36c7ce42018-01-28 13:39:48 +05301330/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001331int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001332cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001333 struct inode *inode, bool mode_from_special_sid,
1334 const char *path, const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001335{
1336 struct cifs_ntsd *pntsd = NULL;
1337 u32 acllen = 0;
1338 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001339 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001340 struct smb_version_operations *ops;
Steve French7505e052007-11-01 18:03:01 +00001341
Joe Perchesf96637b2013-05-04 22:12:25 -05001342 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001343
Steve French42eacf92014-02-10 14:08:16 -06001344 if (IS_ERR(tlink))
1345 return PTR_ERR(tlink);
Steve French7505e052007-11-01 18:03:01 +00001346
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001347 ops = tlink_tcon(tlink)->ses->server->ops;
1348
1349 if (pfid && (ops->get_acl_by_fid))
1350 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
1351 else if (ops->get_acl)
1352 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
Steve French42eacf92014-02-10 14:08:16 -06001353 else {
1354 cifs_put_tlink(tlink);
1355 return -EOPNOTSUPP;
1356 }
Steve French7505e052007-11-01 18:03:01 +00001357 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001358 if (IS_ERR(pntsd)) {
1359 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001360 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001361 } else if (mode_from_special_sid) {
1362 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
Namjae Jeon98128572020-11-09 17:35:33 +09001363 kfree(pntsd);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001364 } else {
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001365 /* get approximated mode from ACL */
1366 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001367 kfree(pntsd);
1368 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001369 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001370 }
Steve French7505e052007-11-01 18:03:01 +00001371
Steve French42eacf92014-02-10 14:08:16 -06001372 cifs_put_tlink(tlink);
1373
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001374 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001375}
Steve French953f8682007-10-31 04:54:42 +00001376
Steve French7505e052007-11-01 18:03:01 +00001377/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001378int
Shyam Prasad N0f220532020-08-17 03:23:12 -07001379id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001380 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001381{
1382 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001383 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001384 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001385 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1386 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001387 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1388 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001389 struct smb_version_operations *ops;
Steve Frencha6603392020-06-12 10:36:37 -05001390 bool mode_from_sid, id_from_sid;
Steve French83e3bc22014-02-02 23:31:47 -06001391
1392 if (IS_ERR(tlink))
1393 return PTR_ERR(tlink);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001394
1395 ops = tlink_tcon(tlink)->ses->server->ops;
Steve French953f8682007-10-31 04:54:42 +00001396
Joe Perchesf96637b2013-05-04 22:12:25 -05001397 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001398
1399 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001400
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001401 if (ops->get_acl == NULL) {
Steve French83e3bc22014-02-02 23:31:47 -06001402 cifs_put_tlink(tlink);
1403 return -EOPNOTSUPP;
1404 }
1405
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001406 pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001407 if (IS_ERR(pntsd)) {
1408 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001409 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001410 cifs_put_tlink(tlink);
1411 return rc;
Steve French97837582007-12-31 07:47:21 +00001412 }
1413
Jeff Laytonc78cd832012-11-25 08:00:35 -05001414 /*
1415 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1416 * as chmod disables ACEs and set the security descriptor. Allocate
1417 * memory for the smb header, set security descriptor request security
1418 * descriptor parameters, and secuirty descriptor itself
1419 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001420 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001421 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1422 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001423 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001424 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001425 return -ENOMEM;
1426 }
1427
Steve French22442172019-07-19 08:15:55 +00001428 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
1429 mode_from_sid = true;
1430 else
1431 mode_from_sid = false;
1432
Steve Frencha6603392020-06-12 10:36:37 -05001433 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
1434 id_from_sid = true;
1435 else
1436 id_from_sid = false;
1437
Shyam Prasad N0f220532020-08-17 03:23:12 -07001438 rc = build_sec_desc(pntsd, pnntsd, secdesclen, pnmode, uid, gid,
Steve Frencha6603392020-06-12 10:36:37 -05001439 mode_from_sid, id_from_sid, &aclflag);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001440
Joe Perchesf96637b2013-05-04 22:12:25 -05001441 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001442
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001443 if (ops->set_acl == NULL)
Steve French83e3bc22014-02-02 23:31:47 -06001444 rc = -EOPNOTSUPP;
1445
Jeff Laytonc78cd832012-11-25 08:00:35 -05001446 if (!rc) {
1447 /* Set the security descriptor */
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001448 rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001449 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001450 }
Steve French83e3bc22014-02-02 23:31:47 -06001451 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001452
1453 kfree(pnntsd);
1454 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001455 return rc;
Steve French953f8682007-10-31 04:54:42 +00001456}