blob: 6d00c419cbae0b54016ba997f55baf1ac7c54956 [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 }
Silviu-Mihai Popescuf7f7c182013-03-11 18:22:32 +020066 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050067 if (!payload)
68 return -ENOMEM;
69
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050070 key->payload.data = payload;
David Howellscf7f6012012-09-13 13:06:29 +010071 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050072 return 0;
73}
74
75static inline void
76cifs_idmap_key_destroy(struct key *key)
77{
Jeff Layton1f630682012-12-03 06:05:31 -050078 if (key->datalen > sizeof(key->payload))
Jeff Layton41a9f1f2012-12-03 06:05:29 -050079 kfree(key->payload.data);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050080}
81
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050082static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -050083 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050084 .instantiate = cifs_idmap_key_instantiate,
85 .destroy = cifs_idmap_key_destroy,
86 .describe = user_describe,
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050087};
88
Jeff Laytonfaa65f02012-12-03 06:05:29 -050089static char *
90sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050091{
Jeff Laytonfaa65f02012-12-03 06:05:29 -050092 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -050093 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050094 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -050095 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050096
97 /* 3 bytes for prefix */
98 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
99 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
100 GFP_KERNEL);
101 if (!sidstr)
102 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500103
104 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500105 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
106 sidptr->revision);
107 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500108
Jeff Layton193cdd82012-12-10 06:10:44 -0500109 /* The authority field is a single 48-bit number */
110 id_auth_val = (unsigned long long)sidptr->authority[5];
111 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
112 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
113 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
114 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
115 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
116
117 /*
118 * MS-DTYP states that if the authority is >= 2^32, then it should be
119 * expressed as a hex value.
120 */
121 if (id_auth_val <= UINT_MAX)
122 len = sprintf(strptr, "-%llu", id_auth_val);
123 else
124 len = sprintf(strptr, "-0x%llx", id_auth_val);
125
126 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500127
128 for (i = 0; i < sidptr->num_subauth; ++i) {
129 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500130 len = sprintf(strptr, "-%u", saval);
131 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500132 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500133
134 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500135}
136
Jeff Layton436bb432012-11-25 08:00:36 -0500137/*
138 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
139 * the same returns zero, if they do not match returns non-zero.
140 */
141static int
142compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
143{
144 int i;
145 int num_subauth, num_sat, num_saw;
146
147 if ((!ctsid) || (!cwsid))
148 return 1;
149
150 /* compare the revision */
151 if (ctsid->revision != cwsid->revision) {
152 if (ctsid->revision > cwsid->revision)
153 return 1;
154 else
155 return -1;
156 }
157
158 /* compare all of the six auth values */
159 for (i = 0; i < NUM_AUTHS; ++i) {
160 if (ctsid->authority[i] != cwsid->authority[i]) {
161 if (ctsid->authority[i] > cwsid->authority[i])
162 return 1;
163 else
164 return -1;
165 }
166 }
167
168 /* compare all of the subauth values if any */
169 num_sat = ctsid->num_subauth;
170 num_saw = cwsid->num_subauth;
171 num_subauth = num_sat < num_saw ? num_sat : num_saw;
172 if (num_subauth) {
173 for (i = 0; i < num_subauth; ++i) {
174 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
175 if (le32_to_cpu(ctsid->sub_auth[i]) >
176 le32_to_cpu(cwsid->sub_auth[i]))
177 return 1;
178 else
179 return -1;
180 }
181 }
182 }
183
184 return 0; /* sids compare/match */
185}
186
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500187static void
Jeff Layton36960e42012-11-03 09:37:28 -0400188cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
189{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500190 int i;
191
192 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500193 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500194 for (i = 0; i < NUM_AUTHS; ++i)
195 dst->authority[i] = src->authority[i];
196 for (i = 0; i < dst->num_subauth; ++i)
197 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400198}
199
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500200static int
201id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500202{
203 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500204 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500205 struct cifs_sid *ksid;
206 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500207 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500208 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500209
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500210 rc = snprintf(desc, sizeof(desc), "%ci:%u",
211 sidtype == SIDOWNER ? 'o' : 'g', cid);
212 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500213 return -EINVAL;
214
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500215 rc = 0;
216 saved_cred = override_creds(root_cred);
217 sidkey = request_key(&cifs_idmap_key_type, desc, "");
218 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500219 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500220 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
221 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500222 goto out_revert_creds;
223 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
224 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500225 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
226 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500227 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500228 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500229
Jeff Layton1f630682012-12-03 06:05:31 -0500230 /*
231 * A sid is usually too large to be embedded in payload.value, but if
232 * there are no subauthorities and the host has 8-byte pointers, then
233 * it could be.
234 */
235 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
236 (struct cifs_sid *)&sidkey->payload.value :
237 (struct cifs_sid *)sidkey->payload.data;
238
Jeff Layton2ae03022012-12-03 06:05:30 -0500239 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
240 if (ksid_size > sidkey->datalen) {
241 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500242 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
243 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500244 goto invalidate_key;
245 }
Jeff Layton1f630682012-12-03 06:05:31 -0500246
Jeff Layton2ae03022012-12-03 06:05:30 -0500247 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500248out_key_put:
249 key_put(sidkey);
250out_revert_creds:
251 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500252 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500253
254invalidate_key:
255 key_invalidate(sidkey);
256 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500257}
258
259static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500260sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
261 struct cifs_fattr *fattr, uint sidtype)
262{
263 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500264 struct key *sidkey;
265 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500266 const struct cred *saved_cred;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800267 kuid_t fuid = cifs_sb->mnt_uid;
268 kgid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500269
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500270 /*
271 * If we have too many subauthorities, then something is really wrong.
272 * Just return an error.
273 */
274 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500275 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
276 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500277 return -EIO;
278 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500279
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500280 sidstr = sid_to_key_str(psid, sidtype);
281 if (!sidstr)
282 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500283
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500284 saved_cred = override_creds(root_cred);
285 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
286 if (IS_ERR(sidkey)) {
287 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500288 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
289 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500290 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500291 }
292
293 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500294 * FIXME: Here we assume that uid_t and gid_t are same size. It's
295 * probably a safe assumption but might be better to check based on
296 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500297 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800298 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500299 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500300 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500301 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
302 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500303 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500304 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500305 }
306
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800307 if (sidtype == SIDOWNER) {
308 kuid_t uid;
309 uid_t id;
310 memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
311 uid = make_kuid(&init_user_ns, id);
312 if (uid_valid(uid))
313 fuid = uid;
314 } else {
315 kgid_t gid;
316 gid_t id;
317 memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
318 gid = make_kgid(&init_user_ns, id);
319 if (gid_valid(gid))
320 fgid = gid;
321 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500322
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500323out_key_put:
324 key_put(sidkey);
325out_revert_creds:
326 revert_creds(saved_cred);
327 kfree(sidstr);
328
329 /*
330 * Note that we return 0 here unconditionally. If the mapping
331 * fails then we just fall back to using the mnt_uid/mnt_gid.
332 */
333 if (sidtype == SIDOWNER)
334 fattr->cf_uid = fuid;
335 else
336 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500337 return 0;
338}
339
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500340int
341init_cifs_idmap(void)
342{
343 struct cred *cred;
344 struct key *keyring;
345 int ret;
346
Joe Perchesf96637b2013-05-04 22:12:25 -0500347 cifs_dbg(FYI, "Registering the %s key type\n",
348 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500349
350 /* create an override credential set with a special thread keyring in
351 * which requests are cached
352 *
353 * this is used to prevent malicious redirections from being installed
354 * with add_key().
355 */
356 cred = prepare_kernel_cred(NULL);
357 if (!cred)
358 return -ENOMEM;
359
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800360 keyring = keyring_alloc(".cifs_idmap",
361 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
David Howellsf8aa23a2012-10-02 19:24:56 +0100362 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
363 KEY_USR_VIEW | KEY_USR_READ,
364 KEY_ALLOC_NOT_IN_QUOTA, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500365 if (IS_ERR(keyring)) {
366 ret = PTR_ERR(keyring);
367 goto failed_put_cred;
368 }
369
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500370 ret = register_key_type(&cifs_idmap_key_type);
371 if (ret < 0)
372 goto failed_put_key;
373
374 /* instruct request_key() to use this special keyring as a cache for
375 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000376 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500377 cred->thread_keyring = keyring;
378 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
379 root_cred = cred;
380
Joe Perchesf96637b2013-05-04 22:12:25 -0500381 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500382 return 0;
383
384failed_put_key:
385 key_put(keyring);
386failed_put_cred:
387 put_cred(cred);
388 return ret;
389}
390
391void
392exit_cifs_idmap(void)
393{
394 key_revoke(root_cred->thread_keyring);
395 unregister_key_type(&cifs_idmap_key_type);
396 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500397 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500398}
399
Steve French97837582007-12-31 07:47:21 +0000400/* copy ntsd, owner sid, and group sid from a security descriptor to another */
401static void copy_sec_desc(const struct cifs_ntsd *pntsd,
402 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
403{
Steve French97837582007-12-31 07:47:21 +0000404 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
405 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
406
407 /* copy security descriptor control portion */
408 pnntsd->revision = pntsd->revision;
409 pnntsd->type = pntsd->type;
410 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
411 pnntsd->sacloffset = 0;
412 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
413 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
414
415 /* copy owner sid */
416 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
417 le32_to_cpu(pntsd->osidoffset));
418 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400419 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000420
421 /* copy group sid */
422 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
423 le32_to_cpu(pntsd->gsidoffset));
424 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
425 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400426 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000427
428 return;
429}
430
431
Steve French630f3f0c2007-10-25 21:17:17 +0000432/*
433 change posix mode to reflect permissions
434 pmode is the existing mode (we only want to overwrite part of this
435 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
436*/
Al Viro9b5e6852007-12-05 08:24:38 +0000437static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000438 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000439{
Al Viro9b5e6852007-12-05 08:24:38 +0000440 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000441 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000442 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000443 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000444 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000445 for the operation you are trying to perform for your user */
446
447 /* For deny ACEs we change the mask so that subsequent allow access
448 control entries do not turn on the bits we are denying */
449 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000450 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000451 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000452
Al Viro9b5e6852007-12-05 08:24:38 +0000453 if ((flags & GENERIC_WRITE) ||
454 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000455 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000456 if ((flags & GENERIC_READ) ||
457 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000458 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000459 if ((flags & GENERIC_EXECUTE) ||
460 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000461 *pbits_to_set &= ~S_IXUGO;
462 return;
463 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500464 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000465 return;
466 }
467 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000468
Al Viro9b5e6852007-12-05 08:24:38 +0000469 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000470 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesf96637b2013-05-04 22:12:25 -0500471 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000472 return;
473 }
Al Viro9b5e6852007-12-05 08:24:38 +0000474 if ((flags & GENERIC_WRITE) ||
475 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000476 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000477 if ((flags & GENERIC_READ) ||
478 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000479 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000480 if ((flags & GENERIC_EXECUTE) ||
481 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000482 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000483
Joe Perchesf96637b2013-05-04 22:12:25 -0500484 cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000485 return;
486}
487
Steve Frenchce06c9f2007-11-08 21:12:01 +0000488/*
489 Generate access flags to reflect permissions mode is the existing mode.
490 This function is called for every ACE in the DACL whose SID matches
491 with either owner or group or everyone.
492*/
493
494static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
495 __u32 *pace_flags)
496{
497 /* reset access mask */
498 *pace_flags = 0x0;
499
500 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
501 mode &= bits_to_use;
502
503 /* check for R/W/X UGO since we do not know whose flags
504 is this but we have cleared all the bits sans RWX for
505 either user or group or other as per bits_to_use */
506 if (mode & S_IRUGO)
507 *pace_flags |= SET_FILE_READ_RIGHTS;
508 if (mode & S_IWUGO)
509 *pace_flags |= SET_FILE_WRITE_RIGHTS;
510 if (mode & S_IXUGO)
511 *pace_flags |= SET_FILE_EXEC_RIGHTS;
512
Joe Perchesf96637b2013-05-04 22:12:25 -0500513 cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
514 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 Perchesf96637b2013-05-04 22:12:25 -0500554 cifs_dbg(VFS, "ACE too small %d\n", 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 Perchesf96637b2013-05-04 22:12:25 -0500559 cifs_dbg(VFS, "ACL too small to parse ACE\n");
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 Perchesf96637b2013-05-04 22:12:25 -0500566 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
567 pace->sid.revision, pace->sid.num_subauth, pace->type,
568 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000569 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500570 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
571 i, 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 Perchesf96637b2013-05-04 22:12:25 -0500604 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000605 return;
606 }
607
Joe Perchesf96637b2013-05-04 22:12:25 -0500608 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
609 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
610 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);
Joe Perchesf96637b2013-05-04 22:12:25 -0500630 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300631 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000632
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000633 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000634 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000635#ifdef CONFIG_CIFS_DEBUG2
636 dump_ace(ppace[i], end_of_acl);
637#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500638 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000639 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000640 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400641 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000642 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500643 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000644 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000645 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400646 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000647 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500648 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000649 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000650 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400651 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000652 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500653 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600654 access_flags_to_mode(ppace[i]->access_req,
655 ppace[i]->type,
656 &fattr->cf_mode,
657 &other_mask);
658
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000659
Steve French44093ca2007-10-23 21:22:55 +0000660/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000661 (void *)ppace[i],
662 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000663
Steve French44093ca2007-10-23 21:22:55 +0000664 acl_base = (char *)ppace[i];
665 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000666 }
667
668 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000669 }
670
671 return;
672}
673
Steve Frenchbcb02032007-09-25 16:17:24 +0000674
Steve French97837582007-12-31 07:47:21 +0000675static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
676 struct cifs_sid *pgrpsid, __u64 nmode)
677{
Al Viro2b210ad2008-03-29 03:09:18 +0000678 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000679 struct cifs_acl *pnndacl;
680
681 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
682
683 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
684 pownersid, nmode, S_IRWXU);
685 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
686 pgrpsid, nmode, S_IRWXG);
687 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
688 &sid_everyone, nmode, S_IRWXO);
689
690 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000691 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000692
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000693 return 0;
Steve French97837582007-12-31 07:47:21 +0000694}
695
696
Steve Frenchbcb02032007-09-25 16:17:24 +0000697static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
698{
699 /* BB need to add parm so we can store the SID BB */
700
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000701 /* validate that we do not go past end of ACL - sid must be at least 8
702 bytes long (assuming no sub-auths - e.g. the null SID */
703 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500704 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000705 return -EINVAL;
706 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000707
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000708#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500709 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000710 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500711 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
712 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000713
Steve Frenchaf6f4612007-10-16 18:40:37 +0000714 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500715 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
716 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000717 }
718
Steve Frenchd12fd122007-10-03 19:43:19 +0000719 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000720 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -0500721 cifs_dbg(FYI, "RID 0x%x\n",
722 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000723 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500724#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000725
Steve Frenchbcb02032007-09-25 16:17:24 +0000726 return 0;
727}
728
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000729
Steve Frenchbcb02032007-09-25 16:17:24 +0000730/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500731static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
732 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000733{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500734 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000735 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
736 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000737 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000738 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000739
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400740 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000741 return -EIO;
742
Steve Frenchbcb02032007-09-25 16:17:24 +0000743 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000744 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000745 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000746 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000747 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000748 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -0500749 cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000750 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
751 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000752 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000753/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000754 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500755 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500756 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000757 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500758 }
759 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
760 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500761 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
762 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500763 return rc;
764 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000765
766 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500767 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500768 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
769 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000770 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500771 }
772 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
773 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500774 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
775 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500776 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 Perchesf96637b2013-05-04 22:12:25 -0500783 cifs_dbg(FYI, "no ACL\n"); /* 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) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500833 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
834 __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) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500853 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
854 __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
Steve French42eacf92014-02-10 14:08:16 -0600867struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
868 const struct cifs_fid *cifsfid, 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();
Steve French42eacf92014-02-10 14:08:16 -0600879 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
880 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400881 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000882
Jeff Layton7ffec372010-09-29 19:51:11 -0400883 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000884
Joe Perchesf96637b2013-05-04 22:12:25 -0500885 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600886 if (rc)
887 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400888 return pntsd;
889}
890
891static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
892 const char *path, u32 *pacllen)
893{
894 struct cifs_ntsd *pntsd = NULL;
895 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400896 unsigned int xid;
897 int rc, create_options = 0;
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);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400900 struct cifs_fid fid;
901 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400902
Jeff Layton7ffec372010-09-29 19:51:11 -0400903 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600904 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400905
906 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400907 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400908
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500909 if (backup_cred(cifs_sb))
910 create_options |= CREATE_OPEN_BACKUP_INTENT;
911
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400912 oparms.tcon = tcon;
913 oparms.cifs_sb = cifs_sb;
914 oparms.desired_access = READ_CONTROL;
915 oparms.create_options = create_options;
916 oparms.disposition = FILE_OPEN;
917 oparms.path = path;
918 oparms.fid = &fid;
919 oparms.reconnect = false;
920
921 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600922 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400923 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
924 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000925 }
926
Jeff Layton7ffec372010-09-29 19:51:11 -0400927 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400928 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600929
Joe Perchesf96637b2013-05-04 22:12:25 -0500930 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600931 if (rc)
932 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000933 return pntsd;
934}
935
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400936/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600937struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400938 struct inode *inode, const char *path,
939 u32 *pacllen)
940{
941 struct cifs_ntsd *pntsd = NULL;
942 struct cifsFileInfo *open_file = NULL;
943
944 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400945 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400946 if (!open_file)
947 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
948
Steve French42eacf92014-02-10 14:08:16 -0600949 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400950 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400951 return pntsd;
952}
953
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500954 /* Set an ACL on the server */
955int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
956 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400957{
958 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400959 unsigned int xid;
960 int rc, access_flags, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +0000961 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500962 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400963 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400964 struct cifs_fid fid;
965 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +0000966
Jeff Layton7ffec372010-09-29 19:51:11 -0400967 if (IS_ERR(tlink))
968 return PTR_ERR(tlink);
969
970 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400971 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000972
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500973 if (backup_cred(cifs_sb))
974 create_options |= CREATE_OPEN_BACKUP_INTENT;
975
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500976 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
977 access_flags = WRITE_OWNER;
978 else
979 access_flags = WRITE_DAC;
980
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400981 oparms.tcon = tcon;
982 oparms.cifs_sb = cifs_sb;
983 oparms.desired_access = access_flags;
984 oparms.create_options = create_options;
985 oparms.disposition = FILE_OPEN;
986 oparms.path = path;
987 oparms.fid = &fid;
988 oparms.reconnect = false;
989
990 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400991 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500992 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400993 goto out;
Steve French97837582007-12-31 07:47:21 +0000994 }
995
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400996 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -0500997 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +0000998
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400999 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001000out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001001 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001002 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001003 return rc;
1004}
Steve French97837582007-12-31 07:47:21 +00001005
Steve French7505e052007-11-01 18:03:01 +00001006/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001007int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001008cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve French42eacf92014-02-10 14:08:16 -06001009 struct inode *inode, const char *path,
1010 const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001011{
1012 struct cifs_ntsd *pntsd = NULL;
1013 u32 acllen = 0;
1014 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001015 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1016 struct cifs_tcon *tcon;
Steve French7505e052007-11-01 18:03:01 +00001017
Joe Perchesf96637b2013-05-04 22:12:25 -05001018 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001019
Steve French42eacf92014-02-10 14:08:16 -06001020 if (IS_ERR(tlink))
1021 return PTR_ERR(tlink);
1022 tcon = tlink_tcon(tlink);
Steve French7505e052007-11-01 18:03:01 +00001023
Steve French42eacf92014-02-10 14:08:16 -06001024 if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
1025 pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
1026 &acllen);
1027 else if (tcon->ses->server->ops->get_acl)
1028 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1029 &acllen);
1030 else {
1031 cifs_put_tlink(tlink);
1032 return -EOPNOTSUPP;
1033 }
Steve French7505e052007-11-01 18:03:01 +00001034 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001035 if (IS_ERR(pntsd)) {
1036 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001037 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001038 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001039 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001040 kfree(pntsd);
1041 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001042 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001043 }
Steve French7505e052007-11-01 18:03:01 +00001044
Steve French42eacf92014-02-10 14:08:16 -06001045 cifs_put_tlink(tlink);
1046
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001047 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001048}
Steve French953f8682007-10-31 04:54:42 +00001049
Steve French7505e052007-11-01 18:03:01 +00001050/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001051int
1052id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001053 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001054{
1055 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001056 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001057 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001058 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1059 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001060 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1061 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1062 struct cifs_tcon *tcon;
1063
1064 if (IS_ERR(tlink))
1065 return PTR_ERR(tlink);
1066 tcon = tlink_tcon(tlink);
Steve French953f8682007-10-31 04:54:42 +00001067
Joe Perchesf96637b2013-05-04 22:12:25 -05001068 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001069
1070 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001071
1072 if (tcon->ses->server->ops->get_acl == NULL) {
1073 cifs_put_tlink(tlink);
1074 return -EOPNOTSUPP;
1075 }
1076
1077 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1078 &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001079 if (IS_ERR(pntsd)) {
1080 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001081 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001082 cifs_put_tlink(tlink);
1083 return rc;
Steve French97837582007-12-31 07:47:21 +00001084 }
1085
Jeff Laytonc78cd832012-11-25 08:00:35 -05001086 /*
1087 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1088 * as chmod disables ACEs and set the security descriptor. Allocate
1089 * memory for the smb header, set security descriptor request security
1090 * descriptor parameters, and secuirty descriptor itself
1091 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001092 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001093 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1094 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001095 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001096 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001097 return -ENOMEM;
1098 }
1099
1100 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1101 &aclflag);
1102
Joe Perchesf96637b2013-05-04 22:12:25 -05001103 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001104
Steve French83e3bc22014-02-02 23:31:47 -06001105 if (tcon->ses->server->ops->set_acl == NULL)
1106 rc = -EOPNOTSUPP;
1107
Jeff Laytonc78cd832012-11-25 08:00:35 -05001108 if (!rc) {
1109 /* Set the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001110 rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
1111 path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001112 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001113 }
Steve French83e3bc22014-02-02 23:31:47 -06001114 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001115
1116 kfree(pnntsd);
1117 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001118 return rc;
Steve French953f8682007-10-31 04:54:42 +00001119}