blob: 2e811f45b413debf6593509190a729b50ecd2e79 [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
Steve French8b1327f2008-03-14 22:37:16 +00004 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050026#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
Steve French65874002007-09-25 19:53:44 +000030#include "cifspdu.h"
31#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000032#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000033#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French65874002007-09-25 19:53:44 +000035
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060036/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000037static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060039/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
Steve French4f612582011-05-27 20:40:18 +000041 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
Steve Frenchbcb02032007-09-25 16:17:24 +000042/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000043static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000044
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050045static const struct cred *root_cred;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050046
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050047static int
David Howellscf7f6012012-09-13 13:06:29 +010048cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050049{
50 char *payload;
51
Jeff Layton41a9f1f2012-12-03 06:05:29 -050052 /*
53 * If the payload is less than or equal to the size of a pointer, then
54 * an allocation here is wasteful. Just copy the data directly to the
55 * payload.value union member instead.
56 *
57 * With this however, you must check the datalen before trying to
58 * dereference payload.data!
59 */
Jeff Layton1f630682012-12-03 06:05:31 -050060 if (prep->datalen <= sizeof(key->payload)) {
Jeff Layton41a9f1f2012-12-03 06:05:29 -050061 key->payload.value = 0;
62 memcpy(&key->payload.value, prep->data, prep->datalen);
63 key->datalen = prep->datalen;
64 return 0;
65 }
David Howellscf7f6012012-09-13 13:06:29 +010066 payload = kmalloc(prep->datalen, GFP_KERNEL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050067 if (!payload)
68 return -ENOMEM;
69
David Howellscf7f6012012-09-13 13:06:29 +010070 memcpy(payload, prep->data, prep->datalen);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050071 key->payload.data = payload;
David Howellscf7f6012012-09-13 13:06:29 +010072 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050073 return 0;
74}
75
76static inline void
77cifs_idmap_key_destroy(struct key *key)
78{
Jeff Layton1f630682012-12-03 06:05:31 -050079 if (key->datalen > sizeof(key->payload))
Jeff Layton41a9f1f2012-12-03 06:05:29 -050080 kfree(key->payload.data);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050081}
82
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050083static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -050084 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050085 .instantiate = cifs_idmap_key_instantiate,
86 .destroy = cifs_idmap_key_destroy,
87 .describe = user_describe,
88 .match = user_match,
89};
90
Jeff Laytonfaa65f02012-12-03 06:05:29 -050091static char *
92sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050093{
Jeff Laytonfaa65f02012-12-03 06:05:29 -050094 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -050095 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050096 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -050097 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050098
99 /* 3 bytes for prefix */
100 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
101 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
102 GFP_KERNEL);
103 if (!sidstr)
104 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500105
106 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500107 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
108 sidptr->revision);
109 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500110
Jeff Layton193cdd82012-12-10 06:10:44 -0500111 /* The authority field is a single 48-bit number */
112 id_auth_val = (unsigned long long)sidptr->authority[5];
113 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
114 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
115 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
116 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
117 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
118
119 /*
120 * MS-DTYP states that if the authority is >= 2^32, then it should be
121 * expressed as a hex value.
122 */
123 if (id_auth_val <= UINT_MAX)
124 len = sprintf(strptr, "-%llu", id_auth_val);
125 else
126 len = sprintf(strptr, "-0x%llx", id_auth_val);
127
128 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500129
130 for (i = 0; i < sidptr->num_subauth; ++i) {
131 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500132 len = sprintf(strptr, "-%u", saval);
133 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500134 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500135
136 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500137}
138
Jeff Layton436bb432012-11-25 08:00:36 -0500139/*
140 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
141 * the same returns zero, if they do not match returns non-zero.
142 */
143static int
144compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
145{
146 int i;
147 int num_subauth, num_sat, num_saw;
148
149 if ((!ctsid) || (!cwsid))
150 return 1;
151
152 /* compare the revision */
153 if (ctsid->revision != cwsid->revision) {
154 if (ctsid->revision > cwsid->revision)
155 return 1;
156 else
157 return -1;
158 }
159
160 /* compare all of the six auth values */
161 for (i = 0; i < NUM_AUTHS; ++i) {
162 if (ctsid->authority[i] != cwsid->authority[i]) {
163 if (ctsid->authority[i] > cwsid->authority[i])
164 return 1;
165 else
166 return -1;
167 }
168 }
169
170 /* compare all of the subauth values if any */
171 num_sat = ctsid->num_subauth;
172 num_saw = cwsid->num_subauth;
173 num_subauth = num_sat < num_saw ? num_sat : num_saw;
174 if (num_subauth) {
175 for (i = 0; i < num_subauth; ++i) {
176 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
177 if (le32_to_cpu(ctsid->sub_auth[i]) >
178 le32_to_cpu(cwsid->sub_auth[i]))
179 return 1;
180 else
181 return -1;
182 }
183 }
184 }
185
186 return 0; /* sids compare/match */
187}
188
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500189static void
Jeff Layton36960e42012-11-03 09:37:28 -0400190cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
191{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500192 int i;
193
194 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500195 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500196 for (i = 0; i < NUM_AUTHS; ++i)
197 dst->authority[i] = src->authority[i];
198 for (i = 0; i < dst->num_subauth; ++i)
199 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400200}
201
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500202static int
203id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500204{
205 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500206 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500207 struct cifs_sid *ksid;
208 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500209 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500210 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500211
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500212 rc = snprintf(desc, sizeof(desc), "%ci:%u",
213 sidtype == SIDOWNER ? 'o' : 'g', cid);
214 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500215 return -EINVAL;
216
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500217 rc = 0;
218 saved_cred = override_creds(root_cred);
219 sidkey = request_key(&cifs_idmap_key_type, desc, "");
220 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500221 rc = -EINVAL;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500222 cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
223 sidtype == SIDOWNER ? 'u' : 'g', cid);
224 goto out_revert_creds;
225 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
226 rc = -EIO;
227 cFYI(1, "%s: Downcall contained malformed key "
228 "(datalen=%hu)", __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500229 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500230 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500231
Jeff Layton1f630682012-12-03 06:05:31 -0500232 /*
233 * A sid is usually too large to be embedded in payload.value, but if
234 * there are no subauthorities and the host has 8-byte pointers, then
235 * it could be.
236 */
237 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
238 (struct cifs_sid *)&sidkey->payload.value :
239 (struct cifs_sid *)sidkey->payload.data;
240
Jeff Layton2ae03022012-12-03 06:05:30 -0500241 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
242 if (ksid_size > sidkey->datalen) {
243 rc = -EIO;
244 cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, "
245 "ksid_size=%u)", __func__, sidkey->datalen, ksid_size);
246 goto invalidate_key;
247 }
Jeff Layton1f630682012-12-03 06:05:31 -0500248
Jeff Layton2ae03022012-12-03 06:05:30 -0500249 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500250out_key_put:
251 key_put(sidkey);
252out_revert_creds:
253 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500254 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500255
256invalidate_key:
257 key_invalidate(sidkey);
258 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500259}
260
261static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500262sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
263 struct cifs_fattr *fattr, uint sidtype)
264{
265 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500266 struct key *sidkey;
267 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500268 const struct cred *saved_cred;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500269 uid_t fuid = cifs_sb->mnt_uid;
270 gid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500271
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500272 /*
273 * If we have too many subauthorities, then something is really wrong.
274 * Just return an error.
275 */
276 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
277 cFYI(1, "%s: %u subauthorities is too many!", __func__,
278 psid->num_subauth);
279 return -EIO;
280 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500281
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500282 sidstr = sid_to_key_str(psid, sidtype);
283 if (!sidstr)
284 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500285
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500286 saved_cred = override_creds(root_cred);
287 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
288 if (IS_ERR(sidkey)) {
289 rc = -EINVAL;
290 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
291 sidtype == SIDOWNER ? 'u' : 'g');
292 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500293 }
294
295 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500296 * FIXME: Here we assume that uid_t and gid_t are same size. It's
297 * probably a safe assumption but might be better to check based on
298 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500299 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800300 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500301 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500302 rc = -EIO;
303 cFYI(1, "%s: Downcall contained malformed key "
304 "(datalen=%hu)", __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500305 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500306 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500307 }
308
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500309 if (sidtype == SIDOWNER)
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500310 memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500311 else
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500312 memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500313
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500314out_key_put:
315 key_put(sidkey);
316out_revert_creds:
317 revert_creds(saved_cred);
318 kfree(sidstr);
319
320 /*
321 * Note that we return 0 here unconditionally. If the mapping
322 * fails then we just fall back to using the mnt_uid/mnt_gid.
323 */
324 if (sidtype == SIDOWNER)
325 fattr->cf_uid = fuid;
326 else
327 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500328 return 0;
329}
330
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500331int
332init_cifs_idmap(void)
333{
334 struct cred *cred;
335 struct key *keyring;
336 int ret;
337
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400338 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500339
340 /* create an override credential set with a special thread keyring in
341 * which requests are cached
342 *
343 * this is used to prevent malicious redirections from being installed
344 * with add_key().
345 */
346 cred = prepare_kernel_cred(NULL);
347 if (!cred)
348 return -ENOMEM;
349
David Howellsf8aa23a2012-10-02 19:24:56 +0100350 keyring = keyring_alloc(".cifs_idmap", 0, 0, cred,
351 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
352 KEY_USR_VIEW | KEY_USR_READ,
353 KEY_ALLOC_NOT_IN_QUOTA, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500354 if (IS_ERR(keyring)) {
355 ret = PTR_ERR(keyring);
356 goto failed_put_cred;
357 }
358
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500359 ret = register_key_type(&cifs_idmap_key_type);
360 if (ret < 0)
361 goto failed_put_key;
362
363 /* instruct request_key() to use this special keyring as a cache for
364 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000365 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500366 cred->thread_keyring = keyring;
367 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
368 root_cred = cred;
369
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400370 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500371 return 0;
372
373failed_put_key:
374 key_put(keyring);
375failed_put_cred:
376 put_cred(cred);
377 return ret;
378}
379
380void
381exit_cifs_idmap(void)
382{
383 key_revoke(root_cred->thread_keyring);
384 unregister_key_type(&cifs_idmap_key_type);
385 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400386 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500387}
388
Steve French97837582007-12-31 07:47:21 +0000389/* copy ntsd, owner sid, and group sid from a security descriptor to another */
390static void copy_sec_desc(const struct cifs_ntsd *pntsd,
391 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
392{
Steve French97837582007-12-31 07:47:21 +0000393 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
394 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
395
396 /* copy security descriptor control portion */
397 pnntsd->revision = pntsd->revision;
398 pnntsd->type = pntsd->type;
399 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
400 pnntsd->sacloffset = 0;
401 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
402 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
403
404 /* copy owner sid */
405 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
406 le32_to_cpu(pntsd->osidoffset));
407 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400408 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000409
410 /* copy group sid */
411 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
412 le32_to_cpu(pntsd->gsidoffset));
413 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
414 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400415 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000416
417 return;
418}
419
420
Steve French630f3f0c2007-10-25 21:17:17 +0000421/*
422 change posix mode to reflect permissions
423 pmode is the existing mode (we only want to overwrite part of this
424 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
425*/
Al Viro9b5e6852007-12-05 08:24:38 +0000426static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000427 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000428{
Al Viro9b5e6852007-12-05 08:24:38 +0000429 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000430 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000431 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000432 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000433 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000434 for the operation you are trying to perform for your user */
435
436 /* For deny ACEs we change the mask so that subsequent allow access
437 control entries do not turn on the bits we are denying */
438 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000439 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000440 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000441
Al Viro9b5e6852007-12-05 08:24:38 +0000442 if ((flags & GENERIC_WRITE) ||
443 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000444 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000445 if ((flags & GENERIC_READ) ||
446 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000447 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000448 if ((flags & GENERIC_EXECUTE) ||
449 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000450 *pbits_to_set &= ~S_IXUGO;
451 return;
452 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000453 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000454 return;
455 }
456 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000457
Al Viro9b5e6852007-12-05 08:24:38 +0000458 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000459 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000460 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000461 return;
462 }
Al Viro9b5e6852007-12-05 08:24:38 +0000463 if ((flags & GENERIC_WRITE) ||
464 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000465 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000466 if ((flags & GENERIC_READ) ||
467 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000468 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000469 if ((flags & GENERIC_EXECUTE) ||
470 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000471 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000472
Joe Perchesb6b38f72010-04-21 03:50:45 +0000473 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000474 return;
475}
476
Steve Frenchce06c9f2007-11-08 21:12:01 +0000477/*
478 Generate access flags to reflect permissions mode is the existing mode.
479 This function is called for every ACE in the DACL whose SID matches
480 with either owner or group or everyone.
481*/
482
483static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
484 __u32 *pace_flags)
485{
486 /* reset access mask */
487 *pace_flags = 0x0;
488
489 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
490 mode &= bits_to_use;
491
492 /* check for R/W/X UGO since we do not know whose flags
493 is this but we have cleared all the bits sans RWX for
494 either user or group or other as per bits_to_use */
495 if (mode & S_IRUGO)
496 *pace_flags |= SET_FILE_READ_RIGHTS;
497 if (mode & S_IWUGO)
498 *pace_flags |= SET_FILE_WRITE_RIGHTS;
499 if (mode & S_IXUGO)
500 *pace_flags |= SET_FILE_EXEC_RIGHTS;
501
Joe Perchesb6b38f72010-04-21 03:50:45 +0000502 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000503 return;
504}
505
Al Viro2b210ad2008-03-29 03:09:18 +0000506static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000507 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
508{
509 int i;
510 __u16 size = 0;
511 __u32 access_req = 0;
512
513 pntace->type = ACCESS_ALLOWED;
514 pntace->flags = 0x0;
515 mode_to_access_flags(nmode, bits, &access_req);
516 if (!access_req)
517 access_req = SET_MINIMUM_RIGHTS;
518 pntace->access_req = cpu_to_le32(access_req);
519
520 pntace->sid.revision = psid->revision;
521 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500522 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000523 pntace->sid.authority[i] = psid->authority[i];
524 for (i = 0; i < psid->num_subauth; i++)
525 pntace->sid.sub_auth[i] = psid->sub_auth[i];
526
527 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
528 pntace->size = cpu_to_le16(size);
529
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000530 return size;
Steve French97837582007-12-31 07:47:21 +0000531}
532
Steve French297647c2007-10-12 04:11:59 +0000533
Steve French953f8682007-10-31 04:54:42 +0000534#ifdef CONFIG_CIFS_DEBUG2
535static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000536{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000537 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000538
539 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000540
Steve French44093ca2007-10-23 21:22:55 +0000541 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000542 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000543 return;
544 }
545
546 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000547 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000548 return;
Steve French44093ca2007-10-23 21:22:55 +0000549 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000550
Steve French44093ca2007-10-23 21:22:55 +0000551 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000552 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000553 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000554 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000555 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000556 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000557 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000558 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
559 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000560 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000561
Steve Frenchd12fd122007-10-03 19:43:19 +0000562 /* BB add length check to make sure that we do not have huge
563 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000564 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000565
Steve Frenchd12fd122007-10-03 19:43:19 +0000566 return;
567}
Steve French953f8682007-10-31 04:54:42 +0000568#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000569
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000570
Steve Frencha750e772007-10-17 22:50:39 +0000571static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000572 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400573 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000574{
575 int i;
576 int num_aces = 0;
577 int acl_size;
578 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000579 struct cifs_ace **ppace;
580
581 /* BB need to add parm so we can store the SID BB */
582
Steve French2b834572007-11-25 10:01:00 +0000583 if (!pdacl) {
584 /* no DACL in the security descriptor, set
585 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400586 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000587 return;
588 }
589
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000590 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000591 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000592 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000593 return;
594 }
595
Joe Perchesb6b38f72010-04-21 03:50:45 +0000596 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000597 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000598 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000599
Steve French7505e052007-11-01 18:03:01 +0000600 /* reset rwx permissions for user/group/other.
601 Also, if num_aces is 0 i.e. DACL has no ACEs,
602 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400603 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000604
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000605 acl_base = (char *)pdacl;
606 acl_size = sizeof(struct cifs_acl);
607
Steve Frenchadbc0352007-10-17 02:12:46 +0000608 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500609 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000610 umode_t user_mask = S_IRWXU;
611 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600612 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000613
Dan Carpenter72501702012-01-11 10:46:27 +0300614 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
615 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000616 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
617 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300618 if (!ppace) {
619 cERROR(1, "DACL memory allocation error");
620 return;
621 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000622
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000623 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000624 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000625#ifdef CONFIG_CIFS_DEBUG2
626 dump_ace(ppace[i], end_of_acl);
627#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500628 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000629 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000630 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400631 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000632 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500633 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000634 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000635 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400636 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000637 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500638 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000639 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000640 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400641 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000642 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500643 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600644 access_flags_to_mode(ppace[i]->access_req,
645 ppace[i]->type,
646 &fattr->cf_mode,
647 &other_mask);
648
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000649
Steve French44093ca2007-10-23 21:22:55 +0000650/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000651 (void *)ppace[i],
652 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000653
Steve French44093ca2007-10-23 21:22:55 +0000654 acl_base = (char *)ppace[i];
655 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000656 }
657
658 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000659 }
660
661 return;
662}
663
Steve Frenchbcb02032007-09-25 16:17:24 +0000664
Steve French97837582007-12-31 07:47:21 +0000665static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
666 struct cifs_sid *pgrpsid, __u64 nmode)
667{
Al Viro2b210ad2008-03-29 03:09:18 +0000668 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000669 struct cifs_acl *pnndacl;
670
671 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
672
673 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
674 pownersid, nmode, S_IRWXU);
675 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
676 pgrpsid, nmode, S_IRWXG);
677 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
678 &sid_everyone, nmode, S_IRWXO);
679
680 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000681 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000682
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000683 return 0;
Steve French97837582007-12-31 07:47:21 +0000684}
685
686
Steve Frenchbcb02032007-09-25 16:17:24 +0000687static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
688{
689 /* BB need to add parm so we can store the SID BB */
690
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000691 /* validate that we do not go past end of ACL - sid must be at least 8
692 bytes long (assuming no sub-auths - e.g. the null SID */
693 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000694 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000695 return -EINVAL;
696 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000697
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000698#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500699 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000700 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000701 cFYI(1, "SID revision %d num_auth %d",
702 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000703
Steve Frenchaf6f4612007-10-16 18:40:37 +0000704 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000705 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
706 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000707 }
708
Steve Frenchd12fd122007-10-03 19:43:19 +0000709 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000710 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000711 cFYI(1, "RID 0x%x",
712 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000713 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500714#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000715
Steve Frenchbcb02032007-09-25 16:17:24 +0000716 return 0;
717}
718
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000719
Steve Frenchbcb02032007-09-25 16:17:24 +0000720/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500721static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
722 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000723{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500724 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000725 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
726 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000727 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000728 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000729
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400730 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000731 return -EIO;
732
Steve Frenchbcb02032007-09-25 16:17:24 +0000733 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000734 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000735 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000736 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000737 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000738 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000739 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000740 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000741 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
742 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000743 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000744/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000745 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500746 if (rc) {
747 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000748 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500749 }
750 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
751 if (rc) {
752 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
753 return rc;
754 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000755
756 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500757 if (rc) {
758 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000759 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500760 }
761 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
762 if (rc) {
763 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
764 return rc;
765 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000766
Steve French7505e052007-11-01 18:03:01 +0000767 if (dacloffset)
768 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400769 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000770 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000771 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000772
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500773 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000774}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000775
Steve French97837582007-12-31 07:47:21 +0000776/* Convert permission bits from mode to equivalent CIFS ACL */
777static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500778 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000779{
780 int rc = 0;
781 __u32 dacloffset;
782 __u32 ndacloffset;
783 __u32 sidsoffset;
784 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500785 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000786 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
787 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
788
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500789 if (nmode != NO_CHANGE_64) { /* chmod */
790 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000791 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500792 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000793 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500794 dacloffset = le32_to_cpu(pntsd->dacloffset);
795 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
796 ndacloffset = sizeof(struct cifs_ntsd);
797 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
798 ndacl_ptr->revision = dacl_ptr->revision;
799 ndacl_ptr->size = 0;
800 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000801
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500802 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
803 nmode);
804 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
805 /* copy sec desc control portion & owner and group sids */
806 copy_sec_desc(pntsd, pnntsd, sidsoffset);
807 *aclflag = CIFS_ACL_DACL;
808 } else {
809 memcpy(pnntsd, pntsd, secdesclen);
810 if (uid != NO_CHANGE_32) { /* chown */
811 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
812 le32_to_cpu(pnntsd->osidoffset));
813 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
814 GFP_KERNEL);
815 if (!nowner_sid_ptr)
816 return -ENOMEM;
817 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
818 if (rc) {
819 cFYI(1, "%s: Mapping error %d for owner id %d",
820 __func__, rc, uid);
821 kfree(nowner_sid_ptr);
822 return rc;
823 }
Jeff Layton36960e42012-11-03 09:37:28 -0400824 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500825 kfree(nowner_sid_ptr);
826 *aclflag = CIFS_ACL_OWNER;
827 }
828 if (gid != NO_CHANGE_32) { /* chgrp */
829 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
830 le32_to_cpu(pnntsd->gsidoffset));
831 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
832 GFP_KERNEL);
833 if (!ngroup_sid_ptr)
834 return -ENOMEM;
835 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
836 if (rc) {
837 cFYI(1, "%s: Mapping error %d for group id %d",
838 __func__, rc, gid);
839 kfree(ngroup_sid_ptr);
840 return rc;
841 }
Jeff Layton36960e42012-11-03 09:37:28 -0400842 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500843 kfree(ngroup_sid_ptr);
844 *aclflag = CIFS_ACL_GROUP;
845 }
846 }
Steve French97837582007-12-31 07:47:21 +0000847
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000848 return rc;
Steve French97837582007-12-31 07:47:21 +0000849}
850
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400851static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
852 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000853{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000854 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400855 unsigned int xid;
856 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400857 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
858
859 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600860 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000861
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400862 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400863 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400864 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000865
Jeff Layton7ffec372010-09-29 19:51:11 -0400866 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000867
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600868 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
869 if (rc)
870 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400871 return pntsd;
872}
873
874static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
875 const char *path, u32 *pacllen)
876{
877 struct cifs_ntsd *pntsd = NULL;
878 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400879 unsigned int xid;
880 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400881 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000882 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400883 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400884
Jeff Layton7ffec372010-09-29 19:51:11 -0400885 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600886 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400887
888 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400889 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400890
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500891 if (backup_cred(cifs_sb))
892 create_options |= CREATE_OPEN_BACKUP_INTENT;
893
894 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
895 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
896 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600897 if (!rc) {
898 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
899 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000900 }
901
Jeff Layton7ffec372010-09-29 19:51:11 -0400902 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400903 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600904
905 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
906 if (rc)
907 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000908 return pntsd;
909}
910
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400911/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600912struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400913 struct inode *inode, const char *path,
914 u32 *pacllen)
915{
916 struct cifs_ntsd *pntsd = NULL;
917 struct cifsFileInfo *open_file = NULL;
918
919 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400920 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400921 if (!open_file)
922 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
923
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700924 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400925 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400926 return pntsd;
927}
928
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500929 /* Set an ACL on the server */
930int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
931 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400932{
933 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400934 unsigned int xid;
935 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000936 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000937 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500938 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400939 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000940
Jeff Layton7ffec372010-09-29 19:51:11 -0400941 if (IS_ERR(tlink))
942 return PTR_ERR(tlink);
943
944 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400945 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000946
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500947 if (backup_cred(cifs_sb))
948 create_options |= CREATE_OPEN_BACKUP_INTENT;
949
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500950 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
951 access_flags = WRITE_OWNER;
952 else
953 access_flags = WRITE_DAC;
954
955 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
956 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
957 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400958 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000959 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400960 goto out;
Steve French97837582007-12-31 07:47:21 +0000961 }
962
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500963 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000964 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000965
Jeff Layton7ffec372010-09-29 19:51:11 -0400966 CIFSSMBClose(xid, tcon, fid);
967out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400968 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400969 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400970 return rc;
971}
Steve French97837582007-12-31 07:47:21 +0000972
Steve French7505e052007-11-01 18:03:01 +0000973/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600974int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400975cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
976 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000977{
978 struct cifs_ntsd *pntsd = NULL;
979 u32 acllen = 0;
980 int rc = 0;
981
Joe Perchesb6b38f72010-04-21 03:50:45 +0000982 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400983
984 if (pfid)
985 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
986 else
987 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000988
989 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600990 if (IS_ERR(pntsd)) {
991 rc = PTR_ERR(pntsd);
992 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
993 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500994 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600995 kfree(pntsd);
996 if (rc)
997 cERROR(1, "parse sec desc failed rc = %d", rc);
998 }
Steve French7505e052007-11-01 18:03:01 +0000999
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001000 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001001}
Steve French953f8682007-10-31 04:54:42 +00001002
Steve French7505e052007-11-01 18:03:01 +00001003/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001004int
1005id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1006 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001007{
1008 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001009 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001010 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001011 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1012 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001013
Joe Perchesb6b38f72010-04-21 03:50:45 +00001014 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001015
1016 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001017 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001018 if (IS_ERR(pntsd)) {
1019 rc = PTR_ERR(pntsd);
1020 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001021 goto out;
Steve French97837582007-12-31 07:47:21 +00001022 }
1023
Jeff Laytonc78cd832012-11-25 08:00:35 -05001024 /*
1025 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1026 * as chmod disables ACEs and set the security descriptor. Allocate
1027 * memory for the smb header, set security descriptor request security
1028 * descriptor parameters, and secuirty descriptor itself
1029 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001030 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001031 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1032 if (!pnntsd) {
1033 cERROR(1, "Unable to allocate security descriptor");
1034 kfree(pntsd);
1035 return -ENOMEM;
1036 }
1037
1038 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1039 &aclflag);
1040
1041 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1042
1043 if (!rc) {
1044 /* Set the security descriptor */
1045 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1046 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1047 }
1048
1049 kfree(pnntsd);
1050 kfree(pntsd);
1051out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001052 return rc;
Steve French953f8682007-10-31 04:54:42 +00001053}