blob: 15bac390dff945d7fa5d785f666b2b0291fb9f65 [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)} };
Steve Frenchbcb02032007-09-25 16:17:24 +000042/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000043static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000044
Steve French3514de32016-10-13 19:06:23 -050045/* S-1-22-1 Unmapped Unix users */
46static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
47 {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
48
49/* S-1-22-2 Unmapped Unix groups */
50static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
51 {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
52
53/*
54 * See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
55 */
56
57/* S-1-5-88 MS NFS and Apple style UID/GID/mode */
58
59/* S-1-5-88-1 Unix uid */
60static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
61 {cpu_to_le32(88),
62 cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
63
64/* S-1-5-88-2 Unix gid */
65static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
66 {cpu_to_le32(88),
67 cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
68
69/* S-1-5-88-3 Unix mode */
70static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
71 {cpu_to_le32(88),
72 cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
73
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050074static const struct cred *root_cred;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050075
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050076static int
David Howellscf7f6012012-09-13 13:06:29 +010077cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050078{
79 char *payload;
80
Jeff Layton41a9f1f2012-12-03 06:05:29 -050081 /*
82 * If the payload is less than or equal to the size of a pointer, then
83 * an allocation here is wasteful. Just copy the data directly to the
84 * payload.value union member instead.
85 *
86 * With this however, you must check the datalen before trying to
87 * dereference payload.data!
88 */
Jeff Layton1f630682012-12-03 06:05:31 -050089 if (prep->datalen <= sizeof(key->payload)) {
David Howells146aa8b2015-10-21 14:04:48 +010090 key->payload.data[0] = NULL;
91 memcpy(&key->payload, prep->data, prep->datalen);
92 } else {
93 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
94 if (!payload)
95 return -ENOMEM;
96 key->payload.data[0] = payload;
Jeff Layton41a9f1f2012-12-03 06:05:29 -050097 }
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050098
David Howellscf7f6012012-09-13 13:06:29 +010099 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500100 return 0;
101}
102
103static inline void
104cifs_idmap_key_destroy(struct key *key)
105{
Jeff Layton1f630682012-12-03 06:05:31 -0500106 if (key->datalen > sizeof(key->payload))
David Howells146aa8b2015-10-21 14:04:48 +0100107 kfree(key->payload.data[0]);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500108}
109
Jeff Laytonb1a6dc22012-11-25 08:00:38 -0500110static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -0500111 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500112 .instantiate = cifs_idmap_key_instantiate,
113 .destroy = cifs_idmap_key_destroy,
114 .describe = user_describe,
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500115};
116
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500117static char *
118sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500119{
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500120 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500121 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500122 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -0500123 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500124
125 /* 3 bytes for prefix */
126 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
127 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
128 GFP_KERNEL);
129 if (!sidstr)
130 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500131
132 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500133 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
134 sidptr->revision);
135 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500136
Jeff Layton193cdd82012-12-10 06:10:44 -0500137 /* The authority field is a single 48-bit number */
138 id_auth_val = (unsigned long long)sidptr->authority[5];
139 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
140 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
141 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
142 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
143 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
144
145 /*
146 * MS-DTYP states that if the authority is >= 2^32, then it should be
147 * expressed as a hex value.
148 */
149 if (id_auth_val <= UINT_MAX)
150 len = sprintf(strptr, "-%llu", id_auth_val);
151 else
152 len = sprintf(strptr, "-0x%llx", id_auth_val);
153
154 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500155
156 for (i = 0; i < sidptr->num_subauth; ++i) {
157 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500158 len = sprintf(strptr, "-%u", saval);
159 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500160 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500161
162 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500163}
164
Jeff Layton436bb432012-11-25 08:00:36 -0500165/*
166 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
167 * the same returns zero, if they do not match returns non-zero.
168 */
169static int
170compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
171{
172 int i;
173 int num_subauth, num_sat, num_saw;
174
175 if ((!ctsid) || (!cwsid))
176 return 1;
177
178 /* compare the revision */
179 if (ctsid->revision != cwsid->revision) {
180 if (ctsid->revision > cwsid->revision)
181 return 1;
182 else
183 return -1;
184 }
185
186 /* compare all of the six auth values */
187 for (i = 0; i < NUM_AUTHS; ++i) {
188 if (ctsid->authority[i] != cwsid->authority[i]) {
189 if (ctsid->authority[i] > cwsid->authority[i])
190 return 1;
191 else
192 return -1;
193 }
194 }
195
196 /* compare all of the subauth values if any */
197 num_sat = ctsid->num_subauth;
198 num_saw = cwsid->num_subauth;
199 num_subauth = num_sat < num_saw ? num_sat : num_saw;
200 if (num_subauth) {
201 for (i = 0; i < num_subauth; ++i) {
202 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
203 if (le32_to_cpu(ctsid->sub_auth[i]) >
204 le32_to_cpu(cwsid->sub_auth[i]))
205 return 1;
206 else
207 return -1;
208 }
209 }
210 }
211
212 return 0; /* sids compare/match */
213}
214
Steve French3514de32016-10-13 19:06:23 -0500215static bool
216is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
217{
218 int i;
219 int num_subauth;
220 const struct cifs_sid *pwell_known_sid;
221
222 if (!psid || (puid == NULL))
223 return false;
224
225 num_subauth = psid->num_subauth;
226
227 /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
228 if (num_subauth == 2) {
229 if (is_group)
230 pwell_known_sid = &sid_unix_groups;
231 else
232 pwell_known_sid = &sid_unix_users;
233 } else if (num_subauth == 3) {
234 if (is_group)
235 pwell_known_sid = &sid_unix_NFS_groups;
236 else
237 pwell_known_sid = &sid_unix_NFS_users;
238 } else
239 return false;
240
241 /* compare the revision */
242 if (psid->revision != pwell_known_sid->revision)
243 return false;
244
245 /* compare all of the six auth values */
246 for (i = 0; i < NUM_AUTHS; ++i) {
247 if (psid->authority[i] != pwell_known_sid->authority[i]) {
248 cifs_dbg(FYI, "auth %d did not match\n", i);
249 return false;
250 }
251 }
252
253 if (num_subauth == 2) {
254 if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
255 return false;
256
257 *puid = le32_to_cpu(psid->sub_auth[1]);
258 } else /* 3 subauths, ie Windows/Mac style */ {
259 *puid = le32_to_cpu(psid->sub_auth[0]);
260 if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
261 (psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
262 return false;
263
264 *puid = le32_to_cpu(psid->sub_auth[2]);
265 }
266
267 cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
268 return true; /* well known sid found, uid returned */
269}
270
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500271static void
Jeff Layton36960e42012-11-03 09:37:28 -0400272cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
273{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500274 int i;
275
276 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500277 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500278 for (i = 0; i < NUM_AUTHS; ++i)
279 dst->authority[i] = src->authority[i];
280 for (i = 0; i < dst->num_subauth; ++i)
281 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400282}
283
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500284static int
285id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500286{
287 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500288 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500289 struct cifs_sid *ksid;
290 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500291 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500292 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500293
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500294 rc = snprintf(desc, sizeof(desc), "%ci:%u",
295 sidtype == SIDOWNER ? 'o' : 'g', cid);
296 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500297 return -EINVAL;
298
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500299 rc = 0;
300 saved_cred = override_creds(root_cred);
301 sidkey = request_key(&cifs_idmap_key_type, desc, "");
302 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500303 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500304 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
305 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500306 goto out_revert_creds;
307 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
308 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500309 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
310 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500311 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500312 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500313
Jeff Layton1f630682012-12-03 06:05:31 -0500314 /*
315 * A sid is usually too large to be embedded in payload.value, but if
316 * there are no subauthorities and the host has 8-byte pointers, then
317 * it could be.
318 */
319 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
David Howells146aa8b2015-10-21 14:04:48 +0100320 (struct cifs_sid *)&sidkey->payload :
321 (struct cifs_sid *)sidkey->payload.data[0];
Jeff Layton1f630682012-12-03 06:05:31 -0500322
Jeff Layton2ae03022012-12-03 06:05:30 -0500323 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
324 if (ksid_size > sidkey->datalen) {
325 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500326 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
327 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500328 goto invalidate_key;
329 }
Jeff Layton1f630682012-12-03 06:05:31 -0500330
Jeff Layton2ae03022012-12-03 06:05:30 -0500331 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500332out_key_put:
333 key_put(sidkey);
334out_revert_creds:
335 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500336 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500337
338invalidate_key:
339 key_invalidate(sidkey);
340 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500341}
342
343static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500344sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
345 struct cifs_fattr *fattr, uint sidtype)
346{
347 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500348 struct key *sidkey;
349 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500350 const struct cred *saved_cred;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800351 kuid_t fuid = cifs_sb->mnt_uid;
352 kgid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500353
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500354 /*
355 * If we have too many subauthorities, then something is really wrong.
356 * Just return an error.
357 */
358 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500359 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
360 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500361 return -EIO;
362 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500363
Steve French3514de32016-10-13 19:06:23 -0500364 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) {
365 uint32_t unix_id;
366 bool is_group;
367
368 if (sidtype != SIDOWNER)
369 is_group = true;
370 else
371 is_group = false;
372
373 if (is_well_known_sid(psid, &unix_id, is_group) == false)
374 goto try_upcall_to_get_id;
375
376 if (is_group) {
377 kgid_t gid;
378 gid_t id;
379
380 id = (gid_t)unix_id;
381 gid = make_kgid(&init_user_ns, id);
382 if (gid_valid(gid)) {
383 fgid = gid;
384 goto got_valid_id;
385 }
386 } else {
387 kuid_t uid;
388 uid_t id;
389
390 id = (uid_t)unix_id;
391 uid = make_kuid(&init_user_ns, id);
392 if (uid_valid(uid)) {
393 fuid = uid;
394 goto got_valid_id;
395 }
396 }
397 /* If unable to find uid/gid easily from SID try via upcall */
398 }
399
400try_upcall_to_get_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500401 sidstr = sid_to_key_str(psid, sidtype);
402 if (!sidstr)
403 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500404
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500405 saved_cred = override_creds(root_cred);
406 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
407 if (IS_ERR(sidkey)) {
408 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500409 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
410 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500411 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500412 }
413
414 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500415 * FIXME: Here we assume that uid_t and gid_t are same size. It's
416 * probably a safe assumption but might be better to check based on
417 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500418 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800419 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500420 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500421 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500422 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
423 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500424 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500425 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500426 }
427
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800428 if (sidtype == SIDOWNER) {
429 kuid_t uid;
430 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100431 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800432 uid = make_kuid(&init_user_ns, id);
433 if (uid_valid(uid))
434 fuid = uid;
435 } else {
436 kgid_t gid;
437 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100438 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800439 gid = make_kgid(&init_user_ns, id);
440 if (gid_valid(gid))
441 fgid = gid;
442 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500443
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500444out_key_put:
445 key_put(sidkey);
446out_revert_creds:
447 revert_creds(saved_cred);
448 kfree(sidstr);
449
450 /*
451 * Note that we return 0 here unconditionally. If the mapping
452 * fails then we just fall back to using the mnt_uid/mnt_gid.
453 */
Steve French3514de32016-10-13 19:06:23 -0500454got_valid_id:
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500455 if (sidtype == SIDOWNER)
456 fattr->cf_uid = fuid;
457 else
458 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500459 return 0;
460}
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,
David Howellsf8aa23a2012-10-02 19:24:56 +0100484 (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
Joe Perchesf96637b2013-05-04 22:12:25 -0500606 cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\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
Joe Perchesf96637b2013-05-04 22:12:25 -0500635 cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
636 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
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000704
Steve Frencha750e772007-10-17 22:50:39 +0000705static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000706 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400707 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000708{
709 int i;
710 int num_aces = 0;
711 int acl_size;
712 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000713 struct cifs_ace **ppace;
714
715 /* BB need to add parm so we can store the SID BB */
716
Steve French2b834572007-11-25 10:01:00 +0000717 if (!pdacl) {
718 /* no DACL in the security descriptor, set
719 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400720 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000721 return;
722 }
723
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000724 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000725 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500726 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000727 return;
728 }
729
Joe Perchesf96637b2013-05-04 22:12:25 -0500730 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
731 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
732 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000733
Steve French7505e052007-11-01 18:03:01 +0000734 /* reset rwx permissions for user/group/other.
735 Also, if num_aces is 0 i.e. DACL has no ACEs,
736 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400737 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000738
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000739 acl_base = (char *)pdacl;
740 acl_size = sizeof(struct cifs_acl);
741
Steve Frenchadbc0352007-10-17 02:12:46 +0000742 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500743 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000744 umode_t user_mask = S_IRWXU;
745 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600746 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000747
Dan Carpenter72501702012-01-11 10:46:27 +0300748 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
749 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000750 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
751 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500752 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300753 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000754
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000755 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000756 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000757#ifdef CONFIG_CIFS_DEBUG2
758 dump_ace(ppace[i], end_of_acl);
759#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500760 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000761 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000762 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400763 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000764 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500765 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000766 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000767 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400768 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000769 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500770 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000771 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000772 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400773 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000774 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500775 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600776 access_flags_to_mode(ppace[i]->access_req,
777 ppace[i]->type,
778 &fattr->cf_mode,
779 &other_mask);
780
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000781
Steve French44093ca2007-10-23 21:22:55 +0000782/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000783 (void *)ppace[i],
784 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000785
Steve French44093ca2007-10-23 21:22:55 +0000786 acl_base = (char *)ppace[i];
787 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000788 }
789
790 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000791 }
792
793 return;
794}
795
Steve Frenchbcb02032007-09-25 16:17:24 +0000796
Steve French97837582007-12-31 07:47:21 +0000797static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
798 struct cifs_sid *pgrpsid, __u64 nmode)
799{
Al Viro2b210ad2008-03-29 03:09:18 +0000800 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000801 struct cifs_acl *pnndacl;
802
803 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
804
805 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
806 pownersid, nmode, S_IRWXU);
807 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
808 pgrpsid, nmode, S_IRWXG);
809 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
810 &sid_everyone, nmode, S_IRWXO);
811
812 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000813 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000814
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000815 return 0;
Steve French97837582007-12-31 07:47:21 +0000816}
817
818
Steve Frenchbcb02032007-09-25 16:17:24 +0000819static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
820{
821 /* BB need to add parm so we can store the SID BB */
822
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000823 /* validate that we do not go past end of ACL - sid must be at least 8
824 bytes long (assuming no sub-auths - e.g. the null SID */
825 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500826 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000827 return -EINVAL;
828 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000829
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000830#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500831 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000832 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500833 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
834 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000835
Steve Frenchaf6f4612007-10-16 18:40:37 +0000836 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500837 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
838 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000839 }
840
Steve Frenchd12fd122007-10-03 19:43:19 +0000841 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000842 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -0500843 cifs_dbg(FYI, "RID 0x%x\n",
844 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000845 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500846#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000847
Steve Frenchbcb02032007-09-25 16:17:24 +0000848 return 0;
849}
850
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000851
Steve Frenchbcb02032007-09-25 16:17:24 +0000852/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500853static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
854 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000855{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500856 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000857 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
858 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000859 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000860 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000861
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400862 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000863 return -EIO;
864
Steve Frenchbcb02032007-09-25 16:17:24 +0000865 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000866 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000867 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000868 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000869 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000870 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -0500871 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 +0000872 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
873 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000874 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000875/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000876 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500877 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500878 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000879 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500880 }
881 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
882 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500883 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
884 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500885 return rc;
886 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000887
888 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500889 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500890 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
891 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000892 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500893 }
894 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
895 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500896 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
897 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500898 return rc;
899 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000900
Steve French7505e052007-11-01 18:03:01 +0000901 if (dacloffset)
902 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400903 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000904 else
Joe Perchesf96637b2013-05-04 22:12:25 -0500905 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000906
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500907 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000908}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000909
Steve French97837582007-12-31 07:47:21 +0000910/* Convert permission bits from mode to equivalent CIFS ACL */
911static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800912 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000913{
914 int rc = 0;
915 __u32 dacloffset;
916 __u32 ndacloffset;
917 __u32 sidsoffset;
918 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500919 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000920 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
921 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
922
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500923 if (nmode != NO_CHANGE_64) { /* chmod */
924 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000925 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500926 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000927 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500928 dacloffset = le32_to_cpu(pntsd->dacloffset);
929 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
930 ndacloffset = sizeof(struct cifs_ntsd);
931 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
932 ndacl_ptr->revision = dacl_ptr->revision;
933 ndacl_ptr->size = 0;
934 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000935
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500936 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
937 nmode);
938 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
939 /* copy sec desc control portion & owner and group sids */
940 copy_sec_desc(pntsd, pnntsd, sidsoffset);
941 *aclflag = CIFS_ACL_DACL;
942 } else {
943 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800944 if (uid_valid(uid)) { /* chown */
945 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500946 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
947 le32_to_cpu(pnntsd->osidoffset));
948 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
949 GFP_KERNEL);
950 if (!nowner_sid_ptr)
951 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800952 id = from_kuid(&init_user_ns, uid);
953 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500954 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500955 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
956 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500957 kfree(nowner_sid_ptr);
958 return rc;
959 }
Jeff Layton36960e42012-11-03 09:37:28 -0400960 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500961 kfree(nowner_sid_ptr);
962 *aclflag = CIFS_ACL_OWNER;
963 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800964 if (gid_valid(gid)) { /* chgrp */
965 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500966 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
967 le32_to_cpu(pnntsd->gsidoffset));
968 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
969 GFP_KERNEL);
970 if (!ngroup_sid_ptr)
971 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800972 id = from_kgid(&init_user_ns, gid);
973 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500974 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500975 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
976 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500977 kfree(ngroup_sid_ptr);
978 return rc;
979 }
Jeff Layton36960e42012-11-03 09:37:28 -0400980 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500981 kfree(ngroup_sid_ptr);
982 *aclflag = CIFS_ACL_GROUP;
983 }
984 }
Steve French97837582007-12-31 07:47:21 +0000985
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000986 return rc;
Steve French97837582007-12-31 07:47:21 +0000987}
988
Steve French42eacf92014-02-10 14:08:16 -0600989struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
990 const struct cifs_fid *cifsfid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000991{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000992 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400993 unsigned int xid;
994 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400995 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
996
997 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600998 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000999
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001000 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -06001001 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1002 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001003 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001004
Jeff Layton7ffec372010-09-29 19:51:11 -04001005 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001006
Joe Perchesf96637b2013-05-04 22:12:25 -05001007 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001008 if (rc)
1009 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001010 return pntsd;
1011}
1012
1013static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1014 const char *path, u32 *pacllen)
1015{
1016 struct cifs_ntsd *pntsd = NULL;
1017 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001018 unsigned int xid;
1019 int rc, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +00001020 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001021 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001022 struct cifs_fid fid;
1023 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001024
Jeff Layton7ffec372010-09-29 19:51:11 -04001025 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001026 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001027
1028 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001029 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001030
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001031 if (backup_cred(cifs_sb))
1032 create_options |= CREATE_OPEN_BACKUP_INTENT;
1033
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001034 oparms.tcon = tcon;
1035 oparms.cifs_sb = cifs_sb;
1036 oparms.desired_access = READ_CONTROL;
1037 oparms.create_options = create_options;
1038 oparms.disposition = FILE_OPEN;
1039 oparms.path = path;
1040 oparms.fid = &fid;
1041 oparms.reconnect = false;
1042
1043 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001044 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001045 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1046 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001047 }
1048
Jeff Layton7ffec372010-09-29 19:51:11 -04001049 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001050 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001051
Joe Perchesf96637b2013-05-04 22:12:25 -05001052 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001053 if (rc)
1054 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001055 return pntsd;
1056}
1057
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001058/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001059struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001060 struct inode *inode, const char *path,
1061 u32 *pacllen)
1062{
1063 struct cifs_ntsd *pntsd = NULL;
1064 struct cifsFileInfo *open_file = NULL;
1065
1066 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001067 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001068 if (!open_file)
1069 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1070
Steve French42eacf92014-02-10 14:08:16 -06001071 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001072 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001073 return pntsd;
1074}
1075
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001076 /* Set an ACL on the server */
1077int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1078 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001079{
1080 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001081 unsigned int xid;
1082 int rc, access_flags, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +00001083 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001084 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001085 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001086 struct cifs_fid fid;
1087 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +00001088
Jeff Layton7ffec372010-09-29 19:51:11 -04001089 if (IS_ERR(tlink))
1090 return PTR_ERR(tlink);
1091
1092 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001093 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001094
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001095 if (backup_cred(cifs_sb))
1096 create_options |= CREATE_OPEN_BACKUP_INTENT;
1097
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001098 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1099 access_flags = WRITE_OWNER;
1100 else
1101 access_flags = WRITE_DAC;
1102
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001103 oparms.tcon = tcon;
1104 oparms.cifs_sb = cifs_sb;
1105 oparms.desired_access = access_flags;
1106 oparms.create_options = create_options;
1107 oparms.disposition = FILE_OPEN;
1108 oparms.path = path;
1109 oparms.fid = &fid;
1110 oparms.reconnect = false;
1111
1112 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001113 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -05001114 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001115 goto out;
Steve French97837582007-12-31 07:47:21 +00001116 }
1117
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001118 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001119 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +00001120
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001121 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001122out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001123 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001124 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001125 return rc;
1126}
Steve French97837582007-12-31 07:47:21 +00001127
Steve French7505e052007-11-01 18:03:01 +00001128/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001129int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001130cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve French42eacf92014-02-10 14:08:16 -06001131 struct inode *inode, const char *path,
1132 const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001133{
1134 struct cifs_ntsd *pntsd = NULL;
1135 u32 acllen = 0;
1136 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001137 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1138 struct cifs_tcon *tcon;
Steve French7505e052007-11-01 18:03:01 +00001139
Joe Perchesf96637b2013-05-04 22:12:25 -05001140 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001141
Steve French42eacf92014-02-10 14:08:16 -06001142 if (IS_ERR(tlink))
1143 return PTR_ERR(tlink);
1144 tcon = tlink_tcon(tlink);
Steve French7505e052007-11-01 18:03:01 +00001145
Steve French42eacf92014-02-10 14:08:16 -06001146 if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
1147 pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
1148 &acllen);
1149 else if (tcon->ses->server->ops->get_acl)
1150 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1151 &acllen);
1152 else {
1153 cifs_put_tlink(tlink);
1154 return -EOPNOTSUPP;
1155 }
Steve French7505e052007-11-01 18:03:01 +00001156 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001157 if (IS_ERR(pntsd)) {
1158 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001159 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001160 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001161 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001162 kfree(pntsd);
1163 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001164 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001165 }
Steve French7505e052007-11-01 18:03:01 +00001166
Steve French42eacf92014-02-10 14:08:16 -06001167 cifs_put_tlink(tlink);
1168
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001169 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001170}
Steve French953f8682007-10-31 04:54:42 +00001171
Steve French7505e052007-11-01 18:03:01 +00001172/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001173int
1174id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001175 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001176{
1177 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001178 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001179 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001180 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1181 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001182 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1183 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1184 struct cifs_tcon *tcon;
1185
1186 if (IS_ERR(tlink))
1187 return PTR_ERR(tlink);
1188 tcon = tlink_tcon(tlink);
Steve French953f8682007-10-31 04:54:42 +00001189
Joe Perchesf96637b2013-05-04 22:12:25 -05001190 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001191
1192 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001193
1194 if (tcon->ses->server->ops->get_acl == NULL) {
1195 cifs_put_tlink(tlink);
1196 return -EOPNOTSUPP;
1197 }
1198
1199 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1200 &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001201 if (IS_ERR(pntsd)) {
1202 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001203 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001204 cifs_put_tlink(tlink);
1205 return rc;
Steve French97837582007-12-31 07:47:21 +00001206 }
1207
Jeff Laytonc78cd832012-11-25 08:00:35 -05001208 /*
1209 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1210 * as chmod disables ACEs and set the security descriptor. Allocate
1211 * memory for the smb header, set security descriptor request security
1212 * descriptor parameters, and secuirty descriptor itself
1213 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001214 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001215 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1216 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001217 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001218 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001219 return -ENOMEM;
1220 }
1221
1222 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1223 &aclflag);
1224
Joe Perchesf96637b2013-05-04 22:12:25 -05001225 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001226
Steve French83e3bc22014-02-02 23:31:47 -06001227 if (tcon->ses->server->ops->set_acl == NULL)
1228 rc = -EOPNOTSUPP;
1229
Jeff Laytonc78cd832012-11-25 08:00:35 -05001230 if (!rc) {
1231 /* Set the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001232 rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
1233 path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001234 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001235 }
Steve French83e3bc22014-02-02 23:31:47 -06001236 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001237
1238 kfree(pnntsd);
1239 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001240 return rc;
Steve French953f8682007-10-31 04:54:42 +00001241}