blob: 751d34bd825c8ec6278087f15fc9b939ef80b544 [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 Laytonfaa65f02012-12-03 06:05:29 -0500194 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500195 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500196
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500197 rc = snprintf(desc, sizeof(desc), "%ci:%u",
198 sidtype == SIDOWNER ? 'o' : 'g', cid);
199 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500200 return -EINVAL;
201
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500202 rc = 0;
203 saved_cred = override_creds(root_cred);
204 sidkey = request_key(&cifs_idmap_key_type, desc, "");
205 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500206 rc = -EINVAL;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500207 cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
208 sidtype == SIDOWNER ? 'u' : 'g', cid);
209 goto out_revert_creds;
210 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
211 rc = -EIO;
212 cFYI(1, "%s: Downcall contained malformed key "
213 "(datalen=%hu)", __func__, sidkey->datalen);
214 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500215 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500216 cifs_copy_sid(ssid, (struct cifs_sid *)sidkey->payload.data);
217out_key_put:
218 key_put(sidkey);
219out_revert_creds:
220 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500221 return rc;
222}
223
224static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500225sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
226 struct cifs_fattr *fattr, uint sidtype)
227{
228 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500229 struct key *sidkey;
230 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500231 const struct cred *saved_cred;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500232 uid_t fuid = cifs_sb->mnt_uid;
233 gid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500234
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500235 /*
236 * If we have too many subauthorities, then something is really wrong.
237 * Just return an error.
238 */
239 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
240 cFYI(1, "%s: %u subauthorities is too many!", __func__,
241 psid->num_subauth);
242 return -EIO;
243 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500244
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500245 sidstr = sid_to_key_str(psid, sidtype);
246 if (!sidstr)
247 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500248
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500249 saved_cred = override_creds(root_cred);
250 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
251 if (IS_ERR(sidkey)) {
252 rc = -EINVAL;
253 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
254 sidtype == SIDOWNER ? 'u' : 'g');
255 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500256 }
257
258 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500259 * FIXME: Here we assume that uid_t and gid_t are same size. It's
260 * probably a safe assumption but might be better to check based on
261 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500262 */
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500263 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500264 rc = -EIO;
265 cFYI(1, "%s: Downcall contained malformed key "
266 "(datalen=%hu)", __func__, sidkey->datalen);
267 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500268 }
269
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500270 if (sidtype == SIDOWNER)
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500271 memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500272 else
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500273 memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500274
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500275out_key_put:
276 key_put(sidkey);
277out_revert_creds:
278 revert_creds(saved_cred);
279 kfree(sidstr);
280
281 /*
282 * Note that we return 0 here unconditionally. If the mapping
283 * fails then we just fall back to using the mnt_uid/mnt_gid.
284 */
285 if (sidtype == SIDOWNER)
286 fattr->cf_uid = fuid;
287 else
288 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500289 return 0;
290}
291
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500292int
293init_cifs_idmap(void)
294{
295 struct cred *cred;
296 struct key *keyring;
297 int ret;
298
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400299 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500300
301 /* create an override credential set with a special thread keyring in
302 * which requests are cached
303 *
304 * this is used to prevent malicious redirections from being installed
305 * with add_key().
306 */
307 cred = prepare_kernel_cred(NULL);
308 if (!cred)
309 return -ENOMEM;
310
311 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
312 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
313 KEY_USR_VIEW | KEY_USR_READ,
314 KEY_ALLOC_NOT_IN_QUOTA);
315 if (IS_ERR(keyring)) {
316 ret = PTR_ERR(keyring);
317 goto failed_put_cred;
318 }
319
320 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
321 if (ret < 0)
322 goto failed_put_key;
323
324 ret = register_key_type(&cifs_idmap_key_type);
325 if (ret < 0)
326 goto failed_put_key;
327
328 /* instruct request_key() to use this special keyring as a cache for
329 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000330 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500331 cred->thread_keyring = keyring;
332 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
333 root_cred = cred;
334
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400335 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500336 return 0;
337
338failed_put_key:
339 key_put(keyring);
340failed_put_cred:
341 put_cred(cred);
342 return ret;
343}
344
345void
346exit_cifs_idmap(void)
347{
348 key_revoke(root_cred->thread_keyring);
349 unregister_key_type(&cifs_idmap_key_type);
350 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400351 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500352}
353
Steve French97837582007-12-31 07:47:21 +0000354/* copy ntsd, owner sid, and group sid from a security descriptor to another */
355static void copy_sec_desc(const struct cifs_ntsd *pntsd,
356 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
357{
Steve French97837582007-12-31 07:47:21 +0000358 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
359 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
360
361 /* copy security descriptor control portion */
362 pnntsd->revision = pntsd->revision;
363 pnntsd->type = pntsd->type;
364 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
365 pnntsd->sacloffset = 0;
366 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
367 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
368
369 /* copy owner sid */
370 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
371 le32_to_cpu(pntsd->osidoffset));
372 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400373 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000374
375 /* copy group sid */
376 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
377 le32_to_cpu(pntsd->gsidoffset));
378 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
379 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400380 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000381
382 return;
383}
384
385
Steve French630f3f0c2007-10-25 21:17:17 +0000386/*
387 change posix mode to reflect permissions
388 pmode is the existing mode (we only want to overwrite part of this
389 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
390*/
Al Viro9b5e6852007-12-05 08:24:38 +0000391static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000392 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000393{
Al Viro9b5e6852007-12-05 08:24:38 +0000394 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000395 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000396 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000397 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000398 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000399 for the operation you are trying to perform for your user */
400
401 /* For deny ACEs we change the mask so that subsequent allow access
402 control entries do not turn on the bits we are denying */
403 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000404 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000405 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000406
Al Viro9b5e6852007-12-05 08:24:38 +0000407 if ((flags & GENERIC_WRITE) ||
408 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000409 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000410 if ((flags & GENERIC_READ) ||
411 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000412 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000413 if ((flags & GENERIC_EXECUTE) ||
414 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000415 *pbits_to_set &= ~S_IXUGO;
416 return;
417 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000418 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000419 return;
420 }
421 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000422
Al Viro9b5e6852007-12-05 08:24:38 +0000423 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000424 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000425 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000426 return;
427 }
Al Viro9b5e6852007-12-05 08:24:38 +0000428 if ((flags & GENERIC_WRITE) ||
429 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000430 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000431 if ((flags & GENERIC_READ) ||
432 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000433 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000434 if ((flags & GENERIC_EXECUTE) ||
435 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000436 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000437
Joe Perchesb6b38f72010-04-21 03:50:45 +0000438 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000439 return;
440}
441
Steve Frenchce06c9f2007-11-08 21:12:01 +0000442/*
443 Generate access flags to reflect permissions mode is the existing mode.
444 This function is called for every ACE in the DACL whose SID matches
445 with either owner or group or everyone.
446*/
447
448static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
449 __u32 *pace_flags)
450{
451 /* reset access mask */
452 *pace_flags = 0x0;
453
454 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
455 mode &= bits_to_use;
456
457 /* check for R/W/X UGO since we do not know whose flags
458 is this but we have cleared all the bits sans RWX for
459 either user or group or other as per bits_to_use */
460 if (mode & S_IRUGO)
461 *pace_flags |= SET_FILE_READ_RIGHTS;
462 if (mode & S_IWUGO)
463 *pace_flags |= SET_FILE_WRITE_RIGHTS;
464 if (mode & S_IXUGO)
465 *pace_flags |= SET_FILE_EXEC_RIGHTS;
466
Joe Perchesb6b38f72010-04-21 03:50:45 +0000467 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000468 return;
469}
470
Al Viro2b210ad2008-03-29 03:09:18 +0000471static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000472 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
473{
474 int i;
475 __u16 size = 0;
476 __u32 access_req = 0;
477
478 pntace->type = ACCESS_ALLOWED;
479 pntace->flags = 0x0;
480 mode_to_access_flags(nmode, bits, &access_req);
481 if (!access_req)
482 access_req = SET_MINIMUM_RIGHTS;
483 pntace->access_req = cpu_to_le32(access_req);
484
485 pntace->sid.revision = psid->revision;
486 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500487 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000488 pntace->sid.authority[i] = psid->authority[i];
489 for (i = 0; i < psid->num_subauth; i++)
490 pntace->sid.sub_auth[i] = psid->sub_auth[i];
491
492 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
493 pntace->size = cpu_to_le16(size);
494
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000495 return size;
Steve French97837582007-12-31 07:47:21 +0000496}
497
Steve French297647c2007-10-12 04:11:59 +0000498
Steve French953f8682007-10-31 04:54:42 +0000499#ifdef CONFIG_CIFS_DEBUG2
500static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000501{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000502 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000503
504 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000505
Steve French44093ca2007-10-23 21:22:55 +0000506 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000507 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000508 return;
509 }
510
511 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000512 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000513 return;
Steve French44093ca2007-10-23 21:22:55 +0000514 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000515
Steve French44093ca2007-10-23 21:22:55 +0000516 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000517 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000518 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000519 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000520 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000521 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000522 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000523 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
524 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000525 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000526
Steve Frenchd12fd122007-10-03 19:43:19 +0000527 /* BB add length check to make sure that we do not have huge
528 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000529 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000530
Steve Frenchd12fd122007-10-03 19:43:19 +0000531 return;
532}
Steve French953f8682007-10-31 04:54:42 +0000533#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000534
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000535
Steve Frencha750e772007-10-17 22:50:39 +0000536static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000537 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400538 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000539{
540 int i;
541 int num_aces = 0;
542 int acl_size;
543 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000544 struct cifs_ace **ppace;
545
546 /* BB need to add parm so we can store the SID BB */
547
Steve French2b834572007-11-25 10:01:00 +0000548 if (!pdacl) {
549 /* no DACL in the security descriptor, set
550 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400551 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000552 return;
553 }
554
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000555 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000556 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000557 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000558 return;
559 }
560
Joe Perchesb6b38f72010-04-21 03:50:45 +0000561 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000562 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000563 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000564
Steve French7505e052007-11-01 18:03:01 +0000565 /* reset rwx permissions for user/group/other.
566 Also, if num_aces is 0 i.e. DACL has no ACEs,
567 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400568 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000569
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000570 acl_base = (char *)pdacl;
571 acl_size = sizeof(struct cifs_acl);
572
Steve Frenchadbc0352007-10-17 02:12:46 +0000573 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500574 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000575 umode_t user_mask = S_IRWXU;
576 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600577 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000578
Dan Carpenter72501702012-01-11 10:46:27 +0300579 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
580 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000581 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
582 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300583 if (!ppace) {
584 cERROR(1, "DACL memory allocation error");
585 return;
586 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000587
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000588 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000589 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000590#ifdef CONFIG_CIFS_DEBUG2
591 dump_ace(ppace[i], end_of_acl);
592#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500593 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000594 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000595 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400596 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000597 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500598 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000599 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000600 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400601 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000602 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500603 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000604 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000605 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400606 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000607 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500608 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600609 access_flags_to_mode(ppace[i]->access_req,
610 ppace[i]->type,
611 &fattr->cf_mode,
612 &other_mask);
613
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000614
Steve French44093ca2007-10-23 21:22:55 +0000615/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000616 (void *)ppace[i],
617 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000618
Steve French44093ca2007-10-23 21:22:55 +0000619 acl_base = (char *)ppace[i];
620 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000621 }
622
623 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000624 }
625
626 return;
627}
628
Steve Frenchbcb02032007-09-25 16:17:24 +0000629
Steve French97837582007-12-31 07:47:21 +0000630static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
631 struct cifs_sid *pgrpsid, __u64 nmode)
632{
Al Viro2b210ad2008-03-29 03:09:18 +0000633 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000634 struct cifs_acl *pnndacl;
635
636 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
637
638 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
639 pownersid, nmode, S_IRWXU);
640 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
641 pgrpsid, nmode, S_IRWXG);
642 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
643 &sid_everyone, nmode, S_IRWXO);
644
645 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000646 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000647
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000648 return 0;
Steve French97837582007-12-31 07:47:21 +0000649}
650
651
Steve Frenchbcb02032007-09-25 16:17:24 +0000652static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
653{
654 /* BB need to add parm so we can store the SID BB */
655
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000656 /* validate that we do not go past end of ACL - sid must be at least 8
657 bytes long (assuming no sub-auths - e.g. the null SID */
658 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000659 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000660 return -EINVAL;
661 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000662
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000663#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500664 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000665 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000666 cFYI(1, "SID revision %d num_auth %d",
667 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000668
Steve Frenchaf6f4612007-10-16 18:40:37 +0000669 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000670 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
671 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000672 }
673
Steve Frenchd12fd122007-10-03 19:43:19 +0000674 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000675 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cFYI(1, "RID 0x%x",
677 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000678 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500679#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000680
Steve Frenchbcb02032007-09-25 16:17:24 +0000681 return 0;
682}
683
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000684
Steve Frenchbcb02032007-09-25 16:17:24 +0000685/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500686static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
687 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000688{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500689 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000690 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
691 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000692 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000693 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000694
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400695 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000696 return -EIO;
697
Steve Frenchbcb02032007-09-25 16:17:24 +0000698 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000699 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000700 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000701 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000702 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000703 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000704 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000705 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000706 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
707 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000708 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000709/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000710 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500711 if (rc) {
712 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000713 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500714 }
715 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
716 if (rc) {
717 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
718 return rc;
719 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000720
721 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500722 if (rc) {
723 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000724 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500725 }
726 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
727 if (rc) {
728 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
729 return rc;
730 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000731
Steve French7505e052007-11-01 18:03:01 +0000732 if (dacloffset)
733 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400734 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000735 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000736 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000737
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500738 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000739}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000740
Steve French97837582007-12-31 07:47:21 +0000741/* Convert permission bits from mode to equivalent CIFS ACL */
742static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500743 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000744{
745 int rc = 0;
746 __u32 dacloffset;
747 __u32 ndacloffset;
748 __u32 sidsoffset;
749 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500750 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000751 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
752 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
753
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500754 if (nmode != NO_CHANGE_64) { /* chmod */
755 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000756 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500757 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000758 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500759 dacloffset = le32_to_cpu(pntsd->dacloffset);
760 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
761 ndacloffset = sizeof(struct cifs_ntsd);
762 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
763 ndacl_ptr->revision = dacl_ptr->revision;
764 ndacl_ptr->size = 0;
765 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000766
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500767 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
768 nmode);
769 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
770 /* copy sec desc control portion & owner and group sids */
771 copy_sec_desc(pntsd, pnntsd, sidsoffset);
772 *aclflag = CIFS_ACL_DACL;
773 } else {
774 memcpy(pnntsd, pntsd, secdesclen);
775 if (uid != NO_CHANGE_32) { /* chown */
776 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
777 le32_to_cpu(pnntsd->osidoffset));
778 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
779 GFP_KERNEL);
780 if (!nowner_sid_ptr)
781 return -ENOMEM;
782 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
783 if (rc) {
784 cFYI(1, "%s: Mapping error %d for owner id %d",
785 __func__, rc, uid);
786 kfree(nowner_sid_ptr);
787 return rc;
788 }
Jeff Layton36960e42012-11-03 09:37:28 -0400789 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500790 kfree(nowner_sid_ptr);
791 *aclflag = CIFS_ACL_OWNER;
792 }
793 if (gid != NO_CHANGE_32) { /* chgrp */
794 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
795 le32_to_cpu(pnntsd->gsidoffset));
796 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
797 GFP_KERNEL);
798 if (!ngroup_sid_ptr)
799 return -ENOMEM;
800 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
801 if (rc) {
802 cFYI(1, "%s: Mapping error %d for group id %d",
803 __func__, rc, gid);
804 kfree(ngroup_sid_ptr);
805 return rc;
806 }
Jeff Layton36960e42012-11-03 09:37:28 -0400807 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500808 kfree(ngroup_sid_ptr);
809 *aclflag = CIFS_ACL_GROUP;
810 }
811 }
Steve French97837582007-12-31 07:47:21 +0000812
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000813 return rc;
Steve French97837582007-12-31 07:47:21 +0000814}
815
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400816static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
817 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000818{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000819 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400820 unsigned int xid;
821 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400822 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
823
824 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600825 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000826
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400827 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400828 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400829 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000830
Jeff Layton7ffec372010-09-29 19:51:11 -0400831 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000832
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600833 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
834 if (rc)
835 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400836 return pntsd;
837}
838
839static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
840 const char *path, u32 *pacllen)
841{
842 struct cifs_ntsd *pntsd = NULL;
843 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400844 unsigned int xid;
845 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400846 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000847 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400848 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400849
Jeff Layton7ffec372010-09-29 19:51:11 -0400850 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600851 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400852
853 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400854 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400855
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500856 if (backup_cred(cifs_sb))
857 create_options |= CREATE_OPEN_BACKUP_INTENT;
858
859 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
860 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
861 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600862 if (!rc) {
863 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
864 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000865 }
866
Jeff Layton7ffec372010-09-29 19:51:11 -0400867 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400868 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600869
870 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
871 if (rc)
872 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000873 return pntsd;
874}
875
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400876/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600877struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400878 struct inode *inode, const char *path,
879 u32 *pacllen)
880{
881 struct cifs_ntsd *pntsd = NULL;
882 struct cifsFileInfo *open_file = NULL;
883
884 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400885 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400886 if (!open_file)
887 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
888
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700889 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400890 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400891 return pntsd;
892}
893
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500894 /* Set an ACL on the server */
895int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
896 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400897{
898 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400899 unsigned int xid;
900 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000901 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000902 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500903 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400904 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000905
Jeff Layton7ffec372010-09-29 19:51:11 -0400906 if (IS_ERR(tlink))
907 return PTR_ERR(tlink);
908
909 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400910 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000911
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500912 if (backup_cred(cifs_sb))
913 create_options |= CREATE_OPEN_BACKUP_INTENT;
914
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500915 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
916 access_flags = WRITE_OWNER;
917 else
918 access_flags = WRITE_DAC;
919
920 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
921 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
922 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400923 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000924 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400925 goto out;
Steve French97837582007-12-31 07:47:21 +0000926 }
927
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500928 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000929 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000930
Jeff Layton7ffec372010-09-29 19:51:11 -0400931 CIFSSMBClose(xid, tcon, fid);
932out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400933 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400934 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400935 return rc;
936}
Steve French97837582007-12-31 07:47:21 +0000937
Steve French7505e052007-11-01 18:03:01 +0000938/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600939int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400940cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
941 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000942{
943 struct cifs_ntsd *pntsd = NULL;
944 u32 acllen = 0;
945 int rc = 0;
946
Joe Perchesb6b38f72010-04-21 03:50:45 +0000947 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400948
949 if (pfid)
950 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
951 else
952 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000953
954 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600955 if (IS_ERR(pntsd)) {
956 rc = PTR_ERR(pntsd);
957 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
958 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500959 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600960 kfree(pntsd);
961 if (rc)
962 cERROR(1, "parse sec desc failed rc = %d", rc);
963 }
Steve French7505e052007-11-01 18:03:01 +0000964
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600965 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000966}
Steve French953f8682007-10-31 04:54:42 +0000967
Steve French7505e052007-11-01 18:03:01 +0000968/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500969int
970id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
971 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +0000972{
973 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500974 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +0000975 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +0000976 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
977 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +0000978
Joe Perchesb6b38f72010-04-21 03:50:45 +0000979 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +0000980
981 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400982 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600983 if (IS_ERR(pntsd)) {
984 rc = PTR_ERR(pntsd);
985 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -0500986 goto out;
Steve French97837582007-12-31 07:47:21 +0000987 }
988
Jeff Laytonc78cd832012-11-25 08:00:35 -0500989 /*
990 * Add three ACEs for owner, group, everyone getting rid of other ACEs
991 * as chmod disables ACEs and set the security descriptor. Allocate
992 * memory for the smb header, set security descriptor request security
993 * descriptor parameters, and secuirty descriptor itself
994 */
995 secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
996 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
997 if (!pnntsd) {
998 cERROR(1, "Unable to allocate security descriptor");
999 kfree(pntsd);
1000 return -ENOMEM;
1001 }
1002
1003 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1004 &aclflag);
1005
1006 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1007
1008 if (!rc) {
1009 /* Set the security descriptor */
1010 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1011 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1012 }
1013
1014 kfree(pnntsd);
1015 kfree(pntsd);
1016out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001017 return rc;
Steve French953f8682007-10-31 04:54:42 +00001018}