blob: 716574aab3b6a88c823a1511569511bb6491a94a [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/*
52 * See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
53 */
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
341static int
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{
345 int rc;
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 French3514de32016-10-13 19:06:23 -0500362 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) {
363 uint32_t unix_id;
364 bool is_group;
365
366 if (sidtype != SIDOWNER)
367 is_group = true;
368 else
369 is_group = false;
370
371 if (is_well_known_sid(psid, &unix_id, is_group) == false)
372 goto try_upcall_to_get_id;
373
374 if (is_group) {
375 kgid_t gid;
376 gid_t id;
377
378 id = (gid_t)unix_id;
379 gid = make_kgid(&init_user_ns, id);
380 if (gid_valid(gid)) {
381 fgid = gid;
382 goto got_valid_id;
383 }
384 } else {
385 kuid_t uid;
386 uid_t id;
387
388 id = (uid_t)unix_id;
389 uid = make_kuid(&init_user_ns, id);
390 if (uid_valid(uid)) {
391 fuid = uid;
392 goto got_valid_id;
393 }
394 }
395 /* If unable to find uid/gid easily from SID try via upcall */
396 }
397
398try_upcall_to_get_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500399 sidstr = sid_to_key_str(psid, sidtype);
400 if (!sidstr)
401 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500402
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500403 saved_cred = override_creds(root_cred);
Linus Torvalds028db3e2019-07-10 18:43:43 -0700404 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500405 if (IS_ERR(sidkey)) {
406 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500407 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
408 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500409 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500410 }
411
412 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500413 * FIXME: Here we assume that uid_t and gid_t are same size. It's
414 * probably a safe assumption but might be better to check based on
415 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500416 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800417 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500418 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500419 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500420 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
421 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500422 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500423 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500424 }
425
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800426 if (sidtype == SIDOWNER) {
427 kuid_t uid;
428 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100429 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800430 uid = make_kuid(&init_user_ns, id);
431 if (uid_valid(uid))
432 fuid = uid;
433 } else {
434 kgid_t gid;
435 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100436 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800437 gid = make_kgid(&init_user_ns, id);
438 if (gid_valid(gid))
439 fgid = gid;
440 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500441
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500442out_key_put:
443 key_put(sidkey);
444out_revert_creds:
445 revert_creds(saved_cred);
446 kfree(sidstr);
447
448 /*
449 * Note that we return 0 here unconditionally. If the mapping
450 * fails then we just fall back to using the mnt_uid/mnt_gid.
451 */
Steve French3514de32016-10-13 19:06:23 -0500452got_valid_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500453 if (sidtype == SIDOWNER)
454 fattr->cf_uid = fuid;
455 else
456 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500457 return 0;
458}
459
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500460int
461init_cifs_idmap(void)
462{
463 struct cred *cred;
464 struct key *keyring;
465 int ret;
466
Joe Perchesf96637b2013-05-04 22:12:25 -0500467 cifs_dbg(FYI, "Registering the %s key type\n",
468 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500469
470 /* create an override credential set with a special thread keyring in
471 * which requests are cached
472 *
473 * this is used to prevent malicious redirections from being installed
474 * with add_key().
475 */
476 cred = prepare_kernel_cred(NULL);
477 if (!cred)
478 return -ENOMEM;
479
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800480 keyring = keyring_alloc(".cifs_idmap",
481 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
Linus Torvalds028db3e2019-07-10 18:43:43 -0700482 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
483 KEY_USR_VIEW | KEY_USR_READ,
David Howells5ac7eac2016-04-06 16:14:24 +0100484 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500485 if (IS_ERR(keyring)) {
486 ret = PTR_ERR(keyring);
487 goto failed_put_cred;
488 }
489
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500490 ret = register_key_type(&cifs_idmap_key_type);
491 if (ret < 0)
492 goto failed_put_key;
493
494 /* instruct request_key() to use this special keyring as a cache for
495 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000496 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500497 cred->thread_keyring = keyring;
498 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
499 root_cred = cred;
500
Joe Perchesf96637b2013-05-04 22:12:25 -0500501 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500502 return 0;
503
504failed_put_key:
505 key_put(keyring);
506failed_put_cred:
507 put_cred(cred);
508 return ret;
509}
510
511void
512exit_cifs_idmap(void)
513{
514 key_revoke(root_cred->thread_keyring);
515 unregister_key_type(&cifs_idmap_key_type);
516 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500517 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500518}
519
Steve French97837582007-12-31 07:47:21 +0000520/* copy ntsd, owner sid, and group sid from a security descriptor to another */
521static void copy_sec_desc(const struct cifs_ntsd *pntsd,
522 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
523{
Steve French97837582007-12-31 07:47:21 +0000524 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
525 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
526
527 /* copy security descriptor control portion */
528 pnntsd->revision = pntsd->revision;
529 pnntsd->type = pntsd->type;
530 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
531 pnntsd->sacloffset = 0;
532 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
533 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
534
535 /* copy owner sid */
536 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
537 le32_to_cpu(pntsd->osidoffset));
538 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400539 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000540
541 /* copy group sid */
542 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
543 le32_to_cpu(pntsd->gsidoffset));
544 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
545 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400546 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000547
548 return;
549}
550
551
Steve French630f3f0c2007-10-25 21:17:17 +0000552/*
553 change posix mode to reflect permissions
554 pmode is the existing mode (we only want to overwrite part of this
555 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
556*/
Al Viro9b5e6852007-12-05 08:24:38 +0000557static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000558 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000559{
Al Viro9b5e6852007-12-05 08:24:38 +0000560 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000561 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000562 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000563 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000564 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000565 for the operation you are trying to perform for your user */
566
567 /* For deny ACEs we change the mask so that subsequent allow access
568 control entries do not turn on the bits we are denying */
569 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000570 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000571 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000572
Al Viro9b5e6852007-12-05 08:24:38 +0000573 if ((flags & GENERIC_WRITE) ||
574 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000575 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000576 if ((flags & GENERIC_READ) ||
577 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000578 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000579 if ((flags & GENERIC_EXECUTE) ||
580 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000581 *pbits_to_set &= ~S_IXUGO;
582 return;
583 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500584 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000585 return;
586 }
587 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000588
Al Viro9b5e6852007-12-05 08:24:38 +0000589 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000590 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesf96637b2013-05-04 22:12:25 -0500591 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000592 return;
593 }
Al Viro9b5e6852007-12-05 08:24:38 +0000594 if ((flags & GENERIC_WRITE) ||
595 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000596 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000597 if ((flags & GENERIC_READ) ||
598 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000599 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000600 if ((flags & GENERIC_EXECUTE) ||
601 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000602 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000603
Frank Sorensonf52aa792020-02-12 15:31:48 -0600604 cifs_dbg(NOISY, "access flags 0x%x mode now %04o\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000605 return;
606}
607
Steve Frenchce06c9f2007-11-08 21:12:01 +0000608/*
609 Generate access flags to reflect permissions mode is the existing mode.
610 This function is called for every ACE in the DACL whose SID matches
611 with either owner or group or everyone.
612*/
613
614static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
615 __u32 *pace_flags)
616{
617 /* reset access mask */
618 *pace_flags = 0x0;
619
620 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
621 mode &= bits_to_use;
622
623 /* check for R/W/X UGO since we do not know whose flags
624 is this but we have cleared all the bits sans RWX for
625 either user or group or other as per bits_to_use */
626 if (mode & S_IRUGO)
627 *pace_flags |= SET_FILE_READ_RIGHTS;
628 if (mode & S_IWUGO)
629 *pace_flags |= SET_FILE_WRITE_RIGHTS;
630 if (mode & S_IXUGO)
631 *pace_flags |= SET_FILE_EXEC_RIGHTS;
632
Frank Sorensonf52aa792020-02-12 15:31:48 -0600633 cifs_dbg(NOISY, "mode: %04o, access flags now 0x%x\n",
Joe Perchesf96637b2013-05-04 22:12:25 -0500634 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000635 return;
636}
637
Al Viro2b210ad2008-03-29 03:09:18 +0000638static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000639 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
640{
641 int i;
642 __u16 size = 0;
643 __u32 access_req = 0;
644
645 pntace->type = ACCESS_ALLOWED;
646 pntace->flags = 0x0;
647 mode_to_access_flags(nmode, bits, &access_req);
648 if (!access_req)
649 access_req = SET_MINIMUM_RIGHTS;
650 pntace->access_req = cpu_to_le32(access_req);
651
652 pntace->sid.revision = psid->revision;
653 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500654 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000655 pntace->sid.authority[i] = psid->authority[i];
656 for (i = 0; i < psid->num_subauth; i++)
657 pntace->sid.sub_auth[i] = psid->sub_auth[i];
658
659 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
660 pntace->size = cpu_to_le16(size);
661
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000662 return size;
Steve French97837582007-12-31 07:47:21 +0000663}
664
Steve French297647c2007-10-12 04:11:59 +0000665
Steve French953f8682007-10-31 04:54:42 +0000666#ifdef CONFIG_CIFS_DEBUG2
667static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000668{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000669 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000670
671 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000672
Steve French44093ca2007-10-23 21:22:55 +0000673 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500674 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000675 return;
676 }
677
678 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500679 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000680 return;
Steve French44093ca2007-10-23 21:22:55 +0000681 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000682
Steve French44093ca2007-10-23 21:22:55 +0000683 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000684 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000685 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500686 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
687 pace->sid.revision, pace->sid.num_subauth, pace->type,
688 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000689 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500690 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
691 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000692 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000693
Steve Frenchd12fd122007-10-03 19:43:19 +0000694 /* BB add length check to make sure that we do not have huge
695 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000696 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000697
Steve Frenchd12fd122007-10-03 19:43:19 +0000698 return;
699}
Steve French953f8682007-10-31 04:54:42 +0000700#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000701
Steve Frencha750e772007-10-17 22:50:39 +0000702static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000703 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000704 struct cifs_fattr *fattr, bool mode_from_special_sid)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000705{
706 int i;
707 int num_aces = 0;
708 int acl_size;
709 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000710 struct cifs_ace **ppace;
711
712 /* BB need to add parm so we can store the SID BB */
713
Steve French2b834572007-11-25 10:01:00 +0000714 if (!pdacl) {
715 /* no DACL in the security descriptor, set
716 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400717 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000718 return;
719 }
720
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000721 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000722 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500723 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000724 return;
725 }
726
Joe Perchesf96637b2013-05-04 22:12:25 -0500727 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
728 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
729 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000730
Steve French7505e052007-11-01 18:03:01 +0000731 /* reset rwx permissions for user/group/other.
732 Also, if num_aces is 0 i.e. DACL has no ACEs,
733 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400734 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000735
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000736 acl_base = (char *)pdacl;
737 acl_size = sizeof(struct cifs_acl);
738
Steve Frenchadbc0352007-10-17 02:12:46 +0000739 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500740 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000741 umode_t user_mask = S_IRWXU;
742 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600743 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000744
Dan Carpenter72501702012-01-11 10:46:27 +0300745 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
746 return;
Kees Cook6da2ec52018-06-12 13:55:00 -0700747 ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
748 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500749 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300750 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000751
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000752 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000753 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000754#ifdef CONFIG_CIFS_DEBUG2
755 dump_ace(ppace[i], end_of_acl);
756#endif
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000757 if (mode_from_special_sid &&
758 (compare_sids(&(ppace[i]->sid),
759 &sid_unix_NFS_mode) == 0)) {
760 /*
761 * Full permissions are:
762 * 07777 = S_ISUID | S_ISGID | S_ISVTX |
763 * S_IRWXU | S_IRWXG | S_IRWXO
764 */
765 fattr->cf_mode &= ~07777;
766 fattr->cf_mode |=
767 le32_to_cpu(ppace[i]->sid.sub_auth[2]);
768 break;
769 } else if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000770 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000771 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400772 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000773 &user_mask);
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000774 else if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000775 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000776 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400777 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000778 &group_mask);
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000779 else if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000780 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000781 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400782 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000783 &other_mask);
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000784 else if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600785 access_flags_to_mode(ppace[i]->access_req,
786 ppace[i]->type,
787 &fattr->cf_mode,
788 &other_mask);
789
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000790
Steve French44093ca2007-10-23 21:22:55 +0000791/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000792 (void *)ppace[i],
793 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000794
Steve French44093ca2007-10-23 21:22:55 +0000795 acl_base = (char *)ppace[i];
796 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000797 }
798
799 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000800 }
801
802 return;
803}
804
Steve French643fbce2020-01-16 19:55:33 -0600805unsigned int setup_authusers_ACE(struct cifs_ace *pntace)
806{
807 int i;
808 unsigned int ace_size = 20;
809
810 pntace->type = ACCESS_ALLOWED_ACE_TYPE;
811 pntace->flags = 0x0;
812 pntace->access_req = cpu_to_le32(GENERIC_ALL);
813 pntace->sid.num_subauth = 1;
814 pntace->sid.revision = 1;
815 for (i = 0; i < NUM_AUTHS; i++)
816 pntace->sid.authority[i] = sid_authusers.authority[i];
817
818 pntace->sid.sub_auth[0] = sid_authusers.sub_auth[0];
819
820 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
821 pntace->size = cpu_to_le16(ace_size);
822 return ace_size;
823}
824
Steve Frenchfdef6652019-12-06 02:02:38 -0600825/*
826 * Fill in the special SID based on the mode. See
827 * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
828 */
829unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
830{
831 int i;
832 unsigned int ace_size = 28;
833
834 pntace->type = ACCESS_DENIED_ACE_TYPE;
835 pntace->flags = 0x0;
836 pntace->access_req = 0;
837 pntace->sid.num_subauth = 3;
838 pntace->sid.revision = 1;
839 for (i = 0; i < NUM_AUTHS; i++)
840 pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
841
842 pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
843 pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
844 pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
845
846 /* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
847 pntace->size = cpu_to_le16(ace_size);
848 return ace_size;
849}
Steve Frenchbcb02032007-09-25 16:17:24 +0000850
Steve French97837582007-12-31 07:47:21 +0000851static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
Steve French22442172019-07-19 08:15:55 +0000852 struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
Steve French97837582007-12-31 07:47:21 +0000853{
Al Viro2b210ad2008-03-29 03:09:18 +0000854 u16 size = 0;
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200855 u32 num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000856 struct cifs_acl *pnndacl;
857
858 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
859
Steve French22442172019-07-19 08:15:55 +0000860 if (modefromsid) {
861 struct cifs_ace *pntace =
862 (struct cifs_ace *)((char *)pnndacl + size);
Steve French22442172019-07-19 08:15:55 +0000863
Steve Frenchfdef6652019-12-06 02:02:38 -0600864 size += setup_special_mode_ACE(pntace, nmode);
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200865 num_aces++;
866 }
Steve French22442172019-07-19 08:15:55 +0000867
Aurelien Aptele37a02c2019-09-17 01:47:27 +0200868 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
869 pownersid, nmode, S_IRWXU);
870 num_aces++;
871 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
872 pgrpsid, nmode, S_IRWXG);
873 num_aces++;
874 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
875 &sid_everyone, nmode, S_IRWXO);
876 num_aces++;
877
878 pndacl->num_aces = cpu_to_le32(num_aces);
Steve French97837582007-12-31 07:47:21 +0000879 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Steve French97837582007-12-31 07:47:21 +0000880
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000881 return 0;
Steve French97837582007-12-31 07:47:21 +0000882}
883
884
Steve Frenchbcb02032007-09-25 16:17:24 +0000885static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
886{
887 /* BB need to add parm so we can store the SID BB */
888
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000889 /* validate that we do not go past end of ACL - sid must be at least 8
890 bytes long (assuming no sub-auths - e.g. the null SID */
891 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500892 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000893 return -EINVAL;
894 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000895
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000896#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500897 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000898 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500899 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
900 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000901
Steve Frenchaf6f4612007-10-16 18:40:37 +0000902 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500903 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
904 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000905 }
906
Steve Frenchd12fd122007-10-03 19:43:19 +0000907 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000908 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -0500909 cifs_dbg(FYI, "RID 0x%x\n",
910 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000911 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500912#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000913
Steve Frenchbcb02032007-09-25 16:17:24 +0000914 return 0;
915}
916
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000917
Steve Frenchbcb02032007-09-25 16:17:24 +0000918/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500919static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000920 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr,
921 bool get_mode_from_special_sid)
Steve Frenchbcb02032007-09-25 16:17:24 +0000922{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500923 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000924 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
925 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000926 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000927 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000928
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400929 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000930 return -EIO;
931
Steve Frenchbcb02032007-09-25 16:17:24 +0000932 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000933 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000934 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000935 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000936 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000937 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -0500938 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 +0000939 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
940 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000941 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000942/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000943 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500944 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500945 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000946 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500947 }
948 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
949 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500950 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
951 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500952 return rc;
953 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000954
955 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500956 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500957 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
958 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000959 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500960 }
961 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
962 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500963 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
964 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500965 return rc;
966 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000967
Steve French7505e052007-11-01 18:03:01 +0000968 if (dacloffset)
969 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +0000970 group_sid_ptr, fattr, get_mode_from_special_sid);
Steve French7505e052007-11-01 18:03:01 +0000971 else
Joe Perchesf96637b2013-05-04 22:12:25 -0500972 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000973
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500974 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000975}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000976
Steve French97837582007-12-31 07:47:21 +0000977/* Convert permission bits from mode to equivalent CIFS ACL */
978static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve French22442172019-07-19 08:15:55 +0000979 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid,
980 bool mode_from_sid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000981{
982 int rc = 0;
983 __u32 dacloffset;
984 __u32 ndacloffset;
985 __u32 sidsoffset;
986 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500987 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000988 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
989 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
990
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500991 if (nmode != NO_CHANGE_64) { /* chmod */
992 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000993 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500994 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000995 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500996 dacloffset = le32_to_cpu(pntsd->dacloffset);
997 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
998 ndacloffset = sizeof(struct cifs_ntsd);
999 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1000 ndacl_ptr->revision = dacl_ptr->revision;
1001 ndacl_ptr->size = 0;
1002 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001003
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001004 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
Steve French22442172019-07-19 08:15:55 +00001005 nmode, mode_from_sid);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001006 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1007 /* copy sec desc control portion & owner and group sids */
1008 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1009 *aclflag = CIFS_ACL_DACL;
1010 } else {
1011 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001012 if (uid_valid(uid)) { /* chown */
1013 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001014 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1015 le32_to_cpu(pnntsd->osidoffset));
1016 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1017 GFP_KERNEL);
1018 if (!nowner_sid_ptr)
1019 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001020 id = from_kuid(&init_user_ns, uid);
1021 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001022 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001023 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
1024 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001025 kfree(nowner_sid_ptr);
1026 return rc;
1027 }
Jeff Layton36960e42012-11-03 09:37:28 -04001028 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001029 kfree(nowner_sid_ptr);
1030 *aclflag = CIFS_ACL_OWNER;
1031 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001032 if (gid_valid(gid)) { /* chgrp */
1033 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001034 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1035 le32_to_cpu(pnntsd->gsidoffset));
1036 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1037 GFP_KERNEL);
1038 if (!ngroup_sid_ptr)
1039 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001040 id = from_kgid(&init_user_ns, gid);
1041 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001042 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001043 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
1044 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001045 kfree(ngroup_sid_ptr);
1046 return rc;
1047 }
Jeff Layton36960e42012-11-03 09:37:28 -04001048 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001049 kfree(ngroup_sid_ptr);
1050 *aclflag = CIFS_ACL_GROUP;
1051 }
1052 }
Steve French97837582007-12-31 07:47:21 +00001053
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001054 return rc;
Steve French97837582007-12-31 07:47:21 +00001055}
1056
Steve French42eacf92014-02-10 14:08:16 -06001057struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1058 const struct cifs_fid *cifsfid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001059{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001060 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001061 unsigned int xid;
1062 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001063 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1064
1065 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001066 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001067
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001068 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001069 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1070 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001071 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001072
Jeff Layton7ffec372010-09-29 19:51:11 -04001073 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001074
Joe Perchesf96637b2013-05-04 22:12:25 -05001075 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001076 if (rc)
1077 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001078 return pntsd;
1079}
1080
1081static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1082 const char *path, u32 *pacllen)
1083{
1084 struct cifs_ntsd *pntsd = NULL;
1085 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001086 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001087 int rc;
Steve French96daf2b2011-05-27 04:34:02 +00001088 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001089 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001090 struct cifs_fid fid;
1091 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001092
Jeff Layton7ffec372010-09-29 19:51:11 -04001093 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001094 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001095
1096 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001097 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001098
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001099 oparms.tcon = tcon;
1100 oparms.cifs_sb = cifs_sb;
1101 oparms.desired_access = READ_CONTROL;
Amir Goldstein0f060932020-02-03 21:46:43 +02001102 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001103 oparms.disposition = FILE_OPEN;
1104 oparms.path = path;
1105 oparms.fid = &fid;
1106 oparms.reconnect = false;
1107
1108 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001109 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001110 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1111 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001112 }
1113
Jeff Layton7ffec372010-09-29 19:51:11 -04001114 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001115 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001116
Joe Perchesf96637b2013-05-04 22:12:25 -05001117 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001118 if (rc)
1119 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001120 return pntsd;
1121}
1122
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001123/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001124struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001125 struct inode *inode, const char *path,
1126 u32 *pacllen)
1127{
1128 struct cifs_ntsd *pntsd = NULL;
1129 struct cifsFileInfo *open_file = NULL;
1130
1131 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001132 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001133 if (!open_file)
1134 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1135
Steve French42eacf92014-02-10 14:08:16 -06001136 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001137 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001138 return pntsd;
1139}
1140
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001141 /* Set an ACL on the server */
1142int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1143 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001144{
1145 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001146 unsigned int xid;
Amir Goldstein0f060932020-02-03 21:46:43 +02001147 int rc, access_flags;
Steve French96daf2b2011-05-27 04:34:02 +00001148 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001149 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001150 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001151 struct cifs_fid fid;
1152 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001153
Jeff Layton7ffec372010-09-29 19:51:11 -04001154 if (IS_ERR(tlink))
1155 return PTR_ERR(tlink);
1156
1157 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001158 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001159
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001160 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1161 access_flags = WRITE_OWNER;
1162 else
1163 access_flags = WRITE_DAC;
1164
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001165 oparms.tcon = tcon;
1166 oparms.cifs_sb = cifs_sb;
1167 oparms.desired_access = access_flags;
Amir Goldstein0f060932020-02-03 21:46:43 +02001168 oparms.create_options = cifs_create_options(cifs_sb, 0);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001169 oparms.disposition = FILE_OPEN;
1170 oparms.path = path;
1171 oparms.fid = &fid;
1172 oparms.reconnect = false;
1173
1174 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001175 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001176 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001177 goto out;
Steve French97837582007-12-31 07:47:21 +00001178 }
1179
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001180 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001181 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001182
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001183 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001184out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001185 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001186 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001187 return rc;
1188}
Steve French97837582007-12-31 07:47:21 +00001189
Achilles Gaikwad36c7ce42018-01-28 13:39:48 +05301190/* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001191int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001192cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001193 struct inode *inode, bool mode_from_special_sid,
1194 const char *path, const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001195{
1196 struct cifs_ntsd *pntsd = NULL;
1197 u32 acllen = 0;
1198 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001199 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001200 struct smb_version_operations *ops;
Steve French7505e052007-11-01 18:03:01 +00001201
Joe Perchesf96637b2013-05-04 22:12:25 -05001202 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001203
Steve French42eacf92014-02-10 14:08:16 -06001204 if (IS_ERR(tlink))
1205 return PTR_ERR(tlink);
Steve French7505e052007-11-01 18:03:01 +00001206
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001207 ops = tlink_tcon(tlink)->ses->server->ops;
1208
1209 if (pfid && (ops->get_acl_by_fid))
1210 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
1211 else if (ops->get_acl)
1212 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
Steve French42eacf92014-02-10 14:08:16 -06001213 else {
1214 cifs_put_tlink(tlink);
1215 return -EOPNOTSUPP;
1216 }
Steve French7505e052007-11-01 18:03:01 +00001217 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001218 if (IS_ERR(pntsd)) {
1219 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001220 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001221 } else if (mode_from_special_sid) {
1222 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, true);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001223 } else {
Steve Frenche2f8fbf2019-07-19 06:30:07 +00001224 /* get approximated mode from ACL */
1225 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr, false);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001226 kfree(pntsd);
1227 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001228 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001229 }
Steve French7505e052007-11-01 18:03:01 +00001230
Steve French42eacf92014-02-10 14:08:16 -06001231 cifs_put_tlink(tlink);
1232
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001233 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001234}
Steve French953f8682007-10-31 04:54:42 +00001235
Steve French7505e052007-11-01 18:03:01 +00001236/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001237int
1238id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001239 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001240{
1241 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001242 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001243 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001244 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1245 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001246 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1247 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001248 struct smb_version_operations *ops;
Steve French22442172019-07-19 08:15:55 +00001249 bool mode_from_sid;
Steve French83e3bc22014-02-02 23:31:47 -06001250
1251 if (IS_ERR(tlink))
1252 return PTR_ERR(tlink);
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001253
1254 ops = tlink_tcon(tlink)->ses->server->ops;
Steve French953f8682007-10-31 04:54:42 +00001255
Joe Perchesf96637b2013-05-04 22:12:25 -05001256 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001257
1258 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001259
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001260 if (ops->get_acl == NULL) {
Steve French83e3bc22014-02-02 23:31:47 -06001261 cifs_put_tlink(tlink);
1262 return -EOPNOTSUPP;
1263 }
1264
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001265 pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001266 if (IS_ERR(pntsd)) {
1267 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001268 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001269 cifs_put_tlink(tlink);
1270 return rc;
Steve French97837582007-12-31 07:47:21 +00001271 }
1272
Jeff Laytonc78cd832012-11-25 08:00:35 -05001273 /*
1274 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1275 * as chmod disables ACEs and set the security descriptor. Allocate
1276 * memory for the smb header, set security descriptor request security
1277 * descriptor parameters, and secuirty descriptor itself
1278 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001279 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001280 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1281 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001282 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001283 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001284 return -ENOMEM;
1285 }
1286
Steve French22442172019-07-19 08:15:55 +00001287 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)
1288 mode_from_sid = true;
1289 else
1290 mode_from_sid = false;
1291
Jeff Laytonc78cd832012-11-25 08:00:35 -05001292 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
Steve French22442172019-07-19 08:15:55 +00001293 mode_from_sid, &aclflag);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001294
Joe Perchesf96637b2013-05-04 22:12:25 -05001295 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001296
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001297 if (ops->set_acl == NULL)
Steve French83e3bc22014-02-02 23:31:47 -06001298 rc = -EOPNOTSUPP;
1299
Jeff Laytonc78cd832012-11-25 08:00:35 -05001300 if (!rc) {
1301 /* Set the security descriptor */
Joe Perches via samba-technicalecdcf622017-05-07 01:31:47 -07001302 rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001303 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001304 }
Steve French83e3bc22014-02-02 23:31:47 -06001305 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001306
1307 kfree(pnntsd);
1308 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001309 return rc;
Steve French953f8682007-10-31 04:54:42 +00001310}