blob: b0b114acdecea33722496e0ec7823ba035ba2d28 [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 */
60 if (prep->datalen <= sizeof(void *)) {
61 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 Layton41a9f1f2012-12-03 06:05:29 -050079 if (key->datalen > sizeof(void *))
80 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
219 ksid = (struct cifs_sid *)sidkey->payload.data;
220 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
221 if (ksid_size > sidkey->datalen) {
222 rc = -EIO;
223 cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, "
224 "ksid_size=%u)", __func__, sidkey->datalen, ksid_size);
225 goto invalidate_key;
226 }
227 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500228out_key_put:
229 key_put(sidkey);
230out_revert_creds:
231 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500232 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500233
234invalidate_key:
235 key_invalidate(sidkey);
236 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500237}
238
239static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500240sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
241 struct cifs_fattr *fattr, uint sidtype)
242{
243 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500244 struct key *sidkey;
245 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500246 const struct cred *saved_cred;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500247 uid_t fuid = cifs_sb->mnt_uid;
248 gid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500249
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500250 /*
251 * If we have too many subauthorities, then something is really wrong.
252 * Just return an error.
253 */
254 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
255 cFYI(1, "%s: %u subauthorities is too many!", __func__,
256 psid->num_subauth);
257 return -EIO;
258 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500259
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500260 sidstr = sid_to_key_str(psid, sidtype);
261 if (!sidstr)
262 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500263
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500264 saved_cred = override_creds(root_cred);
265 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
266 if (IS_ERR(sidkey)) {
267 rc = -EINVAL;
268 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
269 sidtype == SIDOWNER ? 'u' : 'g');
270 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500271 }
272
273 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500274 * FIXME: Here we assume that uid_t and gid_t are same size. It's
275 * probably a safe assumption but might be better to check based on
276 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500277 */
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500278 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500279 rc = -EIO;
280 cFYI(1, "%s: Downcall contained malformed key "
281 "(datalen=%hu)", __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500282 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500283 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500284 }
285
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500286 if (sidtype == SIDOWNER)
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500287 memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500288 else
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500289 memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500290
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500291out_key_put:
292 key_put(sidkey);
293out_revert_creds:
294 revert_creds(saved_cred);
295 kfree(sidstr);
296
297 /*
298 * Note that we return 0 here unconditionally. If the mapping
299 * fails then we just fall back to using the mnt_uid/mnt_gid.
300 */
301 if (sidtype == SIDOWNER)
302 fattr->cf_uid = fuid;
303 else
304 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500305 return 0;
306}
307
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500308int
309init_cifs_idmap(void)
310{
311 struct cred *cred;
312 struct key *keyring;
313 int ret;
314
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400315 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500316
317 /* create an override credential set with a special thread keyring in
318 * which requests are cached
319 *
320 * this is used to prevent malicious redirections from being installed
321 * with add_key().
322 */
323 cred = prepare_kernel_cred(NULL);
324 if (!cred)
325 return -ENOMEM;
326
327 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
328 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
329 KEY_USR_VIEW | KEY_USR_READ,
330 KEY_ALLOC_NOT_IN_QUOTA);
331 if (IS_ERR(keyring)) {
332 ret = PTR_ERR(keyring);
333 goto failed_put_cred;
334 }
335
336 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
337 if (ret < 0)
338 goto failed_put_key;
339
340 ret = register_key_type(&cifs_idmap_key_type);
341 if (ret < 0)
342 goto failed_put_key;
343
344 /* instruct request_key() to use this special keyring as a cache for
345 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000346 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500347 cred->thread_keyring = keyring;
348 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
349 root_cred = cred;
350
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400351 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500352 return 0;
353
354failed_put_key:
355 key_put(keyring);
356failed_put_cred:
357 put_cred(cred);
358 return ret;
359}
360
361void
362exit_cifs_idmap(void)
363{
364 key_revoke(root_cred->thread_keyring);
365 unregister_key_type(&cifs_idmap_key_type);
366 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400367 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500368}
369
Steve French97837582007-12-31 07:47:21 +0000370/* copy ntsd, owner sid, and group sid from a security descriptor to another */
371static void copy_sec_desc(const struct cifs_ntsd *pntsd,
372 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
373{
Steve French97837582007-12-31 07:47:21 +0000374 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
375 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
376
377 /* copy security descriptor control portion */
378 pnntsd->revision = pntsd->revision;
379 pnntsd->type = pntsd->type;
380 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
381 pnntsd->sacloffset = 0;
382 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
383 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
384
385 /* copy owner sid */
386 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
387 le32_to_cpu(pntsd->osidoffset));
388 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400389 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000390
391 /* copy group sid */
392 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
393 le32_to_cpu(pntsd->gsidoffset));
394 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
395 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400396 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000397
398 return;
399}
400
401
Steve French630f3f0c2007-10-25 21:17:17 +0000402/*
403 change posix mode to reflect permissions
404 pmode is the existing mode (we only want to overwrite part of this
405 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
406*/
Al Viro9b5e6852007-12-05 08:24:38 +0000407static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000408 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000409{
Al Viro9b5e6852007-12-05 08:24:38 +0000410 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000411 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000412 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000413 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000414 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000415 for the operation you are trying to perform for your user */
416
417 /* For deny ACEs we change the mask so that subsequent allow access
418 control entries do not turn on the bits we are denying */
419 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000420 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000421 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000422
Al Viro9b5e6852007-12-05 08:24:38 +0000423 if ((flags & GENERIC_WRITE) ||
424 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000425 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000426 if ((flags & GENERIC_READ) ||
427 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000428 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000429 if ((flags & GENERIC_EXECUTE) ||
430 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000431 *pbits_to_set &= ~S_IXUGO;
432 return;
433 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000434 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000435 return;
436 }
437 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000438
Al Viro9b5e6852007-12-05 08:24:38 +0000439 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000440 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000441 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000442 return;
443 }
Al Viro9b5e6852007-12-05 08:24:38 +0000444 if ((flags & GENERIC_WRITE) ||
445 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000446 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000447 if ((flags & GENERIC_READ) ||
448 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000449 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000450 if ((flags & GENERIC_EXECUTE) ||
451 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000452 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000453
Joe Perchesb6b38f72010-04-21 03:50:45 +0000454 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000455 return;
456}
457
Steve Frenchce06c9f2007-11-08 21:12:01 +0000458/*
459 Generate access flags to reflect permissions mode is the existing mode.
460 This function is called for every ACE in the DACL whose SID matches
461 with either owner or group or everyone.
462*/
463
464static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
465 __u32 *pace_flags)
466{
467 /* reset access mask */
468 *pace_flags = 0x0;
469
470 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
471 mode &= bits_to_use;
472
473 /* check for R/W/X UGO since we do not know whose flags
474 is this but we have cleared all the bits sans RWX for
475 either user or group or other as per bits_to_use */
476 if (mode & S_IRUGO)
477 *pace_flags |= SET_FILE_READ_RIGHTS;
478 if (mode & S_IWUGO)
479 *pace_flags |= SET_FILE_WRITE_RIGHTS;
480 if (mode & S_IXUGO)
481 *pace_flags |= SET_FILE_EXEC_RIGHTS;
482
Joe Perchesb6b38f72010-04-21 03:50:45 +0000483 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000484 return;
485}
486
Al Viro2b210ad2008-03-29 03:09:18 +0000487static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000488 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
489{
490 int i;
491 __u16 size = 0;
492 __u32 access_req = 0;
493
494 pntace->type = ACCESS_ALLOWED;
495 pntace->flags = 0x0;
496 mode_to_access_flags(nmode, bits, &access_req);
497 if (!access_req)
498 access_req = SET_MINIMUM_RIGHTS;
499 pntace->access_req = cpu_to_le32(access_req);
500
501 pntace->sid.revision = psid->revision;
502 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500503 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000504 pntace->sid.authority[i] = psid->authority[i];
505 for (i = 0; i < psid->num_subauth; i++)
506 pntace->sid.sub_auth[i] = psid->sub_auth[i];
507
508 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
509 pntace->size = cpu_to_le16(size);
510
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000511 return size;
Steve French97837582007-12-31 07:47:21 +0000512}
513
Steve French297647c2007-10-12 04:11:59 +0000514
Steve French953f8682007-10-31 04:54:42 +0000515#ifdef CONFIG_CIFS_DEBUG2
516static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000517{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000518 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000519
520 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000521
Steve French44093ca2007-10-23 21:22:55 +0000522 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000523 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000524 return;
525 }
526
527 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000528 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000529 return;
Steve French44093ca2007-10-23 21:22:55 +0000530 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000531
Steve French44093ca2007-10-23 21:22:55 +0000532 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000533 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000534 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000535 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000536 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000537 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000538 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000539 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
540 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000541 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000542
Steve Frenchd12fd122007-10-03 19:43:19 +0000543 /* BB add length check to make sure that we do not have huge
544 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000545 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000546
Steve Frenchd12fd122007-10-03 19:43:19 +0000547 return;
548}
Steve French953f8682007-10-31 04:54:42 +0000549#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000550
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000551
Steve Frencha750e772007-10-17 22:50:39 +0000552static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000553 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400554 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000555{
556 int i;
557 int num_aces = 0;
558 int acl_size;
559 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000560 struct cifs_ace **ppace;
561
562 /* BB need to add parm so we can store the SID BB */
563
Steve French2b834572007-11-25 10:01:00 +0000564 if (!pdacl) {
565 /* no DACL in the security descriptor, set
566 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400567 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000568 return;
569 }
570
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000571 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000572 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000573 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000574 return;
575 }
576
Joe Perchesb6b38f72010-04-21 03:50:45 +0000577 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000578 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000579 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000580
Steve French7505e052007-11-01 18:03:01 +0000581 /* reset rwx permissions for user/group/other.
582 Also, if num_aces is 0 i.e. DACL has no ACEs,
583 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400584 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000585
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000586 acl_base = (char *)pdacl;
587 acl_size = sizeof(struct cifs_acl);
588
Steve Frenchadbc0352007-10-17 02:12:46 +0000589 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500590 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000591 umode_t user_mask = S_IRWXU;
592 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600593 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000594
Dan Carpenter72501702012-01-11 10:46:27 +0300595 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
596 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000597 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
598 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300599 if (!ppace) {
600 cERROR(1, "DACL memory allocation error");
601 return;
602 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000603
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000604 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000605 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000606#ifdef CONFIG_CIFS_DEBUG2
607 dump_ace(ppace[i], end_of_acl);
608#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500609 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000610 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000611 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400612 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000613 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500614 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000615 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000616 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400617 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000618 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500619 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000620 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000621 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400622 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000623 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500624 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600625 access_flags_to_mode(ppace[i]->access_req,
626 ppace[i]->type,
627 &fattr->cf_mode,
628 &other_mask);
629
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000630
Steve French44093ca2007-10-23 21:22:55 +0000631/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000632 (void *)ppace[i],
633 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000634
Steve French44093ca2007-10-23 21:22:55 +0000635 acl_base = (char *)ppace[i];
636 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000637 }
638
639 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000640 }
641
642 return;
643}
644
Steve Frenchbcb02032007-09-25 16:17:24 +0000645
Steve French97837582007-12-31 07:47:21 +0000646static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
647 struct cifs_sid *pgrpsid, __u64 nmode)
648{
Al Viro2b210ad2008-03-29 03:09:18 +0000649 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000650 struct cifs_acl *pnndacl;
651
652 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
653
654 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
655 pownersid, nmode, S_IRWXU);
656 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
657 pgrpsid, nmode, S_IRWXG);
658 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
659 &sid_everyone, nmode, S_IRWXO);
660
661 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000662 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000663
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000664 return 0;
Steve French97837582007-12-31 07:47:21 +0000665}
666
667
Steve Frenchbcb02032007-09-25 16:17:24 +0000668static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
669{
670 /* BB need to add parm so we can store the SID BB */
671
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000672 /* validate that we do not go past end of ACL - sid must be at least 8
673 bytes long (assuming no sub-auths - e.g. the null SID */
674 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000675 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000676 return -EINVAL;
677 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000678
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000679#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500680 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000681 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000682 cFYI(1, "SID revision %d num_auth %d",
683 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000684
Steve Frenchaf6f4612007-10-16 18:40:37 +0000685 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000686 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
687 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000688 }
689
Steve Frenchd12fd122007-10-03 19:43:19 +0000690 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000691 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cFYI(1, "RID 0x%x",
693 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000694 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500695#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000696
Steve Frenchbcb02032007-09-25 16:17:24 +0000697 return 0;
698}
699
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000700
Steve Frenchbcb02032007-09-25 16:17:24 +0000701/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500702static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
703 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000704{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500705 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000706 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
707 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000708 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000709 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000710
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400711 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000712 return -EIO;
713
Steve Frenchbcb02032007-09-25 16:17:24 +0000714 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000715 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000716 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000717 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000718 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000719 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000720 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000721 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000722 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
723 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000724 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000725/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000726 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500727 if (rc) {
728 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000729 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500730 }
731 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
732 if (rc) {
733 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
734 return rc;
735 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000736
737 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500738 if (rc) {
739 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000740 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500741 }
742 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
743 if (rc) {
744 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
745 return rc;
746 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000747
Steve French7505e052007-11-01 18:03:01 +0000748 if (dacloffset)
749 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400750 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000751 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000752 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000753
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500754 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000755}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000756
Steve French97837582007-12-31 07:47:21 +0000757/* Convert permission bits from mode to equivalent CIFS ACL */
758static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500759 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000760{
761 int rc = 0;
762 __u32 dacloffset;
763 __u32 ndacloffset;
764 __u32 sidsoffset;
765 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500766 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000767 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
768 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
769
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500770 if (nmode != NO_CHANGE_64) { /* chmod */
771 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000772 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500773 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000774 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500775 dacloffset = le32_to_cpu(pntsd->dacloffset);
776 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
777 ndacloffset = sizeof(struct cifs_ntsd);
778 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
779 ndacl_ptr->revision = dacl_ptr->revision;
780 ndacl_ptr->size = 0;
781 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000782
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500783 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
784 nmode);
785 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
786 /* copy sec desc control portion & owner and group sids */
787 copy_sec_desc(pntsd, pnntsd, sidsoffset);
788 *aclflag = CIFS_ACL_DACL;
789 } else {
790 memcpy(pnntsd, pntsd, secdesclen);
791 if (uid != NO_CHANGE_32) { /* chown */
792 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
793 le32_to_cpu(pnntsd->osidoffset));
794 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
795 GFP_KERNEL);
796 if (!nowner_sid_ptr)
797 return -ENOMEM;
798 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
799 if (rc) {
800 cFYI(1, "%s: Mapping error %d for owner id %d",
801 __func__, rc, uid);
802 kfree(nowner_sid_ptr);
803 return rc;
804 }
Jeff Layton36960e42012-11-03 09:37:28 -0400805 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500806 kfree(nowner_sid_ptr);
807 *aclflag = CIFS_ACL_OWNER;
808 }
809 if (gid != NO_CHANGE_32) { /* chgrp */
810 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
811 le32_to_cpu(pnntsd->gsidoffset));
812 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
813 GFP_KERNEL);
814 if (!ngroup_sid_ptr)
815 return -ENOMEM;
816 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
817 if (rc) {
818 cFYI(1, "%s: Mapping error %d for group id %d",
819 __func__, rc, gid);
820 kfree(ngroup_sid_ptr);
821 return rc;
822 }
Jeff Layton36960e42012-11-03 09:37:28 -0400823 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500824 kfree(ngroup_sid_ptr);
825 *aclflag = CIFS_ACL_GROUP;
826 }
827 }
Steve French97837582007-12-31 07:47:21 +0000828
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000829 return rc;
Steve French97837582007-12-31 07:47:21 +0000830}
831
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400832static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
833 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000834{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000835 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400836 unsigned int xid;
837 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400838 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
839
840 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600841 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000842
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400843 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400844 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400845 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000846
Jeff Layton7ffec372010-09-29 19:51:11 -0400847 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000848
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600849 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
850 if (rc)
851 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400852 return pntsd;
853}
854
855static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
856 const char *path, u32 *pacllen)
857{
858 struct cifs_ntsd *pntsd = NULL;
859 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400860 unsigned int xid;
861 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400862 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000863 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400864 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400865
Jeff Layton7ffec372010-09-29 19:51:11 -0400866 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600867 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400868
869 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400870 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400871
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500872 if (backup_cred(cifs_sb))
873 create_options |= CREATE_OPEN_BACKUP_INTENT;
874
875 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
876 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
877 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600878 if (!rc) {
879 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
880 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000881 }
882
Jeff Layton7ffec372010-09-29 19:51:11 -0400883 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400884 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600885
886 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
887 if (rc)
888 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000889 return pntsd;
890}
891
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400892/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600893struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400894 struct inode *inode, const char *path,
895 u32 *pacllen)
896{
897 struct cifs_ntsd *pntsd = NULL;
898 struct cifsFileInfo *open_file = NULL;
899
900 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400901 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400902 if (!open_file)
903 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
904
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700905 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400906 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400907 return pntsd;
908}
909
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500910 /* Set an ACL on the server */
911int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
912 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400913{
914 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400915 unsigned int xid;
916 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000917 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000918 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500919 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400920 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000921
Jeff Layton7ffec372010-09-29 19:51:11 -0400922 if (IS_ERR(tlink))
923 return PTR_ERR(tlink);
924
925 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400926 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000927
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500928 if (backup_cred(cifs_sb))
929 create_options |= CREATE_OPEN_BACKUP_INTENT;
930
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500931 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
932 access_flags = WRITE_OWNER;
933 else
934 access_flags = WRITE_DAC;
935
936 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
937 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
938 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400939 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000940 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400941 goto out;
Steve French97837582007-12-31 07:47:21 +0000942 }
943
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500944 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000945 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000946
Jeff Layton7ffec372010-09-29 19:51:11 -0400947 CIFSSMBClose(xid, tcon, fid);
948out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400949 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400950 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400951 return rc;
952}
Steve French97837582007-12-31 07:47:21 +0000953
Steve French7505e052007-11-01 18:03:01 +0000954/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600955int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400956cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
957 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000958{
959 struct cifs_ntsd *pntsd = NULL;
960 u32 acllen = 0;
961 int rc = 0;
962
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400964
965 if (pfid)
966 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
967 else
968 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000969
970 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600971 if (IS_ERR(pntsd)) {
972 rc = PTR_ERR(pntsd);
973 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
974 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500975 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600976 kfree(pntsd);
977 if (rc)
978 cERROR(1, "parse sec desc failed rc = %d", rc);
979 }
Steve French7505e052007-11-01 18:03:01 +0000980
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600981 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000982}
Steve French953f8682007-10-31 04:54:42 +0000983
Steve French7505e052007-11-01 18:03:01 +0000984/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500985int
986id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
987 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +0000988{
989 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500990 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +0000991 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +0000992 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
993 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +0000994
Joe Perchesb6b38f72010-04-21 03:50:45 +0000995 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +0000996
997 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400998 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600999 if (IS_ERR(pntsd)) {
1000 rc = PTR_ERR(pntsd);
1001 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001002 goto out;
Steve French97837582007-12-31 07:47:21 +00001003 }
1004
Jeff Laytonc78cd832012-11-25 08:00:35 -05001005 /*
1006 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1007 * as chmod disables ACEs and set the security descriptor. Allocate
1008 * memory for the smb header, set security descriptor request security
1009 * descriptor parameters, and secuirty descriptor itself
1010 */
1011 secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
1012 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1013 if (!pnntsd) {
1014 cERROR(1, "Unable to allocate security descriptor");
1015 kfree(pntsd);
1016 return -ENOMEM;
1017 }
1018
1019 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1020 &aclflag);
1021
1022 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1023
1024 if (!rc) {
1025 /* Set the security descriptor */
1026 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1027 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1028 }
1029
1030 kfree(pnntsd);
1031 kfree(pntsd);
1032out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001033 return rc;
Steve French953f8682007-10-31 04:54:42 +00001034}