blob: f4508ee4e80dcd364023ddbd27a4d6e1dc996209 [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
David Howellscf7f6012012-09-13 13:06:29 +010052 payload = kmalloc(prep->datalen, GFP_KERNEL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050053 if (!payload)
54 return -ENOMEM;
55
David Howellscf7f6012012-09-13 13:06:29 +010056 memcpy(payload, prep->data, prep->datalen);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050057 key->payload.data = payload;
David Howellscf7f6012012-09-13 13:06:29 +010058 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050059 return 0;
60}
61
62static inline void
63cifs_idmap_key_destroy(struct key *key)
64{
65 kfree(key->payload.data);
66}
67
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050068static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -050069 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050070 .instantiate = cifs_idmap_key_instantiate,
71 .destroy = cifs_idmap_key_destroy,
72 .describe = user_describe,
73 .match = user_match,
74};
75
Jeff Laytonfaa65f02012-12-03 06:05:29 -050076static char *
77sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050078{
Jeff Laytonfaa65f02012-12-03 06:05:29 -050079 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -050080 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050081 char *sidstr, *strptr;
82
83 /* 3 bytes for prefix */
84 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
85 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
86 GFP_KERNEL);
87 if (!sidstr)
88 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050089
90 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050091 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
92 sidptr->revision);
93 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050094
Jeff Layton852e2292012-11-25 08:00:36 -050095 for (i = 0; i < NUM_AUTHS; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050096 if (sidptr->authority[i]) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -050097 len = sprintf(strptr, "-%hhu", sidptr->authority[i]);
98 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050099 }
100 }
101
102 for (i = 0; i < sidptr->num_subauth; ++i) {
103 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500104 len = sprintf(strptr, "-%u", saval);
105 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500106 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500107
108 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500109}
110
Jeff Layton436bb432012-11-25 08:00:36 -0500111/*
112 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
113 * the same returns zero, if they do not match returns non-zero.
114 */
115static int
116compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
117{
118 int i;
119 int num_subauth, num_sat, num_saw;
120
121 if ((!ctsid) || (!cwsid))
122 return 1;
123
124 /* compare the revision */
125 if (ctsid->revision != cwsid->revision) {
126 if (ctsid->revision > cwsid->revision)
127 return 1;
128 else
129 return -1;
130 }
131
132 /* compare all of the six auth values */
133 for (i = 0; i < NUM_AUTHS; ++i) {
134 if (ctsid->authority[i] != cwsid->authority[i]) {
135 if (ctsid->authority[i] > cwsid->authority[i])
136 return 1;
137 else
138 return -1;
139 }
140 }
141
142 /* compare all of the subauth values if any */
143 num_sat = ctsid->num_subauth;
144 num_saw = cwsid->num_subauth;
145 num_subauth = num_sat < num_saw ? num_sat : num_saw;
146 if (num_subauth) {
147 for (i = 0; i < num_subauth; ++i) {
148 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
149 if (le32_to_cpu(ctsid->sub_auth[i]) >
150 le32_to_cpu(cwsid->sub_auth[i]))
151 return 1;
152 else
153 return -1;
154 }
155 }
156 }
157
158 return 0; /* sids compare/match */
159}
160
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500161static void
Jeff Layton36960e42012-11-03 09:37:28 -0400162cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
163{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500164 int i;
165
166 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500167 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500168 for (i = 0; i < NUM_AUTHS; ++i)
169 dst->authority[i] = src->authority[i];
170 for (i = 0; i < dst->num_subauth; ++i)
171 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400172}
173
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500174static int
175id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500176{
177 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500178 struct key *sidkey;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500179 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500180 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500181
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500182 rc = snprintf(desc, sizeof(desc), "%ci:%u",
183 sidtype == SIDOWNER ? 'o' : 'g', cid);
184 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500185 return -EINVAL;
186
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500187 rc = 0;
188 saved_cred = override_creds(root_cred);
189 sidkey = request_key(&cifs_idmap_key_type, desc, "");
190 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500191 rc = -EINVAL;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500192 cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
193 sidtype == SIDOWNER ? 'u' : 'g', cid);
194 goto out_revert_creds;
195 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
196 rc = -EIO;
197 cFYI(1, "%s: Downcall contained malformed key "
198 "(datalen=%hu)", __func__, sidkey->datalen);
199 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500200 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500201 cifs_copy_sid(ssid, (struct cifs_sid *)sidkey->payload.data);
202out_key_put:
203 key_put(sidkey);
204out_revert_creds:
205 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500206 return rc;
207}
208
209static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500210sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
211 struct cifs_fattr *fattr, uint sidtype)
212{
213 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500214 struct key *sidkey;
215 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500216 const struct cred *saved_cred;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500217 uid_t fuid = cifs_sb->mnt_uid;
218 gid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500219
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500220 /*
221 * If we have too many subauthorities, then something is really wrong.
222 * Just return an error.
223 */
224 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
225 cFYI(1, "%s: %u subauthorities is too many!", __func__,
226 psid->num_subauth);
227 return -EIO;
228 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500229
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500230 sidstr = sid_to_key_str(psid, sidtype);
231 if (!sidstr)
232 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500233
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500234 saved_cred = override_creds(root_cred);
235 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
236 if (IS_ERR(sidkey)) {
237 rc = -EINVAL;
238 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
239 sidtype == SIDOWNER ? 'u' : 'g');
240 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500241 }
242
243 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500244 * FIXME: Here we assume that uid_t and gid_t are same size. It's
245 * probably a safe assumption but might be better to check based on
246 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500247 */
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500248 if (sidkey->datalen < sizeof(uid_t)) {
249 rc = -EIO;
250 cFYI(1, "%s: Downcall contained malformed key "
251 "(datalen=%hu)", __func__, sidkey->datalen);
252 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500253 }
254
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500255 if (sidtype == SIDOWNER)
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500256 fuid = *(uid_t *)sidkey->payload.value;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500257 else
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500258 fgid = *(gid_t *)sidkey->payload.value;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500259
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500260out_key_put:
261 key_put(sidkey);
262out_revert_creds:
263 revert_creds(saved_cred);
264 kfree(sidstr);
265
266 /*
267 * Note that we return 0 here unconditionally. If the mapping
268 * fails then we just fall back to using the mnt_uid/mnt_gid.
269 */
270 if (sidtype == SIDOWNER)
271 fattr->cf_uid = fuid;
272 else
273 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500274 return 0;
275}
276
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500277int
278init_cifs_idmap(void)
279{
280 struct cred *cred;
281 struct key *keyring;
282 int ret;
283
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400284 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500285
286 /* create an override credential set with a special thread keyring in
287 * which requests are cached
288 *
289 * this is used to prevent malicious redirections from being installed
290 * with add_key().
291 */
292 cred = prepare_kernel_cred(NULL);
293 if (!cred)
294 return -ENOMEM;
295
296 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
297 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
298 KEY_USR_VIEW | KEY_USR_READ,
299 KEY_ALLOC_NOT_IN_QUOTA);
300 if (IS_ERR(keyring)) {
301 ret = PTR_ERR(keyring);
302 goto failed_put_cred;
303 }
304
305 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
306 if (ret < 0)
307 goto failed_put_key;
308
309 ret = register_key_type(&cifs_idmap_key_type);
310 if (ret < 0)
311 goto failed_put_key;
312
313 /* instruct request_key() to use this special keyring as a cache for
314 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000315 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500316 cred->thread_keyring = keyring;
317 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
318 root_cred = cred;
319
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400320 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500321 return 0;
322
323failed_put_key:
324 key_put(keyring);
325failed_put_cred:
326 put_cred(cred);
327 return ret;
328}
329
330void
331exit_cifs_idmap(void)
332{
333 key_revoke(root_cred->thread_keyring);
334 unregister_key_type(&cifs_idmap_key_type);
335 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400336 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500337}
338
Steve French97837582007-12-31 07:47:21 +0000339/* copy ntsd, owner sid, and group sid from a security descriptor to another */
340static void copy_sec_desc(const struct cifs_ntsd *pntsd,
341 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
342{
Steve French97837582007-12-31 07:47:21 +0000343 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
344 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
345
346 /* copy security descriptor control portion */
347 pnntsd->revision = pntsd->revision;
348 pnntsd->type = pntsd->type;
349 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
350 pnntsd->sacloffset = 0;
351 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
352 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
353
354 /* copy owner sid */
355 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
356 le32_to_cpu(pntsd->osidoffset));
357 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400358 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000359
360 /* copy group sid */
361 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
362 le32_to_cpu(pntsd->gsidoffset));
363 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
364 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400365 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000366
367 return;
368}
369
370
Steve French630f3f0c2007-10-25 21:17:17 +0000371/*
372 change posix mode to reflect permissions
373 pmode is the existing mode (we only want to overwrite part of this
374 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
375*/
Al Viro9b5e6852007-12-05 08:24:38 +0000376static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000377 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000378{
Al Viro9b5e6852007-12-05 08:24:38 +0000379 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000380 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000381 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000382 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000383 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000384 for the operation you are trying to perform for your user */
385
386 /* For deny ACEs we change the mask so that subsequent allow access
387 control entries do not turn on the bits we are denying */
388 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000389 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000390 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000391
Al Viro9b5e6852007-12-05 08:24:38 +0000392 if ((flags & GENERIC_WRITE) ||
393 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000394 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000395 if ((flags & GENERIC_READ) ||
396 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000397 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000398 if ((flags & GENERIC_EXECUTE) ||
399 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000400 *pbits_to_set &= ~S_IXUGO;
401 return;
402 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000403 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000404 return;
405 }
406 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000407
Al Viro9b5e6852007-12-05 08:24:38 +0000408 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000409 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000410 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000411 return;
412 }
Al Viro9b5e6852007-12-05 08:24:38 +0000413 if ((flags & GENERIC_WRITE) ||
414 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000415 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000416 if ((flags & GENERIC_READ) ||
417 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000418 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000419 if ((flags & GENERIC_EXECUTE) ||
420 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000421 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000422
Joe Perchesb6b38f72010-04-21 03:50:45 +0000423 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000424 return;
425}
426
Steve Frenchce06c9f2007-11-08 21:12:01 +0000427/*
428 Generate access flags to reflect permissions mode is the existing mode.
429 This function is called for every ACE in the DACL whose SID matches
430 with either owner or group or everyone.
431*/
432
433static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
434 __u32 *pace_flags)
435{
436 /* reset access mask */
437 *pace_flags = 0x0;
438
439 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
440 mode &= bits_to_use;
441
442 /* check for R/W/X UGO since we do not know whose flags
443 is this but we have cleared all the bits sans RWX for
444 either user or group or other as per bits_to_use */
445 if (mode & S_IRUGO)
446 *pace_flags |= SET_FILE_READ_RIGHTS;
447 if (mode & S_IWUGO)
448 *pace_flags |= SET_FILE_WRITE_RIGHTS;
449 if (mode & S_IXUGO)
450 *pace_flags |= SET_FILE_EXEC_RIGHTS;
451
Joe Perchesb6b38f72010-04-21 03:50:45 +0000452 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000453 return;
454}
455
Al Viro2b210ad2008-03-29 03:09:18 +0000456static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000457 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
458{
459 int i;
460 __u16 size = 0;
461 __u32 access_req = 0;
462
463 pntace->type = ACCESS_ALLOWED;
464 pntace->flags = 0x0;
465 mode_to_access_flags(nmode, bits, &access_req);
466 if (!access_req)
467 access_req = SET_MINIMUM_RIGHTS;
468 pntace->access_req = cpu_to_le32(access_req);
469
470 pntace->sid.revision = psid->revision;
471 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500472 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000473 pntace->sid.authority[i] = psid->authority[i];
474 for (i = 0; i < psid->num_subauth; i++)
475 pntace->sid.sub_auth[i] = psid->sub_auth[i];
476
477 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
478 pntace->size = cpu_to_le16(size);
479
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000480 return size;
Steve French97837582007-12-31 07:47:21 +0000481}
482
Steve French297647c2007-10-12 04:11:59 +0000483
Steve French953f8682007-10-31 04:54:42 +0000484#ifdef CONFIG_CIFS_DEBUG2
485static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000486{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000487 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000488
489 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000490
Steve French44093ca2007-10-23 21:22:55 +0000491 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000492 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000493 return;
494 }
495
496 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000497 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000498 return;
Steve French44093ca2007-10-23 21:22:55 +0000499 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000500
Steve French44093ca2007-10-23 21:22:55 +0000501 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000502 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000503 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000504 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000505 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000506 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000507 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000508 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
509 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000510 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000511
Steve Frenchd12fd122007-10-03 19:43:19 +0000512 /* BB add length check to make sure that we do not have huge
513 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000514 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000515
Steve Frenchd12fd122007-10-03 19:43:19 +0000516 return;
517}
Steve French953f8682007-10-31 04:54:42 +0000518#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000519
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000520
Steve Frencha750e772007-10-17 22:50:39 +0000521static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000522 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400523 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000524{
525 int i;
526 int num_aces = 0;
527 int acl_size;
528 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000529 struct cifs_ace **ppace;
530
531 /* BB need to add parm so we can store the SID BB */
532
Steve French2b834572007-11-25 10:01:00 +0000533 if (!pdacl) {
534 /* no DACL in the security descriptor, set
535 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400536 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000537 return;
538 }
539
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000540 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000541 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000542 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000543 return;
544 }
545
Joe Perchesb6b38f72010-04-21 03:50:45 +0000546 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000547 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000548 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000549
Steve French7505e052007-11-01 18:03:01 +0000550 /* reset rwx permissions for user/group/other.
551 Also, if num_aces is 0 i.e. DACL has no ACEs,
552 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400553 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000554
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000555 acl_base = (char *)pdacl;
556 acl_size = sizeof(struct cifs_acl);
557
Steve Frenchadbc0352007-10-17 02:12:46 +0000558 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500559 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000560 umode_t user_mask = S_IRWXU;
561 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600562 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000563
Dan Carpenter72501702012-01-11 10:46:27 +0300564 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
565 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000566 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
567 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300568 if (!ppace) {
569 cERROR(1, "DACL memory allocation error");
570 return;
571 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000572
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000573 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000574 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000575#ifdef CONFIG_CIFS_DEBUG2
576 dump_ace(ppace[i], end_of_acl);
577#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500578 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000579 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000580 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400581 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000582 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500583 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000584 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000585 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400586 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000587 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500588 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000589 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000590 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400591 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000592 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500593 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600594 access_flags_to_mode(ppace[i]->access_req,
595 ppace[i]->type,
596 &fattr->cf_mode,
597 &other_mask);
598
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000599
Steve French44093ca2007-10-23 21:22:55 +0000600/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000601 (void *)ppace[i],
602 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000603
Steve French44093ca2007-10-23 21:22:55 +0000604 acl_base = (char *)ppace[i];
605 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000606 }
607
608 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000609 }
610
611 return;
612}
613
Steve Frenchbcb02032007-09-25 16:17:24 +0000614
Steve French97837582007-12-31 07:47:21 +0000615static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
616 struct cifs_sid *pgrpsid, __u64 nmode)
617{
Al Viro2b210ad2008-03-29 03:09:18 +0000618 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000619 struct cifs_acl *pnndacl;
620
621 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
622
623 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
624 pownersid, nmode, S_IRWXU);
625 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
626 pgrpsid, nmode, S_IRWXG);
627 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
628 &sid_everyone, nmode, S_IRWXO);
629
630 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000631 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000632
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000633 return 0;
Steve French97837582007-12-31 07:47:21 +0000634}
635
636
Steve Frenchbcb02032007-09-25 16:17:24 +0000637static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
638{
639 /* BB need to add parm so we can store the SID BB */
640
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000641 /* validate that we do not go past end of ACL - sid must be at least 8
642 bytes long (assuming no sub-auths - e.g. the null SID */
643 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000644 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000645 return -EINVAL;
646 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000647
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000648#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500649 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000650 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000651 cFYI(1, "SID revision %d num_auth %d",
652 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000653
Steve Frenchaf6f4612007-10-16 18:40:37 +0000654 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000655 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
656 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000657 }
658
Steve Frenchd12fd122007-10-03 19:43:19 +0000659 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000660 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000661 cFYI(1, "RID 0x%x",
662 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000663 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500664#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000665
Steve Frenchbcb02032007-09-25 16:17:24 +0000666 return 0;
667}
668
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000669
Steve Frenchbcb02032007-09-25 16:17:24 +0000670/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500671static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
672 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000673{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500674 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000675 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
676 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000677 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000678 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000679
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400680 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000681 return -EIO;
682
Steve Frenchbcb02032007-09-25 16:17:24 +0000683 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000684 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000685 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000686 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000687 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000688 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000689 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000690 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000691 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
692 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000693 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000694/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000695 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500696 if (rc) {
697 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000698 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500699 }
700 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
701 if (rc) {
702 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
703 return rc;
704 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000705
706 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500707 if (rc) {
708 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000709 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500710 }
711 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
712 if (rc) {
713 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
714 return rc;
715 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000716
Steve French7505e052007-11-01 18:03:01 +0000717 if (dacloffset)
718 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400719 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000720 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000721 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000722
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500723 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000724}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000725
Steve French97837582007-12-31 07:47:21 +0000726/* Convert permission bits from mode to equivalent CIFS ACL */
727static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500728 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000729{
730 int rc = 0;
731 __u32 dacloffset;
732 __u32 ndacloffset;
733 __u32 sidsoffset;
734 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500735 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000736 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
737 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
738
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500739 if (nmode != NO_CHANGE_64) { /* chmod */
740 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000741 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500742 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000743 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500744 dacloffset = le32_to_cpu(pntsd->dacloffset);
745 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
746 ndacloffset = sizeof(struct cifs_ntsd);
747 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
748 ndacl_ptr->revision = dacl_ptr->revision;
749 ndacl_ptr->size = 0;
750 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000751
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500752 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
753 nmode);
754 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
755 /* copy sec desc control portion & owner and group sids */
756 copy_sec_desc(pntsd, pnntsd, sidsoffset);
757 *aclflag = CIFS_ACL_DACL;
758 } else {
759 memcpy(pnntsd, pntsd, secdesclen);
760 if (uid != NO_CHANGE_32) { /* chown */
761 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
762 le32_to_cpu(pnntsd->osidoffset));
763 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
764 GFP_KERNEL);
765 if (!nowner_sid_ptr)
766 return -ENOMEM;
767 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
768 if (rc) {
769 cFYI(1, "%s: Mapping error %d for owner id %d",
770 __func__, rc, uid);
771 kfree(nowner_sid_ptr);
772 return rc;
773 }
Jeff Layton36960e42012-11-03 09:37:28 -0400774 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500775 kfree(nowner_sid_ptr);
776 *aclflag = CIFS_ACL_OWNER;
777 }
778 if (gid != NO_CHANGE_32) { /* chgrp */
779 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
780 le32_to_cpu(pnntsd->gsidoffset));
781 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
782 GFP_KERNEL);
783 if (!ngroup_sid_ptr)
784 return -ENOMEM;
785 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
786 if (rc) {
787 cFYI(1, "%s: Mapping error %d for group id %d",
788 __func__, rc, gid);
789 kfree(ngroup_sid_ptr);
790 return rc;
791 }
Jeff Layton36960e42012-11-03 09:37:28 -0400792 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500793 kfree(ngroup_sid_ptr);
794 *aclflag = CIFS_ACL_GROUP;
795 }
796 }
Steve French97837582007-12-31 07:47:21 +0000797
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000798 return rc;
Steve French97837582007-12-31 07:47:21 +0000799}
800
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400801static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
802 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000803{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000804 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400805 unsigned int xid;
806 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400807 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
808
809 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600810 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000811
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400812 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400813 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400814 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000815
Jeff Layton7ffec372010-09-29 19:51:11 -0400816 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000817
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600818 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
819 if (rc)
820 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400821 return pntsd;
822}
823
824static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
825 const char *path, u32 *pacllen)
826{
827 struct cifs_ntsd *pntsd = NULL;
828 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400829 unsigned int xid;
830 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400831 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000832 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400833 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400834
Jeff Layton7ffec372010-09-29 19:51:11 -0400835 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600836 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400837
838 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400839 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400840
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500841 if (backup_cred(cifs_sb))
842 create_options |= CREATE_OPEN_BACKUP_INTENT;
843
844 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
845 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
846 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600847 if (!rc) {
848 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
849 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000850 }
851
Jeff Layton7ffec372010-09-29 19:51:11 -0400852 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400853 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600854
855 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
856 if (rc)
857 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000858 return pntsd;
859}
860
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400861/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600862struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400863 struct inode *inode, const char *path,
864 u32 *pacllen)
865{
866 struct cifs_ntsd *pntsd = NULL;
867 struct cifsFileInfo *open_file = NULL;
868
869 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400870 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400871 if (!open_file)
872 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
873
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700874 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400875 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400876 return pntsd;
877}
878
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500879 /* Set an ACL on the server */
880int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
881 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400882{
883 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400884 unsigned int xid;
885 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000886 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000887 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500888 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400889 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000890
Jeff Layton7ffec372010-09-29 19:51:11 -0400891 if (IS_ERR(tlink))
892 return PTR_ERR(tlink);
893
894 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400895 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000896
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500897 if (backup_cred(cifs_sb))
898 create_options |= CREATE_OPEN_BACKUP_INTENT;
899
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500900 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
901 access_flags = WRITE_OWNER;
902 else
903 access_flags = WRITE_DAC;
904
905 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
906 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
907 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400908 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000909 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400910 goto out;
Steve French97837582007-12-31 07:47:21 +0000911 }
912
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500913 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000914 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000915
Jeff Layton7ffec372010-09-29 19:51:11 -0400916 CIFSSMBClose(xid, tcon, fid);
917out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400918 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400919 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400920 return rc;
921}
Steve French97837582007-12-31 07:47:21 +0000922
Steve French7505e052007-11-01 18:03:01 +0000923/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600924int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400925cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
926 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000927{
928 struct cifs_ntsd *pntsd = NULL;
929 u32 acllen = 0;
930 int rc = 0;
931
Joe Perchesb6b38f72010-04-21 03:50:45 +0000932 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400933
934 if (pfid)
935 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
936 else
937 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000938
939 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600940 if (IS_ERR(pntsd)) {
941 rc = PTR_ERR(pntsd);
942 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
943 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500944 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600945 kfree(pntsd);
946 if (rc)
947 cERROR(1, "parse sec desc failed rc = %d", rc);
948 }
Steve French7505e052007-11-01 18:03:01 +0000949
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600950 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000951}
Steve French953f8682007-10-31 04:54:42 +0000952
Steve French7505e052007-11-01 18:03:01 +0000953/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500954int
955id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
956 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +0000957{
958 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500959 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +0000960 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +0000961 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
962 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +0000963
Joe Perchesb6b38f72010-04-21 03:50:45 +0000964 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +0000965
966 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400967 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600968 if (IS_ERR(pntsd)) {
969 rc = PTR_ERR(pntsd);
970 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -0500971 goto out;
Steve French97837582007-12-31 07:47:21 +0000972 }
973
Jeff Laytonc78cd832012-11-25 08:00:35 -0500974 /*
975 * Add three ACEs for owner, group, everyone getting rid of other ACEs
976 * as chmod disables ACEs and set the security descriptor. Allocate
977 * memory for the smb header, set security descriptor request security
978 * descriptor parameters, and secuirty descriptor itself
979 */
980 secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
981 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
982 if (!pnntsd) {
983 cERROR(1, "Unable to allocate security descriptor");
984 kfree(pntsd);
985 return -ENOMEM;
986 }
987
988 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
989 &aclflag);
990
991 cFYI(DBG2, "build_sec_desc rc: %d", rc);
992
993 if (!rc) {
994 /* Set the security descriptor */
995 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
996 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
997 }
998
999 kfree(pnntsd);
1000 kfree(pntsd);
1001out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001002 return rc;
Steve French953f8682007-10-31 04:54:42 +00001003}