blob: ef4784e72b1d540ffb9318b93d29761a770670fa [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"
Steve French65874002007-09-25 19:53:44 +000035
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060036/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000037static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060039/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
Fabian Frederickbc09d142014-12-10 15:41:15 -080041 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000042
Steve French3514de32016-10-13 19:06:23 -050043/* S-1-22-1 Unmapped Unix users */
44static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
45 {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
46
47/* S-1-22-2 Unmapped Unix groups */
48static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
49 {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
50
51/*
Alexander A. Klimovcba22b12020-06-27 12:31:25 +020052 * See https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve French3514de32016-10-13 19:06:23 -050053 */
54
55/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
56
57/* S-1-5-88-1 Unix uid */
58static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
59 {cpu_to_le32(88),
60 cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
61
62/* S-1-5-88-2 Unix gid */
63static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
64 {cpu_to_le32(88),
65 cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
66
67/* S-1-5-88-3 Unix mode */
68static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
69 {cpu_to_le32(88),
70 cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
71
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050072static const struct cred *root_cred;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050073
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050074static int
David Howellscf7f6012012-09-13 13:06:29 +010075cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050076{
77 char *payload;
78
Jeff Layton41a9f1f2012-12-03 06:05:29 -050079 /*
80 * If the payload is less than or equal to the size of a pointer, then
81 * an allocation here is wasteful. Just copy the data directly to the
82 * payload.value union member instead.
83 *
84 * With this however, you must check the datalen before trying to
85 * dereference payload.data!
86 */
Jeff Layton1f630682012-12-03 06:05:31 -050087 if (prep->datalen <= sizeof(key->payload)) {
David Howells146aa8b2015-10-21 14:04:48 +010088 key->payload.data[0] = NULL;
89 memcpy(&key->payload, prep->data, prep->datalen);
90 } else {
91 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
92 if (!payload)
93 return -ENOMEM;
94 key->payload.data[0] = payload;
Jeff Layton41a9f1f2012-12-03 06:05:29 -050095 }
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050096
David Howellscf7f6012012-09-13 13:06:29 +010097 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050098 return 0;
99}
100
101static inline void
102cifs_idmap_key_destroy(struct key *key)
103{
Jeff Layton1f630682012-12-03 06:05:31 -0500104 if (key->datalen > sizeof(key->payload))
David Howells146aa8b2015-10-21 14:04:48 +0100105 kfree(key->payload.data[0]);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500106}
107
Jeff Laytonb1a6dc22012-11-25 08:00:38 -0500108static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -0500109 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500110 .instantiate = cifs_idmap_key_instantiate,
111 .destroy = cifs_idmap_key_destroy,
112 .describe = user_describe,
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500113};
114
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500115static char *
116sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500117{
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500118 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500119 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500120 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -0500121 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500122
123 /* 3 bytes for prefix */
124 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
125 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
126 GFP_KERNEL);
127 if (!sidstr)
128 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500129
130 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500131 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
132 sidptr->revision);
133 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500134
Jeff Layton193cdd82012-12-10 06:10:44 -0500135 /* The authority field is a single 48-bit number */
136 id_auth_val = (unsigned long long)sidptr->authority[5];
137 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
138 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
139 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
140 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
141 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
142
143 /*
144 * MS-DTYP states that if the authority is >= 2^32, then it should be
145 * expressed as a hex value.
146 */
147 if (id_auth_val <= UINT_MAX)
148 len = sprintf(strptr, "-%llu", id_auth_val);
149 else
150 len = sprintf(strptr, "-0x%llx", id_auth_val);
151
152 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500153
154 for (i = 0; i < sidptr->num_subauth; ++i) {
155 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500156 len = sprintf(strptr, "-%u", saval);
157 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500158 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500159
160 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500161}
162
Jeff Layton436bb432012-11-25 08:00:36 -0500163/*
164 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
165 * the same returns zero, if they do not match returns non-zero.
166 */
167static int
168compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
169{
170 int i;
171 int num_subauth, num_sat, num_saw;
172
173 if ((!ctsid) || (!cwsid))
174 return 1;
175
176 /* compare the revision */
177 if (ctsid->revision != cwsid->revision) {
178 if (ctsid->revision > cwsid->revision)
179 return 1;
180 else
181 return -1;
182 }
183
184 /* compare all of the six auth values */
185 for (i = 0; i < NUM_AUTHS; ++i) {
186 if (ctsid->authority[i] != cwsid->authority[i]) {
187 if (ctsid->authority[i] > cwsid->authority[i])
188 return 1;
189 else
190 return -1;
191 }
192 }
193
194 /* compare all of the subauth values if any */
195 num_sat = ctsid->num_subauth;
196 num_saw = cwsid->num_subauth;
197 num_subauth = num_sat < num_saw ? num_sat : num_saw;
198 if (num_subauth) {
199 for (i = 0; i < num_subauth; ++i) {
200 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
201 if (le32_to_cpu(ctsid->sub_auth[i]) >
202 le32_to_cpu(cwsid->sub_auth[i]))
203 return 1;
204 else
205 return -1;
206 }
207 }
208 }
209
210 return 0; /* sids compare/match */
211}
212
Steve French3514de32016-10-13 19:06:23 -0500213static bool
214is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
215{
216 int i;
217 int num_subauth;
218 const struct cifs_sid *pwell_known_sid;
219
220 if (!psid || (puid == NULL))
221 return false;
222
223 num_subauth = psid->num_subauth;
224
225 /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
226 if (num_subauth == 2) {
227 if (is_group)
228 pwell_known_sid = &sid_unix_groups;
229 else
230 pwell_known_sid = &sid_unix_users;
231 } else if (num_subauth == 3) {
232 if (is_group)
233 pwell_known_sid = &sid_unix_NFS_groups;
234 else
235 pwell_known_sid = &sid_unix_NFS_users;
236 } else
237 return false;
238
239 /* compare the revision */
240 if (psid->revision != pwell_known_sid->revision)
241 return false;
242
243 /* compare all of the six auth values */
244 for (i = 0; i < NUM_AUTHS; ++i) {
245 if (psid->authority[i] != pwell_known_sid->authority[i]) {
246 cifs_dbg(FYI, "auth %d did not match\n", i);
247 return false;
248 }
249 }
250
251 if (num_subauth == 2) {
252 if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
253 return false;
254
255 *puid = le32_to_cpu(psid->sub_auth[1]);
256 } else /* 3 subauths, ie Windows/Mac style */ {
257 *puid = le32_to_cpu(psid->sub_auth[0]);
258 if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
259 (psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
260 return false;
261
262 *puid = le32_to_cpu(psid->sub_auth[2]);
263 }
264
265 cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
266 return true; /* well known sid found, uid returned */
267}
268
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500269static void
Jeff Layton36960e42012-11-03 09:37:28 -0400270cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
271{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500272 int i;
273
274 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500275 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500276 for (i = 0; i < NUM_AUTHS; ++i)
277 dst->authority[i] = src->authority[i];
278 for (i = 0; i < dst->num_subauth; ++i)
279 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400280}
281
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500282static int
283id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500284{
285 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500286 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500287 struct cifs_sid *ksid;
288 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500289 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500290 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500291
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500292 rc = snprintf(desc, sizeof(desc), "%ci:%u",
293 sidtype == SIDOWNER ? 'o' : 'g', cid);
294 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500295 return -EINVAL;
296
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500297 rc = 0;
298 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700299 sidkey = request_key(&cifs_idmap_key_type, desc, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500300 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500301 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500302 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
303 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500304 goto out_revert_creds;
305 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
306 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500307 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
308 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500309 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500310 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500311
Jeff Layton1f630682012-12-03 06:05:31 -0500312 /*
313 * A sid is usually too large to be embedded in payload.value, but if
314 * there are no subauthorities and the host has 8-byte pointers, then
315 * it could be.
316 */
317 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
David Howells146aa8b2015-10-21 14:04:48 +0100318 (struct cifs_sid *)&sidkey->payload :
319 (struct cifs_sid *)sidkey->payload.data[0];
Jeff Layton1f630682012-12-03 06:05:31 -0500320
Jeff Layton2ae03022012-12-03 06:05:30 -0500321 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
322 if (ksid_size > sidkey->datalen) {
323 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500324 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
325 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500326 goto invalidate_key;
327 }
Jeff Layton1f630682012-12-03 06:05:31 -0500328
Jeff Layton2ae03022012-12-03 06:05:30 -0500329 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500330out_key_put:
331 key_put(sidkey);
332out_revert_creds:
333 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500334 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500335
336invalidate_key:
337 key_invalidate(sidkey);
338 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500339}
340
Steve French99344302020-10-20 02:02:02 -0500341int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500342sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
343 struct cifs_fattr *fattr, uint sidtype)
344{
Qiujun Huangf2d67932020-03-04 15:42:51 +0800345 int rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500346 struct key *sidkey;
347 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500348 const struct cred *saved_cred;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800349 kuid_t fuid = cifs_sb->mnt_uid;
350 kgid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500351
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500352 /*
353 * If we have too many subauthorities, then something is really wrong.
354 * Just return an error.
355 */
356 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500357 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
358 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500359 return -EIO;
360 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500361
Steve French99344302020-10-20 02:02:02 -0500362 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) ||
363 (cifs_sb_master_tcon(cifs_sb)->posix_extensions)) {
Steve French3514de32016-10-13 19:06:23 -0500364 uint32_t unix_id;
365 bool is_group;
366
367 if (sidtype != SIDOWNER)
368 is_group = true;
369 else
370 is_group = false;
371
372 if (is_well_known_sid(psid, &unix_id, is_group) == false)
373 goto try_upcall_to_get_id;
374
375 if (is_group) {
376 kgid_t gid;
377 gid_t id;
378
379 id = (gid_t)unix_id;
380 gid = make_kgid(&init_user_ns, id);
381 if (gid_valid(gid)) {
382 fgid = gid;
383 goto got_valid_id;
384 }
385 } else {
386 kuid_t uid;
387 uid_t id;
388
389 id = (uid_t)unix_id;
390 uid = make_kuid(&init_user_ns, id);
391 if (uid_valid(uid)) {
392 fuid = uid;
393 goto got_valid_id;
394 }
395 }
396 /* If unable to find uid/gid easily from SID try via upcall */
397 }
398
399try_upcall_to_get_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500400 sidstr = sid_to_key_str(psid, sidtype);
401 if (!sidstr)
402 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500403
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500404 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700405 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500406 if (IS_ERR(sidkey)) {
407 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500408 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
409 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500410 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500411 }
412
413 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500414 * FIXME: Here we assume that uid_t and gid_t are same size. It's
415 * probably a safe assumption but might be better to check based on
416 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500417 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800418 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500419 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500420 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500421 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
422 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500423 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500424 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500425 }
426
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800427 if (sidtype == SIDOWNER) {
428 kuid_t uid;
429 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100430 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800431 uid = make_kuid(&init_user_ns, id);
432 if (uid_valid(uid))
433 fuid = uid;
434 } else {
435 kgid_t gid;
436 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100437 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800438 gid = make_kgid(&init_user_ns, id);
439 if (gid_valid(gid))
440 fgid = gid;
441 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500442
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500443out_key_put:
444 key_put(sidkey);
445out_revert_creds:
446 revert_creds(saved_cred);
447 kfree(sidstr);
448
449 /*
450 * Note that we return 0 here unconditionally. If the mapping
451 * fails then we just fall back to using the mnt_uid/mnt_gid.
452 */
Steve French3514de32016-10-13 19:06:23 -0500453got_valid_id:
Qiujun Huangf2d67932020-03-04 15:42:51 +0800454 rc = 0;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500455 if (sidtype == SIDOWNER)
456 fattr->cf_uid = fuid;
457 else
458 fattr->cf_gid = fgid;
Qiujun Huangf2d67932020-03-04 15:42:51 +0800459 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500460}
461
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500462int
463init_cifs_idmap(void)
464{
465 struct cred *cred;
466 struct key *keyring;
467 int ret;
468
Joe Perchesf96637b2013-05-04 22:12:25 -0500469 cifs_dbg(FYI, "Registering the %s key type\n",
470 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500471
472 /* create an override credential set with a special thread keyring in
473 * which requests are cached
474 *
475 * this is used to prevent malicious redirections from being installed
476 * with add_key().
477 */
478 cred = prepare_kernel_cred(NULL);
479 if (!cred)
480 return -ENOMEM;
481
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800482 keyring = keyring_alloc(".cifs_idmap",
483 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
Linus Torvalds028db3e2019-07-10 18:43:43 -0700484 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
485 KEY_USR_VIEW | KEY_USR_READ,
David Howells5ac7eac2016-04-06 16:14:24 +0100486 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500487 if (IS_ERR(keyring)) {
488 ret = PTR_ERR(keyring);
489 goto failed_put_cred;
490 }
491
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500492 ret = register_key_type(&cifs_idmap_key_type);
493 if (ret < 0)
494 goto failed_put_key;
495
496 /* instruct request_key() to use this special keyring as a cache for
497 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000498 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500499 cred->thread_keyring = keyring;
500 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
501 root_cred = cred;
502
Joe Perchesf96637b2013-05-04 22:12:25 -0500503 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500504 return 0;
505
506failed_put_key:
507 key_put(keyring);
508failed_put_cred:
509 put_cred(cred);
510 return ret;
511}
512
513void
514exit_cifs_idmap(void)
515{
516 key_revoke(root_cred->thread_keyring);
517 unregister_key_type(&cifs_idmap_key_type);
518 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500519 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500520}
521
Steve French97837582007-12-31 07:47:21 +0000522/* copy ntsd, owner sid, and group sid from a security descriptor to another */
523static void copy_sec_desc(const struct cifs_ntsd *pntsd,
524 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
525{
Steve French97837582007-12-31 07:47:21 +0000526 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
527 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
528
529 /* copy security descriptor control portion */
530 pnntsd->revision = pntsd->revision;
531 pnntsd->type = pntsd->type;
532 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
533 pnntsd->sacloffset = 0;
534 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
535 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
536
537 /* copy owner sid */
538 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
539 le32_to_cpu(pntsd->osidoffset));
540 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400541 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000542
543 /* copy group sid */
544 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
545 le32_to_cpu(pntsd->gsidoffset));
546 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
547 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400548 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000549
550 return;
551}
552
553
Steve French630f3f0c2007-10-25 21:17:17 +0000554/*
555 change posix mode to reflect permissions
556 pmode is the existing mode (we only want to overwrite part of this
557 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
558*/
Al Viro9b5e6852007-12-05 08:24:38 +0000559static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000560 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000561{
Al Viro9b5e6852007-12-05 08:24:38 +0000562 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000563 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000564 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000565 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000566 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000567 for the operation you are trying to perform for your user */
568
569 /* For deny ACEs we change the mask so that subsequent allow access
570 control entries do not turn on the bits we are denying */
571 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000572 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000573 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000574
Al Viro9b5e6852007-12-05 08:24:38 +0000575 if ((flags & GENERIC_WRITE) ||
576 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000577 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000578 if ((flags & GENERIC_READ) ||
579 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000580 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000581 if ((flags & GENERIC_EXECUTE) ||
582 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000583 *pbits_to_set &= ~S_IXUGO;
584 return;
585 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500586 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000587 return;
588 }
589 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000590
Al Viro9b5e6852007-12-05 08:24:38 +0000591 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000592 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesf96637b2013-05-04 22:12:25 -0500593 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000594 return;
595 }
Al Viro9b5e6852007-12-05 08:24:38 +0000596 if ((flags & GENERIC_WRITE) ||
597 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000598 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000599 if ((flags & GENERIC_READ) ||
600 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000601 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000602 if ((flags & GENERIC_EXECUTE) ||
603 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000604 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000605
Frank Sorensonf52aa792020-02-12 15:31:48 -0600606 cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000607 return;
608}
609
Steve Frenchce06c9f2007-11-08 21:12:01 +0000610/*
611 Generate access flags to reflect permissions mode is the existing mode.
612 This function is called for every ACE in the DACL whose SID matches
613 with either owner or group or everyone.
614*/
615
616static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
617 __u32 *pace_flags)
618{
619 /* reset access mask */
620 *pace_flags = 0x0;
621
622 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
623 mode &= bits_to_use;
624
625 /* check for R/W/X UGO since we do not know whose flags
626 is this but we have cleared all the bits sans RWX for
627 either user or group or other as per bits_to_use */
628 if (mode & S_IRUGO)
629 *pace_flags |= SET_FILE_READ_RIGHTS;
630 if (mode & S_IWUGO)
631 *pace_flags |= SET_FILE_WRITE_RIGHTS;
632 if (mode & S_IXUGO)
633 *pace_flags |= SET_FILE_EXEC_RIGHTS;
634
Frank Sorensonf52aa792020-02-12 15:31:48 -0600635 cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n",
Joe Perchesf96637b2013-05-04 22:12:25 -0500636 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000637 return;
638}
639
Al Viro2b210ad2008-03-29 03:09:18 +0000640static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000641 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
642{
643 int i;
644 __u16 size = 0;
645 __u32 access_req = 0;
646
647 pntace->type = ACCESS_ALLOWED;
648 pntace->flags = 0x0;
649 mode_to_access_flags(nmode, bits, &access_req);
650 if (!access_req)
651 access_req = SET_MINIMUM_RIGHTS;
652 pntace->access_req = cpu_to_le32(access_req);
653
654 pntace->sid.revision = psid->revision;
655 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500656 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000657 pntace->sid.authority[i] = psid->authority[i];
658 for (i = 0; i < psid->num_subauth; i++)
659 pntace->sid.sub_auth[i] = psid->sub_auth[i];
660
661 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
662 pntace->size = cpu_to_le16(size);
663
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000664 return size;
Steve French97837582007-12-31 07:47:21 +0000665}
666
Steve French297647c2007-10-12 04:11:59 +0000667
Steve French953f8682007-10-31 04:54:42 +0000668#ifdef CONFIG_CIFS_DEBUG2
669static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000670{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000671 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000672
673 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000674
Steve French44093ca2007-10-23 21:22:55 +0000675 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500676 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000677 return;
678 }
679
680 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500681 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000682 return;
Steve French44093ca2007-10-23 21:22:55 +0000683 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000684
Steve French44093ca2007-10-23 21:22:55 +0000685 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000686 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000687 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500688 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
689 pace->sid.revision, pace->sid.num_subauth, pace->type,
690 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000691 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500692 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
693 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000694 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000695
Steve Frenchd12fd122007-10-03 19:43:19 +0000696 /* BB add length check to make sure that we do not have huge
697 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000698 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000699
Steve Frenchd12fd122007-10-03 19:43:19 +0000700 return;
701}
Steve French953f8682007-10-31 04:54:42 +0000702#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000703
Steve Frencha750e772007-10-17 22:50:39 +0000704static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000705 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000706 struct cifs_fattr *fattr, bool mode_from_special_sid)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000707{
708 int i;
709 int num_aces = 0;
710 int acl_size;
711 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000712 struct cifs_ace **ppace;
713
714 /* BB need to add parm so we can store the SID BB */
715
Steve French2b834572007-11-25 10:01:00 +0000716 if (!pdacl) {
717 /* no DACL in the security descriptor, set
718 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400719 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000720 return;
721 }
722
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000723 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000724 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500725 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000726 return;
727 }
728
Joe Perchesf96637b2013-05-04 22:12:25 -0500729 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
730 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
731 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000732
Steve French7505e052007-11-01 18:03:01 +0000733 /* reset rwx permissions for user/group/other.
734 Also, if num_aces is 0 i.e. DACL has no ACEs,
735 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400736 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000737
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000738 acl_base = (char *)pdacl;
739 acl_size = sizeof(struct cifs_acl);
740
Steve Frenchadbc0352007-10-17 02:12:46 +0000741 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500742 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000743 umode_t user_mask = S_IRWXU;
744 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600745 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000746
Dan Carpenter72501702012-01-11 10:46:27 +0300747 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
748 return;
Kees Cook6da2ec52018-06-12 13:55:00 -0700749 ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
750 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500751 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300752 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000753
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000754 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000755 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000756#ifdef CONFIG_CIFS_DEBUG2
757 dump_ace(ppace[i], end_of_acl);
758#endif
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000759 if (mode_from_special_sid &&
760 (compare_sids(&(ppace[i]->sid),
761 &sid_unix_NFS_mode) == 0)) {
762 /*
763 * Full permissions are:
764 * 07777 = S_ISUID | S_ISGID | S_ISVTX |
765 * S_IRWXU | S_IRWXG | S_IRWXO
766 */
767 fattr->cf_mode &= ~07777;
768 fattr->cf_mode |=
769 le32_to_cpu(ppace[i]->sid.sub_auth[2]);
770 break;
771 } else if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000772 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000773 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400774 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000775 &user_mask);
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000776 else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000777 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000778 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400779 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000780 &group_mask);
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000781 else if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000782 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000783 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400784 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000785 &other_mask);
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000786 else if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600787 access_flags_to_mode(ppace[i]->access_req,
788 ppace[i]->type,
789 &fattr->cf_mode,
790 &other_mask);
791
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000792
Steve French44093ca2007-10-23 21:22:55 +0000793/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000794 (void *)ppace[i],
795 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000796
Steve French44093ca2007-10-23 21:22:55 +0000797 acl_base = (char *)ppace[i];
798 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000799 }
800
801 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000802 }
803
804 return;
805}
806
Steve French643fbce2020-01-16 19:55:33 -0600807unsigned int setup_authusers_ACE(struct cifs_ace *pntace)
808{
809 int i;
810 unsigned int ace_size = 20;
811
812 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
813 pntace->flags = 0x0;
814 pntace->access_req = cpu_to_le32(GENERIC_ALL);
815 pntace->sid.num_subauth = 1;
816 pntace->sid.revision = 1;
817 for (i = 0; i < NUM_AUTHS; i++)
818 pntace->sid.authority[i] = sid_authusers.authority[i];
819
820 pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0];
821
822 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
823 pntace->size = cpu_to_le16(ace_size);
824 return ace_size;
825}
826
Steve Frenchfdef6652019-12-06 02:02:38 -0600827/*
828 * Fill in the special SID based on the mode. See
Alexander A. Klimovcba22b12020-06-27 12:31:25 +0200829 * https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
Steve Frenchfdef6652019-12-06 02:02:38 -0600830 */
831unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
832{
833 int i;
834 unsigned int ace_size = 28;
835
836 pntace->type = ACCESS_DENIED_ACE_TYPE;
837 pntace->flags = 0x0;
838 pntace->access_req = 0;
839 pntace->sid.num_subauth = 3;
840 pntace->sid.revision = 1;
841 for (i = 0; i < NUM_AUTHS; i++)
842 pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
843
844 pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
845 pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
846 pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
847
848 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
849 pntace->size = cpu_to_le16(ace_size);
850 return ace_size;
851}
Steve Frenchbcb02032007-09-25 16:17:24 +0000852
Steve French975221e2020-06-12 09:25:21 -0500853unsigned int setup_special_user_owner_ACE(struct cifs_ace *pntace)
854{
855 int i;
856 unsigned int ace_size = 28;
857
858 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
859 pntace->flags = 0x0;
860 pntace->access_req = cpu_to_le32(GENERIC_ALL);
861 pntace->sid.num_subauth = 3;
862 pntace->sid.revision = 1;
863 for (i = 0; i < NUM_AUTHS; i++)
864 pntace->sid.authority[i] = sid_unix_NFS_users.authority[i];
865
866 pntace->sid.sub_auth[0] = sid_unix_NFS_users.sub_auth[0];
867 pntace->sid.sub_auth[1] = sid_unix_NFS_users.sub_auth[1];
868 pntace->sid.sub_auth[2] = cpu_to_le32(current_fsgid().val);
869
870 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
871 pntace->size = cpu_to_le16(ace_size);
872 return ace_size;
873}
874
Steve French97837582007-12-31 07:47:21 +0000875static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
Steve French22442172019-07-19 08:15:55 +0000876 struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
Steve French97837582007-12-31 07:47:21 +0000877{
Al Viro2b210ad2008-03-29 03:09:18 +0000878 u16 size = 0;
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200879 u32 num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000880 struct cifs_acl *pnndacl;
881
882 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
883
Steve French22442172019-07-19 08:15:55 +0000884 if (modefromsid) {
885 struct cifs_ace *pntace =
886 (struct cifs_ace *)((char *)pnndacl + size);
Steve French22442172019-07-19 08:15:55 +0000887
Steve Frenchfdef6652019-12-06 02:02:38 -0600888 size += setup_special_mode_ACE(pntace, nmode);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200889 num_aces++;
890 }
Steve French22442172019-07-19 08:15:55 +0000891
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200892 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
893 pownersid, nmode, S_IRWXU);
894 num_aces++;
895 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
896 pgrpsid, nmode, S_IRWXG);
897 num_aces++;
898 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
899 &sid_everyone, nmode, S_IRWXO);
900 num_aces++;
901
902 pndacl->num_aces = cpu_to_le32(num_aces);
Steve French97837582007-12-31 07:47:21 +0000903 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Steve French97837582007-12-31 07:47:21 +0000904
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000905 return 0;
Steve French97837582007-12-31 07:47:21 +0000906}
907
908
Steve Frenchbcb02032007-09-25 16:17:24 +0000909static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
910{
911 /* BB need to add parm so we can store the SID BB */
912
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000913 /* validate that we do not go past end of ACL - sid must be at least 8
914 bytes long (assuming no sub-auths - e.g. the null SID */
915 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500916 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000917 return -EINVAL;
918 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000919
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000920#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500921 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000922 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500923 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
924 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000925
Steve Frenchaf6f4612007-10-16 18:40:37 +0000926 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500927 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
928 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000929 }
930
Steve Frenchd12fd122007-10-03 19:43:19 +0000931 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000932 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -0500933 cifs_dbg(FYI, "RID 0x%x\n",
934 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000935 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500936#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000937
Steve Frenchbcb02032007-09-25 16:17:24 +0000938 return 0;
939}
940
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000941
Steve Frenchbcb02032007-09-25 16:17:24 +0000942/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500943static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000944 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
945 bool get_mode_from_special_sid)
Steve Frenchbcb02032007-09-25 16:17:24 +0000946{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500947 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000948 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
949 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000950 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000951 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000952
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400953 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000954 return -EIO;
955
Steve Frenchbcb02032007-09-25 16:17:24 +0000956 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000957 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000958 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000959 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000960 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000961 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -0500962 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 +0000963 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
964 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000965 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000966/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000967 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500968 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500969 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000970 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500971 }
972 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
973 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500974 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
975 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500976 return rc;
977 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000978
979 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500980 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500981 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
982 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000983 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500984 }
985 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
986 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500987 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
988 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500989 return rc;
990 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000991
Steve French7505e052007-11-01 18:03:01 +0000992 if (dacloffset)
993 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000994 group_sid_ptr, fattr, get_mode_from_special_sid);
Steve French7505e052007-11-01 18:03:01 +0000995 else
Joe Perchesf96637b2013-05-04 22:12:25 -0500996 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000997
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500998 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000999}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001000
Steve French97837582007-12-31 07:47:21 +00001001/* Convert permission bits from mode to equivalent CIFS ACL */
1002static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve French22442172019-07-19 08:15:55 +00001003 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid,
Steve Frencha6603392020-06-12 10:36:37 -05001004 bool mode_from_sid, bool id_from_sid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001005{
1006 int rc = 0;
1007 __u32 dacloffset;
1008 __u32 ndacloffset;
1009 __u32 sidsoffset;
1010 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001011 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001012 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1013 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1014
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001015 if (nmode != NO_CHANGE_64) { /* chmod */
1016 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001017 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001018 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001019 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001020 dacloffset = le32_to_cpu(pntsd->dacloffset);
1021 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1022 ndacloffset = sizeof(struct cifs_ntsd);
1023 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1024 ndacl_ptr->revision = dacl_ptr->revision;
1025 ndacl_ptr->size = 0;
1026 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001027
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001028 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Steve French22442172019-07-19 08:15:55 +00001029 nmode, mode_from_sid);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001030 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1031 /* copy sec desc control portion & owner and group sids */
1032 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1033 *aclflag = CIFS_ACL_DACL;
1034 } else {
1035 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001036 if (uid_valid(uid)) { /* chown */
1037 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001038 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1039 le32_to_cpu(pnntsd->osidoffset));
1040 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1041 GFP_KERNEL);
1042 if (!nowner_sid_ptr)
1043 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001044 id = from_kuid(&init_user_ns, uid);
Steve Frencha6603392020-06-12 10:36:37 -05001045 if (id_from_sid) {
1046 struct owner_sid *osid = (struct owner_sid *)nowner_sid_ptr;
1047 /* Populate the user ownership fields S-1-5-88-1 */
1048 osid->Revision = 1;
1049 osid->NumAuth = 3;
1050 osid->Authority[5] = 5;
1051 osid->SubAuthorities[0] = cpu_to_le32(88);
1052 osid->SubAuthorities[1] = cpu_to_le32(1);
1053 osid->SubAuthorities[2] = cpu_to_le32(id);
1054 } else { /* lookup sid with upcall */
1055 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
1056 if (rc) {
1057 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
1058 __func__, rc, id);
1059 kfree(nowner_sid_ptr);
1060 return rc;
1061 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001062 }
Jeff Layton36960e42012-11-03 09:37:28 -04001063 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001064 kfree(nowner_sid_ptr);
1065 *aclflag = CIFS_ACL_OWNER;
1066 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001067 if (gid_valid(gid)) { /* chgrp */
1068 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001069 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1070 le32_to_cpu(pnntsd->gsidoffset));
1071 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1072 GFP_KERNEL);
1073 if (!ngroup_sid_ptr)
1074 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001075 id = from_kgid(&init_user_ns, gid);
Steve Frencha6603392020-06-12 10:36:37 -05001076 if (id_from_sid) {
1077 struct owner_sid *gsid = (struct owner_sid *)ngroup_sid_ptr;
1078 /* Populate the group ownership fields S-1-5-88-2 */
1079 gsid->Revision = 1;
1080 gsid->NumAuth = 3;
1081 gsid->Authority[5] = 5;
1082 gsid->SubAuthorities[0] = cpu_to_le32(88);
1083 gsid->SubAuthorities[1] = cpu_to_le32(2);
1084 gsid->SubAuthorities[2] = cpu_to_le32(id);
1085 } else { /* lookup sid with upcall */
1086 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
1087 if (rc) {
1088 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
1089 __func__, rc, id);
1090 kfree(ngroup_sid_ptr);
1091 return rc;
1092 }
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001093 }
Jeff Layton36960e42012-11-03 09:37:28 -04001094 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001095 kfree(ngroup_sid_ptr);
1096 *aclflag = CIFS_ACL_GROUP;
1097 }
1098 }
Steve French97837582007-12-31 07:47:21 +00001099
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001100 return rc;
Steve French97837582007-12-31 07:47:21 +00001101}
1102
Steve French42eacf92014-02-10 14:08:16 -06001103struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1104 const struct cifs_fid *cifsfid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001105{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001106 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001107 unsigned int xid;
1108 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001109 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1110
1111 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001112 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001113
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001114 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001115 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1116 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001117 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001118
Jeff Layton7ffec372010-09-29 19:51:11 -04001119 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001120
Joe Perchesf96637b2013-05-04 22:12:25 -05001121 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001122 if (rc)
1123 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001124 return pntsd;
1125}
1126
1127static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1128 const char *path, u32 *pacllen)
1129{
1130 struct cifs_ntsd *pntsd = NULL;
1131 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001132 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001133 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00001134 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001135 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001136 struct cifs_fid fid;
1137 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001138
Jeff Layton7ffec372010-09-29 19:51:11 -04001139 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001140 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001141
1142 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001143 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001144
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001145 oparms.tcon = tcon;
1146 oparms.cifs_sb = cifs_sb;
1147 oparms.desired_access = READ_CONTROL;
Amir Goldstein0f060932020-02-03 21:46:43 +02001148 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001149 oparms.disposition = FILE_OPEN;
1150 oparms.path = path;
1151 oparms.fid = &fid;
1152 oparms.reconnect = false;
1153
1154 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001155 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001156 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1157 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001158 }
1159
Jeff Layton7ffec372010-09-29 19:51:11 -04001160 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001161 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001162
Joe Perchesf96637b2013-05-04 22:12:25 -05001163 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001164 if (rc)
1165 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001166 return pntsd;
1167}
1168
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001169/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001170struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001171 struct inode *inode, const char *path,
1172 u32 *pacllen)
1173{
1174 struct cifs_ntsd *pntsd = NULL;
1175 struct cifsFileInfo *open_file = NULL;
1176
1177 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001178 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001179 if (!open_file)
1180 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1181
Steve French42eacf92014-02-10 14:08:16 -06001182 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001183 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001184 return pntsd;
1185}
1186
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001187 /* Set an ACL on the server */
1188int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1189 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001190{
1191 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001192 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001193 int rc, access_flags;
Steve French96daf2b2011-05-27 04:34:02 +00001194 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001195 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001196 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001197 struct cifs_fid fid;
1198 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001199
Jeff Layton7ffec372010-09-29 19:51:11 -04001200 if (IS_ERR(tlink))
1201 return PTR_ERR(tlink);
1202
1203 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001204 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001205
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001206 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1207 access_flags = WRITE_OWNER;
1208 else
1209 access_flags = WRITE_DAC;
1210
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001211 oparms.tcon = tcon;
1212 oparms.cifs_sb = cifs_sb;
1213 oparms.desired_access = access_flags;
Amir Goldstein0f060932020-02-03 21:46:43 +02001214 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001215 oparms.disposition = FILE_OPEN;
1216 oparms.path = path;
1217 oparms.fid = &fid;
1218 oparms.reconnect = false;
1219
1220 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001221 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001222 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001223 goto out;
Steve French97837582007-12-31 07:47:21 +00001224 }
1225
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001226 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001227 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001228
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001229 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001230out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001231 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001232 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001233 return rc;
1234}
Steve French97837582007-12-31 07:47:21 +00001235
Achilles Gaikwad36c7ce42018-01-28 13:39:48 +05301236/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001237int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001238cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001239 struct inode *inode, bool mode_from_special_sid,
1240 const char *path, const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001241{
1242 struct cifs_ntsd *pntsd = NULL;
1243 u32 acllen = 0;
1244 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001245 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001246 struct smb_version_operations *ops;
Steve French7505e052007-11-01 18:03:01 +00001247
Joe Perchesf96637b2013-05-04 22:12:25 -05001248 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001249
Steve French42eacf92014-02-10 14:08:16 -06001250 if (IS_ERR(tlink))
1251 return PTR_ERR(tlink);
Steve French7505e052007-11-01 18:03:01 +00001252
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001253 ops = tlink_tcon(tlink)->ses->server->ops;
1254
1255 if (pfid && (ops->get_acl_by_fid))
1256 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
1257 else if (ops->get_acl)
1258 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
Steve French42eacf92014-02-10 14:08:16 -06001259 else {
1260 cifs_put_tlink(tlink);
1261 return -EOPNOTSUPP;
1262 }
Steve French7505e052007-11-01 18:03:01 +00001263 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001264 if (IS_ERR(pntsd)) {
1265 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001266 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001267 } else if (mode_from_special_sid) {
1268 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
Namjae Jeon98128572020-11-09 17:35:33 +09001269 kfree(pntsd);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001270 } else {
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001271 /* get approximated mode from ACL */
1272 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001273 kfree(pntsd);
1274 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001275 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001276 }
Steve French7505e052007-11-01 18:03:01 +00001277
Steve French42eacf92014-02-10 14:08:16 -06001278 cifs_put_tlink(tlink);
1279
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001280 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001281}
Steve French953f8682007-10-31 04:54:42 +00001282
Steve French7505e052007-11-01 18:03:01 +00001283/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001284int
1285id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001286 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001287{
1288 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001289 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001290 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001291 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1292 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001293 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1294 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001295 struct smb_version_operations *ops;
Steve Frencha6603392020-06-12 10:36:37 -05001296 bool mode_from_sid, id_from_sid;
Steve French83e3bc22014-02-02 23:31:47 -06001297
1298 if (IS_ERR(tlink))
1299 return PTR_ERR(tlink);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001300
1301 ops = tlink_tcon(tlink)->ses->server->ops;
Steve French953f8682007-10-31 04:54:42 +00001302
Joe Perchesf96637b2013-05-04 22:12:25 -05001303 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001304
1305 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001306
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001307 if (ops->get_acl == NULL) {
Steve French83e3bc22014-02-02 23:31:47 -06001308 cifs_put_tlink(tlink);
1309 return -EOPNOTSUPP;
1310 }
1311
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001312 pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001313 if (IS_ERR(pntsd)) {
1314 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001315 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001316 cifs_put_tlink(tlink);
1317 return rc;
Steve French97837582007-12-31 07:47:21 +00001318 }
1319
Jeff Laytonc78cd832012-11-25 08:00:35 -05001320 /*
1321 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1322 * as chmod disables ACEs and set the security descriptor. Allocate
1323 * memory for the smb header, set security descriptor request security
1324 * descriptor parameters, and secuirty descriptor itself
1325 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001326 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001327 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1328 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001329 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001330 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001331 return -ENOMEM;
1332 }
1333
Steve French22442172019-07-19 08:15:55 +00001334 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
1335 mode_from_sid = true;
1336 else
1337 mode_from_sid = false;
1338
Steve Frencha6603392020-06-12 10:36:37 -05001339 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL)
1340 id_from_sid = true;
1341 else
1342 id_from_sid = false;
1343
Jeff Laytonc78cd832012-11-25 08:00:35 -05001344 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
Steve Frencha6603392020-06-12 10:36:37 -05001345 mode_from_sid, id_from_sid, &aclflag);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001346
Joe Perchesf96637b2013-05-04 22:12:25 -05001347 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001348
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001349 if (ops->set_acl == NULL)
Steve French83e3bc22014-02-02 23:31:47 -06001350 rc = -EOPNOTSUPP;
1351
Jeff Laytonc78cd832012-11-25 08:00:35 -05001352 if (!rc) {
1353 /* Set the security descriptor */
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001354 rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001355 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001356 }
Steve French83e3bc22014-02-02 23:31:47 -06001357 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001358
1359 kfree(pnntsd);
1360 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001361 return rc;
Steve French953f8682007-10-31 04:54:42 +00001362}