blob: aaaf5ce142b8d3f31fec67ef90d34a6d3114240f [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
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800350 keyring = keyring_alloc(".cifs_idmap",
351 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
David Howellsf8aa23a2012-10-02 19:24:56 +0100352 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
353 KEY_USR_VIEW | KEY_USR_READ,
354 KEY_ALLOC_NOT_IN_QUOTA, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500355 if (IS_ERR(keyring)) {
356 ret = PTR_ERR(keyring);
357 goto failed_put_cred;
358 }
359
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500360 ret = register_key_type(&cifs_idmap_key_type);
361 if (ret < 0)
362 goto failed_put_key;
363
364 /* instruct request_key() to use this special keyring as a cache for
365 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000366 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500367 cred->thread_keyring = keyring;
368 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
369 root_cred = cred;
370
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400371 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500372 return 0;
373
374failed_put_key:
375 key_put(keyring);
376failed_put_cred:
377 put_cred(cred);
378 return ret;
379}
380
381void
382exit_cifs_idmap(void)
383{
384 key_revoke(root_cred->thread_keyring);
385 unregister_key_type(&cifs_idmap_key_type);
386 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400387 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500388}
389
Steve French97837582007-12-31 07:47:21 +0000390/* copy ntsd, owner sid, and group sid from a security descriptor to another */
391static void copy_sec_desc(const struct cifs_ntsd *pntsd,
392 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
393{
Steve French97837582007-12-31 07:47:21 +0000394 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
395 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
396
397 /* copy security descriptor control portion */
398 pnntsd->revision = pntsd->revision;
399 pnntsd->type = pntsd->type;
400 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
401 pnntsd->sacloffset = 0;
402 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
403 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
404
405 /* copy owner sid */
406 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
407 le32_to_cpu(pntsd->osidoffset));
408 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400409 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000410
411 /* copy group sid */
412 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
413 le32_to_cpu(pntsd->gsidoffset));
414 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
415 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400416 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000417
418 return;
419}
420
421
Steve French630f3f0c2007-10-25 21:17:17 +0000422/*
423 change posix mode to reflect permissions
424 pmode is the existing mode (we only want to overwrite part of this
425 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
426*/
Al Viro9b5e6852007-12-05 08:24:38 +0000427static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000428 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000429{
Al Viro9b5e6852007-12-05 08:24:38 +0000430 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000431 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000432 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000433 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000434 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000435 for the operation you are trying to perform for your user */
436
437 /* For deny ACEs we change the mask so that subsequent allow access
438 control entries do not turn on the bits we are denying */
439 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000440 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000441 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000442
Al Viro9b5e6852007-12-05 08:24:38 +0000443 if ((flags & GENERIC_WRITE) ||
444 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000445 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000446 if ((flags & GENERIC_READ) ||
447 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000448 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000449 if ((flags & GENERIC_EXECUTE) ||
450 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000451 *pbits_to_set &= ~S_IXUGO;
452 return;
453 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000454 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000455 return;
456 }
457 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000458
Al Viro9b5e6852007-12-05 08:24:38 +0000459 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000460 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000461 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000462 return;
463 }
Al Viro9b5e6852007-12-05 08:24:38 +0000464 if ((flags & GENERIC_WRITE) ||
465 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000466 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000467 if ((flags & GENERIC_READ) ||
468 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000469 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000470 if ((flags & GENERIC_EXECUTE) ||
471 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000472 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000473
Joe Perchesb6b38f72010-04-21 03:50:45 +0000474 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000475 return;
476}
477
Steve Frenchce06c9f2007-11-08 21:12:01 +0000478/*
479 Generate access flags to reflect permissions mode is the existing mode.
480 This function is called for every ACE in the DACL whose SID matches
481 with either owner or group or everyone.
482*/
483
484static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
485 __u32 *pace_flags)
486{
487 /* reset access mask */
488 *pace_flags = 0x0;
489
490 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
491 mode &= bits_to_use;
492
493 /* check for R/W/X UGO since we do not know whose flags
494 is this but we have cleared all the bits sans RWX for
495 either user or group or other as per bits_to_use */
496 if (mode & S_IRUGO)
497 *pace_flags |= SET_FILE_READ_RIGHTS;
498 if (mode & S_IWUGO)
499 *pace_flags |= SET_FILE_WRITE_RIGHTS;
500 if (mode & S_IXUGO)
501 *pace_flags |= SET_FILE_EXEC_RIGHTS;
502
Joe Perchesb6b38f72010-04-21 03:50:45 +0000503 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000504 return;
505}
506
Al Viro2b210ad2008-03-29 03:09:18 +0000507static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000508 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
509{
510 int i;
511 __u16 size = 0;
512 __u32 access_req = 0;
513
514 pntace->type = ACCESS_ALLOWED;
515 pntace->flags = 0x0;
516 mode_to_access_flags(nmode, bits, &access_req);
517 if (!access_req)
518 access_req = SET_MINIMUM_RIGHTS;
519 pntace->access_req = cpu_to_le32(access_req);
520
521 pntace->sid.revision = psid->revision;
522 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500523 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000524 pntace->sid.authority[i] = psid->authority[i];
525 for (i = 0; i < psid->num_subauth; i++)
526 pntace->sid.sub_auth[i] = psid->sub_auth[i];
527
528 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
529 pntace->size = cpu_to_le16(size);
530
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000531 return size;
Steve French97837582007-12-31 07:47:21 +0000532}
533
Steve French297647c2007-10-12 04:11:59 +0000534
Steve French953f8682007-10-31 04:54:42 +0000535#ifdef CONFIG_CIFS_DEBUG2
536static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000537{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000538 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000539
540 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000541
Steve French44093ca2007-10-23 21:22:55 +0000542 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000543 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000544 return;
545 }
546
547 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000548 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000549 return;
Steve French44093ca2007-10-23 21:22:55 +0000550 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000551
Steve French44093ca2007-10-23 21:22:55 +0000552 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000553 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000554 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000555 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000556 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000557 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000558 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000559 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
560 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000561 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000562
Steve Frenchd12fd122007-10-03 19:43:19 +0000563 /* BB add length check to make sure that we do not have huge
564 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000565 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000566
Steve Frenchd12fd122007-10-03 19:43:19 +0000567 return;
568}
Steve French953f8682007-10-31 04:54:42 +0000569#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000570
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000571
Steve Frencha750e772007-10-17 22:50:39 +0000572static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000573 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400574 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000575{
576 int i;
577 int num_aces = 0;
578 int acl_size;
579 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000580 struct cifs_ace **ppace;
581
582 /* BB need to add parm so we can store the SID BB */
583
Steve French2b834572007-11-25 10:01:00 +0000584 if (!pdacl) {
585 /* no DACL in the security descriptor, set
586 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400587 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000588 return;
589 }
590
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000591 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000592 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000593 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000594 return;
595 }
596
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000598 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000599 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000600
Steve French7505e052007-11-01 18:03:01 +0000601 /* reset rwx permissions for user/group/other.
602 Also, if num_aces is 0 i.e. DACL has no ACEs,
603 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400604 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000605
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000606 acl_base = (char *)pdacl;
607 acl_size = sizeof(struct cifs_acl);
608
Steve Frenchadbc0352007-10-17 02:12:46 +0000609 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500610 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000611 umode_t user_mask = S_IRWXU;
612 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600613 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000614
Dan Carpenter72501702012-01-11 10:46:27 +0300615 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
616 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000617 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
618 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300619 if (!ppace) {
620 cERROR(1, "DACL memory allocation error");
621 return;
622 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000623
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000624 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000625 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000626#ifdef CONFIG_CIFS_DEBUG2
627 dump_ace(ppace[i], end_of_acl);
628#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500629 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000630 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000631 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400632 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000633 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500634 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000635 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000636 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400637 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000638 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500639 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000640 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000641 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400642 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000643 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500644 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600645 access_flags_to_mode(ppace[i]->access_req,
646 ppace[i]->type,
647 &fattr->cf_mode,
648 &other_mask);
649
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000650
Steve French44093ca2007-10-23 21:22:55 +0000651/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000652 (void *)ppace[i],
653 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000654
Steve French44093ca2007-10-23 21:22:55 +0000655 acl_base = (char *)ppace[i];
656 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000657 }
658
659 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000660 }
661
662 return;
663}
664
Steve Frenchbcb02032007-09-25 16:17:24 +0000665
Steve French97837582007-12-31 07:47:21 +0000666static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
667 struct cifs_sid *pgrpsid, __u64 nmode)
668{
Al Viro2b210ad2008-03-29 03:09:18 +0000669 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000670 struct cifs_acl *pnndacl;
671
672 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
673
674 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
675 pownersid, nmode, S_IRWXU);
676 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
677 pgrpsid, nmode, S_IRWXG);
678 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
679 &sid_everyone, nmode, S_IRWXO);
680
681 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000682 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000683
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000684 return 0;
Steve French97837582007-12-31 07:47:21 +0000685}
686
687
Steve Frenchbcb02032007-09-25 16:17:24 +0000688static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
689{
690 /* BB need to add parm so we can store the SID BB */
691
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000692 /* validate that we do not go past end of ACL - sid must be at least 8
693 bytes long (assuming no sub-auths - e.g. the null SID */
694 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000695 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000696 return -EINVAL;
697 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000698
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000699#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500700 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000701 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cFYI(1, "SID revision %d num_auth %d",
703 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000704
Steve Frenchaf6f4612007-10-16 18:40:37 +0000705 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000706 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
707 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000708 }
709
Steve Frenchd12fd122007-10-03 19:43:19 +0000710 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000711 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000712 cFYI(1, "RID 0x%x",
713 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000714 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500715#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000716
Steve Frenchbcb02032007-09-25 16:17:24 +0000717 return 0;
718}
719
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000720
Steve Frenchbcb02032007-09-25 16:17:24 +0000721/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500722static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
723 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000724{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500725 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000726 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
727 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000728 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000729 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000730
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400731 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000732 return -EIO;
733
Steve Frenchbcb02032007-09-25 16:17:24 +0000734 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000735 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000736 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000737 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000738 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000739 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000740 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000741 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000742 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
743 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000744 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000745/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000746 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500747 if (rc) {
748 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000749 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500750 }
751 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
752 if (rc) {
753 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
754 return rc;
755 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000756
757 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500758 if (rc) {
759 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000760 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500761 }
762 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
763 if (rc) {
764 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
765 return rc;
766 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000767
Steve French7505e052007-11-01 18:03:01 +0000768 if (dacloffset)
769 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400770 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000771 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000772 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000773
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500774 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000775}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000776
Steve French97837582007-12-31 07:47:21 +0000777/* Convert permission bits from mode to equivalent CIFS ACL */
778static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500779 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000780{
781 int rc = 0;
782 __u32 dacloffset;
783 __u32 ndacloffset;
784 __u32 sidsoffset;
785 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500786 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000787 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
788 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
789
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500790 if (nmode != NO_CHANGE_64) { /* chmod */
791 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000792 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500793 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000794 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500795 dacloffset = le32_to_cpu(pntsd->dacloffset);
796 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
797 ndacloffset = sizeof(struct cifs_ntsd);
798 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
799 ndacl_ptr->revision = dacl_ptr->revision;
800 ndacl_ptr->size = 0;
801 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000802
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500803 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
804 nmode);
805 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
806 /* copy sec desc control portion & owner and group sids */
807 copy_sec_desc(pntsd, pnntsd, sidsoffset);
808 *aclflag = CIFS_ACL_DACL;
809 } else {
810 memcpy(pnntsd, pntsd, secdesclen);
811 if (uid != NO_CHANGE_32) { /* chown */
812 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
813 le32_to_cpu(pnntsd->osidoffset));
814 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
815 GFP_KERNEL);
816 if (!nowner_sid_ptr)
817 return -ENOMEM;
818 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
819 if (rc) {
820 cFYI(1, "%s: Mapping error %d for owner id %d",
821 __func__, rc, uid);
822 kfree(nowner_sid_ptr);
823 return rc;
824 }
Jeff Layton36960e42012-11-03 09:37:28 -0400825 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500826 kfree(nowner_sid_ptr);
827 *aclflag = CIFS_ACL_OWNER;
828 }
829 if (gid != NO_CHANGE_32) { /* chgrp */
830 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
831 le32_to_cpu(pnntsd->gsidoffset));
832 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
833 GFP_KERNEL);
834 if (!ngroup_sid_ptr)
835 return -ENOMEM;
836 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
837 if (rc) {
838 cFYI(1, "%s: Mapping error %d for group id %d",
839 __func__, rc, gid);
840 kfree(ngroup_sid_ptr);
841 return rc;
842 }
Jeff Layton36960e42012-11-03 09:37:28 -0400843 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500844 kfree(ngroup_sid_ptr);
845 *aclflag = CIFS_ACL_GROUP;
846 }
847 }
Steve French97837582007-12-31 07:47:21 +0000848
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000849 return rc;
Steve French97837582007-12-31 07:47:21 +0000850}
851
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400852static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
853 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000854{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000855 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400856 unsigned int xid;
857 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400858 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
859
860 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600861 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000862
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400863 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400864 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400865 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000866
Jeff Layton7ffec372010-09-29 19:51:11 -0400867 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000868
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600869 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
870 if (rc)
871 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400872 return pntsd;
873}
874
875static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
876 const char *path, u32 *pacllen)
877{
878 struct cifs_ntsd *pntsd = NULL;
879 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400880 unsigned int xid;
881 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400882 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000883 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400884 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400885
Jeff Layton7ffec372010-09-29 19:51:11 -0400886 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600887 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400888
889 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400890 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400891
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500892 if (backup_cred(cifs_sb))
893 create_options |= CREATE_OPEN_BACKUP_INTENT;
894
895 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
896 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
897 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600898 if (!rc) {
899 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
900 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000901 }
902
Jeff Layton7ffec372010-09-29 19:51:11 -0400903 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400904 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600905
906 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
907 if (rc)
908 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000909 return pntsd;
910}
911
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400912/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600913struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400914 struct inode *inode, const char *path,
915 u32 *pacllen)
916{
917 struct cifs_ntsd *pntsd = NULL;
918 struct cifsFileInfo *open_file = NULL;
919
920 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400921 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400922 if (!open_file)
923 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
924
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700925 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400926 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400927 return pntsd;
928}
929
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500930 /* Set an ACL on the server */
931int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
932 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400933{
934 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400935 unsigned int xid;
936 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000937 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000938 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500939 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400940 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000941
Jeff Layton7ffec372010-09-29 19:51:11 -0400942 if (IS_ERR(tlink))
943 return PTR_ERR(tlink);
944
945 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400946 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000947
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500948 if (backup_cred(cifs_sb))
949 create_options |= CREATE_OPEN_BACKUP_INTENT;
950
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500951 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
952 access_flags = WRITE_OWNER;
953 else
954 access_flags = WRITE_DAC;
955
956 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
957 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
958 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400959 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000960 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400961 goto out;
Steve French97837582007-12-31 07:47:21 +0000962 }
963
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500964 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000965 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000966
Jeff Layton7ffec372010-09-29 19:51:11 -0400967 CIFSSMBClose(xid, tcon, fid);
968out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400969 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400970 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400971 return rc;
972}
Steve French97837582007-12-31 07:47:21 +0000973
Steve French7505e052007-11-01 18:03:01 +0000974/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600975int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400976cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
977 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000978{
979 struct cifs_ntsd *pntsd = NULL;
980 u32 acllen = 0;
981 int rc = 0;
982
Joe Perchesb6b38f72010-04-21 03:50:45 +0000983 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400984
985 if (pfid)
986 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
987 else
988 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000989
990 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600991 if (IS_ERR(pntsd)) {
992 rc = PTR_ERR(pntsd);
993 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
994 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500995 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600996 kfree(pntsd);
997 if (rc)
998 cERROR(1, "parse sec desc failed rc = %d", rc);
999 }
Steve French7505e052007-11-01 18:03:01 +00001000
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001001 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001002}
Steve French953f8682007-10-31 04:54:42 +00001003
Steve French7505e052007-11-01 18:03:01 +00001004/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001005int
1006id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1007 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001008{
1009 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001010 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001011 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001012 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1013 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001014
Joe Perchesb6b38f72010-04-21 03:50:45 +00001015 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001016
1017 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001018 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001019 if (IS_ERR(pntsd)) {
1020 rc = PTR_ERR(pntsd);
1021 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001022 goto out;
Steve French97837582007-12-31 07:47:21 +00001023 }
1024
Jeff Laytonc78cd832012-11-25 08:00:35 -05001025 /*
1026 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1027 * as chmod disables ACEs and set the security descriptor. Allocate
1028 * memory for the smb header, set security descriptor request security
1029 * descriptor parameters, and secuirty descriptor itself
1030 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001031 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001032 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1033 if (!pnntsd) {
1034 cERROR(1, "Unable to allocate security descriptor");
1035 kfree(pntsd);
1036 return -ENOMEM;
1037 }
1038
1039 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1040 &aclflag);
1041
1042 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1043
1044 if (!rc) {
1045 /* Set the security descriptor */
1046 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1047 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1048 }
1049
1050 kfree(pnntsd);
1051 kfree(pntsd);
1052out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001053 return rc;
Steve French953f8682007-10-31 04:54:42 +00001054}