blob: 8dd9212ffef58fb003f6745d5a850669ac1d9969 [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 = {
Steve French4f612582011-05-27 20:40:18 +000041 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_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
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050045static const struct cred *root_cred;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050046
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050047static int
David Howellscf7f6012012-09-13 13:06:29 +010048cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050049{
50 char *payload;
51
Jeff Layton41a9f1f2012-12-03 06:05:29 -050052 /*
53 * If the payload is less than or equal to the size of a pointer, then
54 * an allocation here is wasteful. Just copy the data directly to the
55 * payload.value union member instead.
56 *
57 * With this however, you must check the datalen before trying to
58 * dereference payload.data!
59 */
Jeff Layton1f630682012-12-03 06:05:31 -050060 if (prep->datalen <= sizeof(key->payload)) {
Jeff Layton41a9f1f2012-12-03 06:05:29 -050061 key->payload.value = 0;
62 memcpy(&key->payload.value, prep->data, prep->datalen);
63 key->datalen = prep->datalen;
64 return 0;
65 }
David Howellscf7f6012012-09-13 13:06:29 +010066 payload = kmalloc(prep->datalen, GFP_KERNEL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050067 if (!payload)
68 return -ENOMEM;
69
David Howellscf7f6012012-09-13 13:06:29 +010070 memcpy(payload, prep->data, prep->datalen);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050071 key->payload.data = payload;
David Howellscf7f6012012-09-13 13:06:29 +010072 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050073 return 0;
74}
75
76static inline void
77cifs_idmap_key_destroy(struct key *key)
78{
Jeff Layton1f630682012-12-03 06:05:31 -050079 if (key->datalen > sizeof(key->payload))
Jeff Layton41a9f1f2012-12-03 06:05:29 -050080 kfree(key->payload.data);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050081}
82
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050083static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -050084 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050085 .instantiate = cifs_idmap_key_instantiate,
86 .destroy = cifs_idmap_key_destroy,
87 .describe = user_describe,
88 .match = user_match,
89};
90
Jeff Laytonfaa65f02012-12-03 06:05:29 -050091static char *
92sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050093{
Jeff Laytonfaa65f02012-12-03 06:05:29 -050094 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -050095 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050096 char *sidstr, *strptr;
97
98 /* 3 bytes for prefix */
99 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
100 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
101 GFP_KERNEL);
102 if (!sidstr)
103 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500104
105 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500106 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
107 sidptr->revision);
108 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500109
Jeff Layton852e2292012-11-25 08:00:36 -0500110 for (i = 0; i < NUM_AUTHS; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500111 if (sidptr->authority[i]) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500112 len = sprintf(strptr, "-%hhu", sidptr->authority[i]);
113 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500114 }
115 }
116
117 for (i = 0; i < sidptr->num_subauth; ++i) {
118 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500119 len = sprintf(strptr, "-%u", saval);
120 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500121 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500122
123 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500124}
125
Jeff Layton436bb432012-11-25 08:00:36 -0500126/*
127 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
128 * the same returns zero, if they do not match returns non-zero.
129 */
130static int
131compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
132{
133 int i;
134 int num_subauth, num_sat, num_saw;
135
136 if ((!ctsid) || (!cwsid))
137 return 1;
138
139 /* compare the revision */
140 if (ctsid->revision != cwsid->revision) {
141 if (ctsid->revision > cwsid->revision)
142 return 1;
143 else
144 return -1;
145 }
146
147 /* compare all of the six auth values */
148 for (i = 0; i < NUM_AUTHS; ++i) {
149 if (ctsid->authority[i] != cwsid->authority[i]) {
150 if (ctsid->authority[i] > cwsid->authority[i])
151 return 1;
152 else
153 return -1;
154 }
155 }
156
157 /* compare all of the subauth values if any */
158 num_sat = ctsid->num_subauth;
159 num_saw = cwsid->num_subauth;
160 num_subauth = num_sat < num_saw ? num_sat : num_saw;
161 if (num_subauth) {
162 for (i = 0; i < num_subauth; ++i) {
163 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
164 if (le32_to_cpu(ctsid->sub_auth[i]) >
165 le32_to_cpu(cwsid->sub_auth[i]))
166 return 1;
167 else
168 return -1;
169 }
170 }
171 }
172
173 return 0; /* sids compare/match */
174}
175
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500176static void
Jeff Layton36960e42012-11-03 09:37:28 -0400177cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
178{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500179 int i;
180
181 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500182 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500183 for (i = 0; i < NUM_AUTHS; ++i)
184 dst->authority[i] = src->authority[i];
185 for (i = 0; i < dst->num_subauth; ++i)
186 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400187}
188
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500189static int
190id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500191{
192 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500193 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500194 struct cifs_sid *ksid;
195 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500196 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500197 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500198
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500199 rc = snprintf(desc, sizeof(desc), "%ci:%u",
200 sidtype == SIDOWNER ? 'o' : 'g', cid);
201 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500202 return -EINVAL;
203
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500204 rc = 0;
205 saved_cred = override_creds(root_cred);
206 sidkey = request_key(&cifs_idmap_key_type, desc, "");
207 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500208 rc = -EINVAL;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500209 cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
210 sidtype == SIDOWNER ? 'u' : 'g', cid);
211 goto out_revert_creds;
212 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
213 rc = -EIO;
214 cFYI(1, "%s: Downcall contained malformed key "
215 "(datalen=%hu)", __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500216 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500217 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500218
Jeff Layton1f630682012-12-03 06:05:31 -0500219 /*
220 * A sid is usually too large to be embedded in payload.value, but if
221 * there are no subauthorities and the host has 8-byte pointers, then
222 * it could be.
223 */
224 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
225 (struct cifs_sid *)&sidkey->payload.value :
226 (struct cifs_sid *)sidkey->payload.data;
227
Jeff Layton2ae03022012-12-03 06:05:30 -0500228 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
229 if (ksid_size > sidkey->datalen) {
230 rc = -EIO;
231 cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, "
232 "ksid_size=%u)", __func__, sidkey->datalen, ksid_size);
233 goto invalidate_key;
234 }
Jeff Layton1f630682012-12-03 06:05:31 -0500235
Jeff Layton2ae03022012-12-03 06:05:30 -0500236 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500237out_key_put:
238 key_put(sidkey);
239out_revert_creds:
240 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500241 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500242
243invalidate_key:
244 key_invalidate(sidkey);
245 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500246}
247
248static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500249sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
250 struct cifs_fattr *fattr, uint sidtype)
251{
252 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500253 struct key *sidkey;
254 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500255 const struct cred *saved_cred;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500256 uid_t fuid = cifs_sb->mnt_uid;
257 gid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500258
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500259 /*
260 * If we have too many subauthorities, then something is really wrong.
261 * Just return an error.
262 */
263 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
264 cFYI(1, "%s: %u subauthorities is too many!", __func__,
265 psid->num_subauth);
266 return -EIO;
267 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500268
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500269 sidstr = sid_to_key_str(psid, sidtype);
270 if (!sidstr)
271 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500272
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500273 saved_cred = override_creds(root_cred);
274 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
275 if (IS_ERR(sidkey)) {
276 rc = -EINVAL;
277 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
278 sidtype == SIDOWNER ? 'u' : 'g');
279 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500280 }
281
282 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500283 * FIXME: Here we assume that uid_t and gid_t are same size. It's
284 * probably a safe assumption but might be better to check based on
285 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500286 */
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500287 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500288 rc = -EIO;
289 cFYI(1, "%s: Downcall contained malformed key "
290 "(datalen=%hu)", __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500291 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500292 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500293 }
294
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500295 if (sidtype == SIDOWNER)
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500296 memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500297 else
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500298 memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500299
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500300out_key_put:
301 key_put(sidkey);
302out_revert_creds:
303 revert_creds(saved_cred);
304 kfree(sidstr);
305
306 /*
307 * Note that we return 0 here unconditionally. If the mapping
308 * fails then we just fall back to using the mnt_uid/mnt_gid.
309 */
310 if (sidtype == SIDOWNER)
311 fattr->cf_uid = fuid;
312 else
313 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500314 return 0;
315}
316
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500317int
318init_cifs_idmap(void)
319{
320 struct cred *cred;
321 struct key *keyring;
322 int ret;
323
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400324 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500325
326 /* create an override credential set with a special thread keyring in
327 * which requests are cached
328 *
329 * this is used to prevent malicious redirections from being installed
330 * with add_key().
331 */
332 cred = prepare_kernel_cred(NULL);
333 if (!cred)
334 return -ENOMEM;
335
336 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
337 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
338 KEY_USR_VIEW | KEY_USR_READ,
339 KEY_ALLOC_NOT_IN_QUOTA);
340 if (IS_ERR(keyring)) {
341 ret = PTR_ERR(keyring);
342 goto failed_put_cred;
343 }
344
345 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
346 if (ret < 0)
347 goto failed_put_key;
348
349 ret = register_key_type(&cifs_idmap_key_type);
350 if (ret < 0)
351 goto failed_put_key;
352
353 /* instruct request_key() to use this special keyring as a cache for
354 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000355 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500356 cred->thread_keyring = keyring;
357 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
358 root_cred = cred;
359
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400360 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500361 return 0;
362
363failed_put_key:
364 key_put(keyring);
365failed_put_cred:
366 put_cred(cred);
367 return ret;
368}
369
370void
371exit_cifs_idmap(void)
372{
373 key_revoke(root_cred->thread_keyring);
374 unregister_key_type(&cifs_idmap_key_type);
375 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400376 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500377}
378
Steve French97837582007-12-31 07:47:21 +0000379/* copy ntsd, owner sid, and group sid from a security descriptor to another */
380static void copy_sec_desc(const struct cifs_ntsd *pntsd,
381 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
382{
Steve French97837582007-12-31 07:47:21 +0000383 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
384 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
385
386 /* copy security descriptor control portion */
387 pnntsd->revision = pntsd->revision;
388 pnntsd->type = pntsd->type;
389 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
390 pnntsd->sacloffset = 0;
391 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
392 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
393
394 /* copy owner sid */
395 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
396 le32_to_cpu(pntsd->osidoffset));
397 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400398 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000399
400 /* copy group sid */
401 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
402 le32_to_cpu(pntsd->gsidoffset));
403 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
404 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400405 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000406
407 return;
408}
409
410
Steve French630f3f0c2007-10-25 21:17:17 +0000411/*
412 change posix mode to reflect permissions
413 pmode is the existing mode (we only want to overwrite part of this
414 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
415*/
Al Viro9b5e6852007-12-05 08:24:38 +0000416static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000417 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000418{
Al Viro9b5e6852007-12-05 08:24:38 +0000419 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000420 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000421 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000422 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000423 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000424 for the operation you are trying to perform for your user */
425
426 /* For deny ACEs we change the mask so that subsequent allow access
427 control entries do not turn on the bits we are denying */
428 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000429 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000430 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000431
Al Viro9b5e6852007-12-05 08:24:38 +0000432 if ((flags & GENERIC_WRITE) ||
433 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000434 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000435 if ((flags & GENERIC_READ) ||
436 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000437 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000438 if ((flags & GENERIC_EXECUTE) ||
439 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000440 *pbits_to_set &= ~S_IXUGO;
441 return;
442 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000443 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000444 return;
445 }
446 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000447
Al Viro9b5e6852007-12-05 08:24:38 +0000448 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000449 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000450 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000451 return;
452 }
Al Viro9b5e6852007-12-05 08:24:38 +0000453 if ((flags & GENERIC_WRITE) ||
454 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000455 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000456 if ((flags & GENERIC_READ) ||
457 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000458 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000459 if ((flags & GENERIC_EXECUTE) ||
460 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000461 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000462
Joe Perchesb6b38f72010-04-21 03:50:45 +0000463 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000464 return;
465}
466
Steve Frenchce06c9f2007-11-08 21:12:01 +0000467/*
468 Generate access flags to reflect permissions mode is the existing mode.
469 This function is called for every ACE in the DACL whose SID matches
470 with either owner or group or everyone.
471*/
472
473static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
474 __u32 *pace_flags)
475{
476 /* reset access mask */
477 *pace_flags = 0x0;
478
479 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
480 mode &= bits_to_use;
481
482 /* check for R/W/X UGO since we do not know whose flags
483 is this but we have cleared all the bits sans RWX for
484 either user or group or other as per bits_to_use */
485 if (mode & S_IRUGO)
486 *pace_flags |= SET_FILE_READ_RIGHTS;
487 if (mode & S_IWUGO)
488 *pace_flags |= SET_FILE_WRITE_RIGHTS;
489 if (mode & S_IXUGO)
490 *pace_flags |= SET_FILE_EXEC_RIGHTS;
491
Joe Perchesb6b38f72010-04-21 03:50:45 +0000492 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000493 return;
494}
495
Al Viro2b210ad2008-03-29 03:09:18 +0000496static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000497 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
498{
499 int i;
500 __u16 size = 0;
501 __u32 access_req = 0;
502
503 pntace->type = ACCESS_ALLOWED;
504 pntace->flags = 0x0;
505 mode_to_access_flags(nmode, bits, &access_req);
506 if (!access_req)
507 access_req = SET_MINIMUM_RIGHTS;
508 pntace->access_req = cpu_to_le32(access_req);
509
510 pntace->sid.revision = psid->revision;
511 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500512 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000513 pntace->sid.authority[i] = psid->authority[i];
514 for (i = 0; i < psid->num_subauth; i++)
515 pntace->sid.sub_auth[i] = psid->sub_auth[i];
516
517 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
518 pntace->size = cpu_to_le16(size);
519
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000520 return size;
Steve French97837582007-12-31 07:47:21 +0000521}
522
Steve French297647c2007-10-12 04:11:59 +0000523
Steve French953f8682007-10-31 04:54:42 +0000524#ifdef CONFIG_CIFS_DEBUG2
525static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000526{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000527 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000528
529 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000530
Steve French44093ca2007-10-23 21:22:55 +0000531 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000533 return;
534 }
535
536 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000537 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000538 return;
Steve French44093ca2007-10-23 21:22:55 +0000539 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000540
Steve French44093ca2007-10-23 21:22:55 +0000541 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000542 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000543 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000544 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000545 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000546 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000547 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000548 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
549 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000550 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000551
Steve Frenchd12fd122007-10-03 19:43:19 +0000552 /* BB add length check to make sure that we do not have huge
553 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000554 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000555
Steve Frenchd12fd122007-10-03 19:43:19 +0000556 return;
557}
Steve French953f8682007-10-31 04:54:42 +0000558#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000559
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000560
Steve Frencha750e772007-10-17 22:50:39 +0000561static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000562 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400563 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000564{
565 int i;
566 int num_aces = 0;
567 int acl_size;
568 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000569 struct cifs_ace **ppace;
570
571 /* BB need to add parm so we can store the SID BB */
572
Steve French2b834572007-11-25 10:01:00 +0000573 if (!pdacl) {
574 /* no DACL in the security descriptor, set
575 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400576 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000577 return;
578 }
579
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000580 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000581 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000582 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000583 return;
584 }
585
Joe Perchesb6b38f72010-04-21 03:50:45 +0000586 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000587 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000588 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000589
Steve French7505e052007-11-01 18:03:01 +0000590 /* reset rwx permissions for user/group/other.
591 Also, if num_aces is 0 i.e. DACL has no ACEs,
592 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400593 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000594
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000595 acl_base = (char *)pdacl;
596 acl_size = sizeof(struct cifs_acl);
597
Steve Frenchadbc0352007-10-17 02:12:46 +0000598 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500599 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000600 umode_t user_mask = S_IRWXU;
601 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600602 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000603
Dan Carpenter72501702012-01-11 10:46:27 +0300604 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
605 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000606 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
607 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300608 if (!ppace) {
609 cERROR(1, "DACL memory allocation error");
610 return;
611 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000612
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000613 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000614 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000615#ifdef CONFIG_CIFS_DEBUG2
616 dump_ace(ppace[i], end_of_acl);
617#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500618 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000619 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000620 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400621 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000622 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500623 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000624 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000625 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400626 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000627 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500628 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000629 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000630 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400631 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000632 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500633 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600634 access_flags_to_mode(ppace[i]->access_req,
635 ppace[i]->type,
636 &fattr->cf_mode,
637 &other_mask);
638
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000639
Steve French44093ca2007-10-23 21:22:55 +0000640/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000641 (void *)ppace[i],
642 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000643
Steve French44093ca2007-10-23 21:22:55 +0000644 acl_base = (char *)ppace[i];
645 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000646 }
647
648 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000649 }
650
651 return;
652}
653
Steve Frenchbcb02032007-09-25 16:17:24 +0000654
Steve French97837582007-12-31 07:47:21 +0000655static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
656 struct cifs_sid *pgrpsid, __u64 nmode)
657{
Al Viro2b210ad2008-03-29 03:09:18 +0000658 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000659 struct cifs_acl *pnndacl;
660
661 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
662
663 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
664 pownersid, nmode, S_IRWXU);
665 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
666 pgrpsid, nmode, S_IRWXG);
667 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
668 &sid_everyone, nmode, S_IRWXO);
669
670 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000671 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000672
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000673 return 0;
Steve French97837582007-12-31 07:47:21 +0000674}
675
676
Steve Frenchbcb02032007-09-25 16:17:24 +0000677static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
678{
679 /* BB need to add parm so we can store the SID BB */
680
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000681 /* validate that we do not go past end of ACL - sid must be at least 8
682 bytes long (assuming no sub-auths - e.g. the null SID */
683 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000684 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000685 return -EINVAL;
686 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000687
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000688#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500689 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000690 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000691 cFYI(1, "SID revision %d num_auth %d",
692 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000693
Steve Frenchaf6f4612007-10-16 18:40:37 +0000694 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000695 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
696 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000697 }
698
Steve Frenchd12fd122007-10-03 19:43:19 +0000699 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000700 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000701 cFYI(1, "RID 0x%x",
702 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000703 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500704#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000705
Steve Frenchbcb02032007-09-25 16:17:24 +0000706 return 0;
707}
708
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000709
Steve Frenchbcb02032007-09-25 16:17:24 +0000710/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500711static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
712 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000713{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500714 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000715 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
716 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000717 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000718 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000719
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400720 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000721 return -EIO;
722
Steve Frenchbcb02032007-09-25 16:17:24 +0000723 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000724 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000725 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000726 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000727 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000728 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000729 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000730 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000731 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
732 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000733 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000734/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000735 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500736 if (rc) {
737 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000738 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500739 }
740 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
741 if (rc) {
742 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
743 return rc;
744 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000745
746 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500747 if (rc) {
748 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000749 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500750 }
751 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
752 if (rc) {
753 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
754 return rc;
755 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000756
Steve French7505e052007-11-01 18:03:01 +0000757 if (dacloffset)
758 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400759 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000760 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000761 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000762
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500763 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000764}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000765
Steve French97837582007-12-31 07:47:21 +0000766/* Convert permission bits from mode to equivalent CIFS ACL */
767static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500768 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000769{
770 int rc = 0;
771 __u32 dacloffset;
772 __u32 ndacloffset;
773 __u32 sidsoffset;
774 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500775 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000776 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
777 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
778
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500779 if (nmode != NO_CHANGE_64) { /* chmod */
780 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000781 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500782 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000783 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500784 dacloffset = le32_to_cpu(pntsd->dacloffset);
785 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
786 ndacloffset = sizeof(struct cifs_ntsd);
787 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
788 ndacl_ptr->revision = dacl_ptr->revision;
789 ndacl_ptr->size = 0;
790 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000791
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500792 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
793 nmode);
794 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
795 /* copy sec desc control portion & owner and group sids */
796 copy_sec_desc(pntsd, pnntsd, sidsoffset);
797 *aclflag = CIFS_ACL_DACL;
798 } else {
799 memcpy(pnntsd, pntsd, secdesclen);
800 if (uid != NO_CHANGE_32) { /* chown */
801 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
802 le32_to_cpu(pnntsd->osidoffset));
803 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
804 GFP_KERNEL);
805 if (!nowner_sid_ptr)
806 return -ENOMEM;
807 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
808 if (rc) {
809 cFYI(1, "%s: Mapping error %d for owner id %d",
810 __func__, rc, uid);
811 kfree(nowner_sid_ptr);
812 return rc;
813 }
Jeff Layton36960e42012-11-03 09:37:28 -0400814 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500815 kfree(nowner_sid_ptr);
816 *aclflag = CIFS_ACL_OWNER;
817 }
818 if (gid != NO_CHANGE_32) { /* chgrp */
819 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
820 le32_to_cpu(pnntsd->gsidoffset));
821 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
822 GFP_KERNEL);
823 if (!ngroup_sid_ptr)
824 return -ENOMEM;
825 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
826 if (rc) {
827 cFYI(1, "%s: Mapping error %d for group id %d",
828 __func__, rc, gid);
829 kfree(ngroup_sid_ptr);
830 return rc;
831 }
Jeff Layton36960e42012-11-03 09:37:28 -0400832 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500833 kfree(ngroup_sid_ptr);
834 *aclflag = CIFS_ACL_GROUP;
835 }
836 }
Steve French97837582007-12-31 07:47:21 +0000837
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000838 return rc;
Steve French97837582007-12-31 07:47:21 +0000839}
840
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400841static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
842 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000843{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000844 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400845 unsigned int xid;
846 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400847 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
848
849 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600850 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000851
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400852 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400853 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400854 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000855
Jeff Layton7ffec372010-09-29 19:51:11 -0400856 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000857
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600858 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
859 if (rc)
860 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400861 return pntsd;
862}
863
864static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
865 const char *path, u32 *pacllen)
866{
867 struct cifs_ntsd *pntsd = NULL;
868 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400869 unsigned int xid;
870 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400871 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000872 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400873 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400874
Jeff Layton7ffec372010-09-29 19:51:11 -0400875 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600876 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400877
878 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400879 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400880
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500881 if (backup_cred(cifs_sb))
882 create_options |= CREATE_OPEN_BACKUP_INTENT;
883
884 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
885 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
886 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600887 if (!rc) {
888 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
889 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000890 }
891
Jeff Layton7ffec372010-09-29 19:51:11 -0400892 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400893 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600894
895 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
896 if (rc)
897 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000898 return pntsd;
899}
900
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400901/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600902struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400903 struct inode *inode, const char *path,
904 u32 *pacllen)
905{
906 struct cifs_ntsd *pntsd = NULL;
907 struct cifsFileInfo *open_file = NULL;
908
909 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400910 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400911 if (!open_file)
912 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
913
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700914 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400915 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400916 return pntsd;
917}
918
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500919 /* Set an ACL on the server */
920int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
921 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400922{
923 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400924 unsigned int xid;
925 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000926 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000927 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500928 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400929 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000930
Jeff Layton7ffec372010-09-29 19:51:11 -0400931 if (IS_ERR(tlink))
932 return PTR_ERR(tlink);
933
934 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400935 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000936
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500937 if (backup_cred(cifs_sb))
938 create_options |= CREATE_OPEN_BACKUP_INTENT;
939
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500940 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
941 access_flags = WRITE_OWNER;
942 else
943 access_flags = WRITE_DAC;
944
945 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
946 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
947 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400948 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000949 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400950 goto out;
Steve French97837582007-12-31 07:47:21 +0000951 }
952
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500953 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000954 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000955
Jeff Layton7ffec372010-09-29 19:51:11 -0400956 CIFSSMBClose(xid, tcon, fid);
957out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400958 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400959 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400960 return rc;
961}
Steve French97837582007-12-31 07:47:21 +0000962
Steve French7505e052007-11-01 18:03:01 +0000963/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600964int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400965cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
966 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000967{
968 struct cifs_ntsd *pntsd = NULL;
969 u32 acllen = 0;
970 int rc = 0;
971
Joe Perchesb6b38f72010-04-21 03:50:45 +0000972 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400973
974 if (pfid)
975 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
976 else
977 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000978
979 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600980 if (IS_ERR(pntsd)) {
981 rc = PTR_ERR(pntsd);
982 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
983 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500984 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600985 kfree(pntsd);
986 if (rc)
987 cERROR(1, "parse sec desc failed rc = %d", rc);
988 }
Steve French7505e052007-11-01 18:03:01 +0000989
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600990 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000991}
Steve French953f8682007-10-31 04:54:42 +0000992
Steve French7505e052007-11-01 18:03:01 +0000993/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500994int
995id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
996 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +0000997{
998 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500999 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001000 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001001 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1002 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001003
Joe Perchesb6b38f72010-04-21 03:50:45 +00001004 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001005
1006 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001007 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001008 if (IS_ERR(pntsd)) {
1009 rc = PTR_ERR(pntsd);
1010 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001011 goto out;
Steve French97837582007-12-31 07:47:21 +00001012 }
1013
Jeff Laytonc78cd832012-11-25 08:00:35 -05001014 /*
1015 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1016 * as chmod disables ACEs and set the security descriptor. Allocate
1017 * memory for the smb header, set security descriptor request security
1018 * descriptor parameters, and secuirty descriptor itself
1019 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001020 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001021 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1022 if (!pnntsd) {
1023 cERROR(1, "Unable to allocate security descriptor");
1024 kfree(pntsd);
1025 return -ENOMEM;
1026 }
1027
1028 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1029 &aclflag);
1030
1031 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1032
1033 if (!rc) {
1034 /* Set the security descriptor */
1035 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1036 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1037 }
1038
1039 kfree(pnntsd);
1040 kfree(pntsd);
1041out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001042 return rc;
Steve French953f8682007-10-31 04:54:42 +00001043}