blob: f1e3f25fe00412a584a70883a5cf6f661741d821 [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;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800269 kuid_t fuid = cifs_sb->mnt_uid;
270 kgid_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
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800309 if (sidtype == SIDOWNER) {
310 kuid_t uid;
311 uid_t id;
312 memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
313 uid = make_kuid(&init_user_ns, id);
314 if (uid_valid(uid))
315 fuid = uid;
316 } else {
317 kgid_t gid;
318 gid_t id;
319 memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
320 gid = make_kgid(&init_user_ns, id);
321 if (gid_valid(gid))
322 fgid = gid;
323 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500324
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500325out_key_put:
326 key_put(sidkey);
327out_revert_creds:
328 revert_creds(saved_cred);
329 kfree(sidstr);
330
331 /*
332 * Note that we return 0 here unconditionally. If the mapping
333 * fails then we just fall back to using the mnt_uid/mnt_gid.
334 */
335 if (sidtype == SIDOWNER)
336 fattr->cf_uid = fuid;
337 else
338 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500339 return 0;
340}
341
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500342int
343init_cifs_idmap(void)
344{
345 struct cred *cred;
346 struct key *keyring;
347 int ret;
348
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400349 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500350
351 /* create an override credential set with a special thread keyring in
352 * which requests are cached
353 *
354 * this is used to prevent malicious redirections from being installed
355 * with add_key().
356 */
357 cred = prepare_kernel_cred(NULL);
358 if (!cred)
359 return -ENOMEM;
360
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800361 keyring = keyring_alloc(".cifs_idmap",
362 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
David Howellsf8aa23a2012-10-02 19:24:56 +0100363 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
364 KEY_USR_VIEW | KEY_USR_READ,
365 KEY_ALLOC_NOT_IN_QUOTA, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500366 if (IS_ERR(keyring)) {
367 ret = PTR_ERR(keyring);
368 goto failed_put_cred;
369 }
370
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500371 ret = register_key_type(&cifs_idmap_key_type);
372 if (ret < 0)
373 goto failed_put_key;
374
375 /* instruct request_key() to use this special keyring as a cache for
376 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000377 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500378 cred->thread_keyring = keyring;
379 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
380 root_cred = cred;
381
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400382 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500383 return 0;
384
385failed_put_key:
386 key_put(keyring);
387failed_put_cred:
388 put_cred(cred);
389 return ret;
390}
391
392void
393exit_cifs_idmap(void)
394{
395 key_revoke(root_cred->thread_keyring);
396 unregister_key_type(&cifs_idmap_key_type);
397 put_cred(root_cred);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400398 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500399}
400
Steve French97837582007-12-31 07:47:21 +0000401/* copy ntsd, owner sid, and group sid from a security descriptor to another */
402static void copy_sec_desc(const struct cifs_ntsd *pntsd,
403 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
404{
Steve French97837582007-12-31 07:47:21 +0000405 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
406 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
407
408 /* copy security descriptor control portion */
409 pnntsd->revision = pntsd->revision;
410 pnntsd->type = pntsd->type;
411 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
412 pnntsd->sacloffset = 0;
413 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
414 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
415
416 /* copy owner sid */
417 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
418 le32_to_cpu(pntsd->osidoffset));
419 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400420 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000421
422 /* copy group sid */
423 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
424 le32_to_cpu(pntsd->gsidoffset));
425 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
426 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400427 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000428
429 return;
430}
431
432
Steve French630f3f0c2007-10-25 21:17:17 +0000433/*
434 change posix mode to reflect permissions
435 pmode is the existing mode (we only want to overwrite part of this
436 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
437*/
Al Viro9b5e6852007-12-05 08:24:38 +0000438static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000439 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000440{
Al Viro9b5e6852007-12-05 08:24:38 +0000441 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000442 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000443 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000444 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000445 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000446 for the operation you are trying to perform for your user */
447
448 /* For deny ACEs we change the mask so that subsequent allow access
449 control entries do not turn on the bits we are denying */
450 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000451 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000452 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000453
Al Viro9b5e6852007-12-05 08:24:38 +0000454 if ((flags & GENERIC_WRITE) ||
455 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000456 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000457 if ((flags & GENERIC_READ) ||
458 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000459 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000460 if ((flags & GENERIC_EXECUTE) ||
461 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000462 *pbits_to_set &= ~S_IXUGO;
463 return;
464 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000465 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000466 return;
467 }
468 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000469
Al Viro9b5e6852007-12-05 08:24:38 +0000470 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000471 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000472 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000473 return;
474 }
Al Viro9b5e6852007-12-05 08:24:38 +0000475 if ((flags & GENERIC_WRITE) ||
476 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000477 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000478 if ((flags & GENERIC_READ) ||
479 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000480 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000481 if ((flags & GENERIC_EXECUTE) ||
482 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000483 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000484
Joe Perchesb6b38f72010-04-21 03:50:45 +0000485 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000486 return;
487}
488
Steve Frenchce06c9f2007-11-08 21:12:01 +0000489/*
490 Generate access flags to reflect permissions mode is the existing mode.
491 This function is called for every ACE in the DACL whose SID matches
492 with either owner or group or everyone.
493*/
494
495static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
496 __u32 *pace_flags)
497{
498 /* reset access mask */
499 *pace_flags = 0x0;
500
501 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
502 mode &= bits_to_use;
503
504 /* check for R/W/X UGO since we do not know whose flags
505 is this but we have cleared all the bits sans RWX for
506 either user or group or other as per bits_to_use */
507 if (mode & S_IRUGO)
508 *pace_flags |= SET_FILE_READ_RIGHTS;
509 if (mode & S_IWUGO)
510 *pace_flags |= SET_FILE_WRITE_RIGHTS;
511 if (mode & S_IXUGO)
512 *pace_flags |= SET_FILE_EXEC_RIGHTS;
513
Joe Perchesb6b38f72010-04-21 03:50:45 +0000514 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000515 return;
516}
517
Al Viro2b210ad2008-03-29 03:09:18 +0000518static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000519 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
520{
521 int i;
522 __u16 size = 0;
523 __u32 access_req = 0;
524
525 pntace->type = ACCESS_ALLOWED;
526 pntace->flags = 0x0;
527 mode_to_access_flags(nmode, bits, &access_req);
528 if (!access_req)
529 access_req = SET_MINIMUM_RIGHTS;
530 pntace->access_req = cpu_to_le32(access_req);
531
532 pntace->sid.revision = psid->revision;
533 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500534 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000535 pntace->sid.authority[i] = psid->authority[i];
536 for (i = 0; i < psid->num_subauth; i++)
537 pntace->sid.sub_auth[i] = psid->sub_auth[i];
538
539 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
540 pntace->size = cpu_to_le16(size);
541
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000542 return size;
Steve French97837582007-12-31 07:47:21 +0000543}
544
Steve French297647c2007-10-12 04:11:59 +0000545
Steve French953f8682007-10-31 04:54:42 +0000546#ifdef CONFIG_CIFS_DEBUG2
547static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000548{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000549 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000550
551 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000552
Steve French44093ca2007-10-23 21:22:55 +0000553 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000554 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000555 return;
556 }
557
558 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000559 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000560 return;
Steve French44093ca2007-10-23 21:22:55 +0000561 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000562
Steve French44093ca2007-10-23 21:22:55 +0000563 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000564 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000565 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000566 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000567 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000568 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000569 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000570 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
571 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000572 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000573
Steve Frenchd12fd122007-10-03 19:43:19 +0000574 /* BB add length check to make sure that we do not have huge
575 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000576 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000577
Steve Frenchd12fd122007-10-03 19:43:19 +0000578 return;
579}
Steve French953f8682007-10-31 04:54:42 +0000580#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000581
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000582
Steve Frencha750e772007-10-17 22:50:39 +0000583static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000584 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400585 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000586{
587 int i;
588 int num_aces = 0;
589 int acl_size;
590 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000591 struct cifs_ace **ppace;
592
593 /* BB need to add parm so we can store the SID BB */
594
Steve French2b834572007-11-25 10:01:00 +0000595 if (!pdacl) {
596 /* no DACL in the security descriptor, set
597 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400598 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000599 return;
600 }
601
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000602 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000603 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000604 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000605 return;
606 }
607
Joe Perchesb6b38f72010-04-21 03:50:45 +0000608 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000609 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000610 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000611
Steve French7505e052007-11-01 18:03:01 +0000612 /* reset rwx permissions for user/group/other.
613 Also, if num_aces is 0 i.e. DACL has no ACEs,
614 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400615 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000616
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000617 acl_base = (char *)pdacl;
618 acl_size = sizeof(struct cifs_acl);
619
Steve Frenchadbc0352007-10-17 02:12:46 +0000620 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500621 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000622 umode_t user_mask = S_IRWXU;
623 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600624 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000625
Dan Carpenter72501702012-01-11 10:46:27 +0300626 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
627 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000628 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
629 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300630 if (!ppace) {
631 cERROR(1, "DACL memory allocation error");
632 return;
633 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000634
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000635 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000636 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000637#ifdef CONFIG_CIFS_DEBUG2
638 dump_ace(ppace[i], end_of_acl);
639#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500640 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000641 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000642 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400643 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000644 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500645 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000646 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000647 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400648 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000649 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500650 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000651 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000652 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400653 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000654 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500655 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600656 access_flags_to_mode(ppace[i]->access_req,
657 ppace[i]->type,
658 &fattr->cf_mode,
659 &other_mask);
660
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000661
Steve French44093ca2007-10-23 21:22:55 +0000662/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000663 (void *)ppace[i],
664 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000665
Steve French44093ca2007-10-23 21:22:55 +0000666 acl_base = (char *)ppace[i];
667 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000668 }
669
670 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000671 }
672
673 return;
674}
675
Steve Frenchbcb02032007-09-25 16:17:24 +0000676
Steve French97837582007-12-31 07:47:21 +0000677static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
678 struct cifs_sid *pgrpsid, __u64 nmode)
679{
Al Viro2b210ad2008-03-29 03:09:18 +0000680 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000681 struct cifs_acl *pnndacl;
682
683 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
684
685 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
686 pownersid, nmode, S_IRWXU);
687 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
688 pgrpsid, nmode, S_IRWXG);
689 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
690 &sid_everyone, nmode, S_IRWXO);
691
692 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000693 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000694
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000695 return 0;
Steve French97837582007-12-31 07:47:21 +0000696}
697
698
Steve Frenchbcb02032007-09-25 16:17:24 +0000699static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
700{
701 /* BB need to add parm so we can store the SID BB */
702
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000703 /* validate that we do not go past end of ACL - sid must be at least 8
704 bytes long (assuming no sub-auths - e.g. the null SID */
705 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000706 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000707 return -EINVAL;
708 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000709
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000710#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500711 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000712 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000713 cFYI(1, "SID revision %d num_auth %d",
714 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000715
Steve Frenchaf6f4612007-10-16 18:40:37 +0000716 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000717 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
718 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000719 }
720
Steve Frenchd12fd122007-10-03 19:43:19 +0000721 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000722 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000723 cFYI(1, "RID 0x%x",
724 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000725 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500726#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000727
Steve Frenchbcb02032007-09-25 16:17:24 +0000728 return 0;
729}
730
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000731
Steve Frenchbcb02032007-09-25 16:17:24 +0000732/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500733static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
734 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000735{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500736 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000737 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
738 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000739 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000740 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000741
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400742 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000743 return -EIO;
744
Steve Frenchbcb02032007-09-25 16:17:24 +0000745 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000746 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000747 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000748 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000749 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000750 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000751 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000752 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000753 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
754 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000756/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000757 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500758 if (rc) {
759 cFYI(1, "%s: Error %d parsing Owner SID", __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, owner_sid_ptr, fattr, SIDOWNER);
763 if (rc) {
764 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
765 return rc;
766 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000767
768 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500769 if (rc) {
770 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000771 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500772 }
773 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
774 if (rc) {
775 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
776 return rc;
777 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000778
Steve French7505e052007-11-01 18:03:01 +0000779 if (dacloffset)
780 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400781 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000782 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000783 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000784
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500785 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000786}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000787
Steve French97837582007-12-31 07:47:21 +0000788/* Convert permission bits from mode to equivalent CIFS ACL */
789static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800790 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000791{
792 int rc = 0;
793 __u32 dacloffset;
794 __u32 ndacloffset;
795 __u32 sidsoffset;
796 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500797 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000798 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
799 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
800
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500801 if (nmode != NO_CHANGE_64) { /* chmod */
802 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000803 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500804 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000805 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500806 dacloffset = le32_to_cpu(pntsd->dacloffset);
807 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
808 ndacloffset = sizeof(struct cifs_ntsd);
809 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
810 ndacl_ptr->revision = dacl_ptr->revision;
811 ndacl_ptr->size = 0;
812 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000813
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500814 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
815 nmode);
816 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
817 /* copy sec desc control portion & owner and group sids */
818 copy_sec_desc(pntsd, pnntsd, sidsoffset);
819 *aclflag = CIFS_ACL_DACL;
820 } else {
821 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800822 if (uid_valid(uid)) { /* chown */
823 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500824 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
825 le32_to_cpu(pnntsd->osidoffset));
826 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
827 GFP_KERNEL);
828 if (!nowner_sid_ptr)
829 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800830 id = from_kuid(&init_user_ns, uid);
831 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500832 if (rc) {
833 cFYI(1, "%s: Mapping error %d for owner id %d",
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800834 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500835 kfree(nowner_sid_ptr);
836 return rc;
837 }
Jeff Layton36960e42012-11-03 09:37:28 -0400838 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500839 kfree(nowner_sid_ptr);
840 *aclflag = CIFS_ACL_OWNER;
841 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800842 if (gid_valid(gid)) { /* chgrp */
843 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500844 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
845 le32_to_cpu(pnntsd->gsidoffset));
846 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
847 GFP_KERNEL);
848 if (!ngroup_sid_ptr)
849 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800850 id = from_kgid(&init_user_ns, gid);
851 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500852 if (rc) {
853 cFYI(1, "%s: Mapping error %d for group id %d",
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800854 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500855 kfree(ngroup_sid_ptr);
856 return rc;
857 }
Jeff Layton36960e42012-11-03 09:37:28 -0400858 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500859 kfree(ngroup_sid_ptr);
860 *aclflag = CIFS_ACL_GROUP;
861 }
862 }
Steve French97837582007-12-31 07:47:21 +0000863
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000864 return rc;
Steve French97837582007-12-31 07:47:21 +0000865}
866
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400867static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
868 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000869{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000870 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400871 unsigned int xid;
872 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400873 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
874
875 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600876 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000877
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400878 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400879 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400880 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000881
Jeff Layton7ffec372010-09-29 19:51:11 -0400882 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000883
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600884 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
885 if (rc)
886 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400887 return pntsd;
888}
889
890static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
891 const char *path, u32 *pacllen)
892{
893 struct cifs_ntsd *pntsd = NULL;
894 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400895 unsigned int xid;
896 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400897 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000898 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400899 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400900
Jeff Layton7ffec372010-09-29 19:51:11 -0400901 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600902 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400903
904 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400905 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400906
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500907 if (backup_cred(cifs_sb))
908 create_options |= CREATE_OPEN_BACKUP_INTENT;
909
910 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
911 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
912 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600913 if (!rc) {
914 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
915 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000916 }
917
Jeff Layton7ffec372010-09-29 19:51:11 -0400918 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400919 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600920
921 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
922 if (rc)
923 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000924 return pntsd;
925}
926
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400927/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600928struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400929 struct inode *inode, const char *path,
930 u32 *pacllen)
931{
932 struct cifs_ntsd *pntsd = NULL;
933 struct cifsFileInfo *open_file = NULL;
934
935 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400936 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400937 if (!open_file)
938 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
939
Pavel Shilovsky4b4de762012-09-18 16:20:26 -0700940 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400941 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400942 return pntsd;
943}
944
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500945 /* Set an ACL on the server */
946int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
947 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400948{
949 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400950 unsigned int xid;
951 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +0000952 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000953 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500954 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400955 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000956
Jeff Layton7ffec372010-09-29 19:51:11 -0400957 if (IS_ERR(tlink))
958 return PTR_ERR(tlink);
959
960 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400961 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000962
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500963 if (backup_cred(cifs_sb))
964 create_options |= CREATE_OPEN_BACKUP_INTENT;
965
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500966 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
967 access_flags = WRITE_OWNER;
968 else
969 access_flags = WRITE_DAC;
970
971 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
972 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
973 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400974 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000975 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400976 goto out;
Steve French97837582007-12-31 07:47:21 +0000977 }
978
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500979 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000980 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000981
Jeff Layton7ffec372010-09-29 19:51:11 -0400982 CIFSSMBClose(xid, tcon, fid);
983out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400984 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400985 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400986 return rc;
987}
Steve French97837582007-12-31 07:47:21 +0000988
Steve French7505e052007-11-01 18:03:01 +0000989/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600990int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400991cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
992 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000993{
994 struct cifs_ntsd *pntsd = NULL;
995 u32 acllen = 0;
996 int rc = 0;
997
Joe Perchesb6b38f72010-04-21 03:50:45 +0000998 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400999
1000 if (pfid)
1001 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1002 else
1003 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001004
1005 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001006 if (IS_ERR(pntsd)) {
1007 rc = PTR_ERR(pntsd);
1008 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1009 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001010 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001011 kfree(pntsd);
1012 if (rc)
1013 cERROR(1, "parse sec desc failed rc = %d", rc);
1014 }
Steve French7505e052007-11-01 18:03:01 +00001015
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001016 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001017}
Steve French953f8682007-10-31 04:54:42 +00001018
Steve French7505e052007-11-01 18:03:01 +00001019/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001020int
1021id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001022 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001023{
1024 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001025 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001026 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001027 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1028 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001029
Joe Perchesb6b38f72010-04-21 03:50:45 +00001030 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001031
1032 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001033 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001034 if (IS_ERR(pntsd)) {
1035 rc = PTR_ERR(pntsd);
1036 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001037 goto out;
Steve French97837582007-12-31 07:47:21 +00001038 }
1039
Jeff Laytonc78cd832012-11-25 08:00:35 -05001040 /*
1041 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1042 * as chmod disables ACEs and set the security descriptor. Allocate
1043 * memory for the smb header, set security descriptor request security
1044 * descriptor parameters, and secuirty descriptor itself
1045 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001046 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001047 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1048 if (!pnntsd) {
1049 cERROR(1, "Unable to allocate security descriptor");
1050 kfree(pntsd);
1051 return -ENOMEM;
1052 }
1053
1054 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1055 &aclflag);
1056
1057 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1058
1059 if (!rc) {
1060 /* Set the security descriptor */
1061 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1062 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1063 }
1064
1065 kfree(pnntsd);
1066 kfree(pntsd);
1067out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001068 return rc;
Steve French953f8682007-10-31 04:54:42 +00001069}