blob: 7ff866dbb89eb7b31033ce1e99f7b56f664fbdf6 [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,
87 .match = user_match,
88};
89
Jeff Laytonfaa65f02012-12-03 06:05:29 -050090static char *
91sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050092{
Jeff Laytonfaa65f02012-12-03 06:05:29 -050093 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -050094 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050095 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -050096 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050097
98 /* 3 bytes for prefix */
99 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
100 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
101 GFP_KERNEL);
102 if (!sidstr)
103 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500104
105 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500106 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
107 sidptr->revision);
108 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500109
Jeff Layton193cdd82012-12-10 06:10:44 -0500110 /* The authority field is a single 48-bit number */
111 id_auth_val = (unsigned long long)sidptr->authority[5];
112 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
113 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
114 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
115 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
116 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
117
118 /*
119 * MS-DTYP states that if the authority is >= 2^32, then it should be
120 * expressed as a hex value.
121 */
122 if (id_auth_val <= UINT_MAX)
123 len = sprintf(strptr, "-%llu", id_auth_val);
124 else
125 len = sprintf(strptr, "-0x%llx", id_auth_val);
126
127 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500128
129 for (i = 0; i < sidptr->num_subauth; ++i) {
130 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500131 len = sprintf(strptr, "-%u", saval);
132 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500133 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500134
135 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500136}
137
Jeff Layton436bb432012-11-25 08:00:36 -0500138/*
139 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
140 * the same returns zero, if they do not match returns non-zero.
141 */
142static int
143compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
144{
145 int i;
146 int num_subauth, num_sat, num_saw;
147
148 if ((!ctsid) || (!cwsid))
149 return 1;
150
151 /* compare the revision */
152 if (ctsid->revision != cwsid->revision) {
153 if (ctsid->revision > cwsid->revision)
154 return 1;
155 else
156 return -1;
157 }
158
159 /* compare all of the six auth values */
160 for (i = 0; i < NUM_AUTHS; ++i) {
161 if (ctsid->authority[i] != cwsid->authority[i]) {
162 if (ctsid->authority[i] > cwsid->authority[i])
163 return 1;
164 else
165 return -1;
166 }
167 }
168
169 /* compare all of the subauth values if any */
170 num_sat = ctsid->num_subauth;
171 num_saw = cwsid->num_subauth;
172 num_subauth = num_sat < num_saw ? num_sat : num_saw;
173 if (num_subauth) {
174 for (i = 0; i < num_subauth; ++i) {
175 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
176 if (le32_to_cpu(ctsid->sub_auth[i]) >
177 le32_to_cpu(cwsid->sub_auth[i]))
178 return 1;
179 else
180 return -1;
181 }
182 }
183 }
184
185 return 0; /* sids compare/match */
186}
187
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500188static void
Jeff Layton36960e42012-11-03 09:37:28 -0400189cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
190{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500191 int i;
192
193 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500194 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500195 for (i = 0; i < NUM_AUTHS; ++i)
196 dst->authority[i] = src->authority[i];
197 for (i = 0; i < dst->num_subauth; ++i)
198 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400199}
200
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500201static int
202id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500203{
204 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500205 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500206 struct cifs_sid *ksid;
207 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500208 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500209 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500210
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500211 rc = snprintf(desc, sizeof(desc), "%ci:%u",
212 sidtype == SIDOWNER ? 'o' : 'g', cid);
213 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500214 return -EINVAL;
215
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500216 rc = 0;
217 saved_cred = override_creds(root_cred);
218 sidkey = request_key(&cifs_idmap_key_type, desc, "");
219 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500220 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500221 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
222 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500223 goto out_revert_creds;
224 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
225 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500226 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
227 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500228 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500229 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500230
Jeff Layton1f630682012-12-03 06:05:31 -0500231 /*
232 * A sid is usually too large to be embedded in payload.value, but if
233 * there are no subauthorities and the host has 8-byte pointers, then
234 * it could be.
235 */
236 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
237 (struct cifs_sid *)&sidkey->payload.value :
238 (struct cifs_sid *)sidkey->payload.data;
239
Jeff Layton2ae03022012-12-03 06:05:30 -0500240 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
241 if (ksid_size > sidkey->datalen) {
242 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500243 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
244 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500245 goto invalidate_key;
246 }
Jeff Layton1f630682012-12-03 06:05:31 -0500247
Jeff Layton2ae03022012-12-03 06:05:30 -0500248 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500249out_key_put:
250 key_put(sidkey);
251out_revert_creds:
252 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500253 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500254
255invalidate_key:
256 key_invalidate(sidkey);
257 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500258}
259
260static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500261sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
262 struct cifs_fattr *fattr, uint sidtype)
263{
264 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500265 struct key *sidkey;
266 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500267 const struct cred *saved_cred;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800268 kuid_t fuid = cifs_sb->mnt_uid;
269 kgid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500270
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500271 /*
272 * If we have too many subauthorities, then something is really wrong.
273 * Just return an error.
274 */
275 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500276 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
277 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500278 return -EIO;
279 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500280
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500281 sidstr = sid_to_key_str(psid, sidtype);
282 if (!sidstr)
283 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500284
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500285 saved_cred = override_creds(root_cred);
286 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
287 if (IS_ERR(sidkey)) {
288 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500289 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
290 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500291 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500292 }
293
294 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500295 * FIXME: Here we assume that uid_t and gid_t are same size. It's
296 * probably a safe assumption but might be better to check based on
297 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500298 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800299 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500300 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500301 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500302 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
303 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500304 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500305 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500306 }
307
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800308 if (sidtype == SIDOWNER) {
309 kuid_t uid;
310 uid_t id;
311 memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
312 uid = make_kuid(&init_user_ns, id);
313 if (uid_valid(uid))
314 fuid = uid;
315 } else {
316 kgid_t gid;
317 gid_t id;
318 memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
319 gid = make_kgid(&init_user_ns, id);
320 if (gid_valid(gid))
321 fgid = gid;
322 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500323
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500324out_key_put:
325 key_put(sidkey);
326out_revert_creds:
327 revert_creds(saved_cred);
328 kfree(sidstr);
329
330 /*
331 * Note that we return 0 here unconditionally. If the mapping
332 * fails then we just fall back to using the mnt_uid/mnt_gid.
333 */
334 if (sidtype == SIDOWNER)
335 fattr->cf_uid = fuid;
336 else
337 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500338 return 0;
339}
340
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500341int
342init_cifs_idmap(void)
343{
344 struct cred *cred;
345 struct key *keyring;
346 int ret;
347
Joe Perchesf96637b2013-05-04 22:12:25 -0500348 cifs_dbg(FYI, "Registering the %s key type\n",
349 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
Joe Perchesf96637b2013-05-04 22:12:25 -0500382 cifs_dbg(FYI, "cifs idmap keyring: %d\n", 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);
Joe Perchesf96637b2013-05-04 22:12:25 -0500398 cifs_dbg(FYI, "Unregistered %s key type\n", 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 Perchesf96637b2013-05-04 22:12:25 -0500465 cifs_dbg(VFS, "unknown access control type %d\n", 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 Perchesf96637b2013-05-04 22:12:25 -0500472 cifs_dbg(NOISY, "all perms\n");
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 Perchesf96637b2013-05-04 22:12:25 -0500485 cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", 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 Perchesf96637b2013-05-04 22:12:25 -0500514 cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
515 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000516 return;
517}
518
Al Viro2b210ad2008-03-29 03:09:18 +0000519static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000520 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
521{
522 int i;
523 __u16 size = 0;
524 __u32 access_req = 0;
525
526 pntace->type = ACCESS_ALLOWED;
527 pntace->flags = 0x0;
528 mode_to_access_flags(nmode, bits, &access_req);
529 if (!access_req)
530 access_req = SET_MINIMUM_RIGHTS;
531 pntace->access_req = cpu_to_le32(access_req);
532
533 pntace->sid.revision = psid->revision;
534 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500535 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000536 pntace->sid.authority[i] = psid->authority[i];
537 for (i = 0; i < psid->num_subauth; i++)
538 pntace->sid.sub_auth[i] = psid->sub_auth[i];
539
540 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
541 pntace->size = cpu_to_le16(size);
542
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000543 return size;
Steve French97837582007-12-31 07:47:21 +0000544}
545
Steve French297647c2007-10-12 04:11:59 +0000546
Steve French953f8682007-10-31 04:54:42 +0000547#ifdef CONFIG_CIFS_DEBUG2
548static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000549{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000550 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000551
552 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000553
Steve French44093ca2007-10-23 21:22:55 +0000554 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500555 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000556 return;
557 }
558
559 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500560 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000561 return;
Steve French44093ca2007-10-23 21:22:55 +0000562 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000563
Steve French44093ca2007-10-23 21:22:55 +0000564 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000565 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000566 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500567 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
568 pace->sid.revision, pace->sid.num_subauth, pace->type,
569 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000570 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500571 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
572 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000573 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000574
Steve Frenchd12fd122007-10-03 19:43:19 +0000575 /* BB add length check to make sure that we do not have huge
576 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000577 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000578
Steve Frenchd12fd122007-10-03 19:43:19 +0000579 return;
580}
Steve French953f8682007-10-31 04:54:42 +0000581#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000582
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000583
Steve Frencha750e772007-10-17 22:50:39 +0000584static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000585 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400586 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000587{
588 int i;
589 int num_aces = 0;
590 int acl_size;
591 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000592 struct cifs_ace **ppace;
593
594 /* BB need to add parm so we can store the SID BB */
595
Steve French2b834572007-11-25 10:01:00 +0000596 if (!pdacl) {
597 /* no DACL in the security descriptor, set
598 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400599 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000600 return;
601 }
602
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000603 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000604 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500605 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000606 return;
607 }
608
Joe Perchesf96637b2013-05-04 22:12:25 -0500609 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
610 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
611 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000612
Steve French7505e052007-11-01 18:03:01 +0000613 /* reset rwx permissions for user/group/other.
614 Also, if num_aces is 0 i.e. DACL has no ACEs,
615 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400616 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000617
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000618 acl_base = (char *)pdacl;
619 acl_size = sizeof(struct cifs_acl);
620
Steve Frenchadbc0352007-10-17 02:12:46 +0000621 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500622 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000623 umode_t user_mask = S_IRWXU;
624 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600625 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000626
Dan Carpenter72501702012-01-11 10:46:27 +0300627 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
628 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000629 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
630 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500631 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300632 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000633
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000634 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000635 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000636#ifdef CONFIG_CIFS_DEBUG2
637 dump_ace(ppace[i], end_of_acl);
638#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500639 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000640 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000641 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400642 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000643 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500644 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000645 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000646 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400647 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000648 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500649 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000650 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000651 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400652 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000653 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500654 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600655 access_flags_to_mode(ppace[i]->access_req,
656 ppace[i]->type,
657 &fattr->cf_mode,
658 &other_mask);
659
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000660
Steve French44093ca2007-10-23 21:22:55 +0000661/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000662 (void *)ppace[i],
663 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000664
Steve French44093ca2007-10-23 21:22:55 +0000665 acl_base = (char *)ppace[i];
666 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000667 }
668
669 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000670 }
671
672 return;
673}
674
Steve Frenchbcb02032007-09-25 16:17:24 +0000675
Steve French97837582007-12-31 07:47:21 +0000676static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
677 struct cifs_sid *pgrpsid, __u64 nmode)
678{
Al Viro2b210ad2008-03-29 03:09:18 +0000679 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000680 struct cifs_acl *pnndacl;
681
682 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
683
684 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
685 pownersid, nmode, S_IRWXU);
686 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
687 pgrpsid, nmode, S_IRWXG);
688 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
689 &sid_everyone, nmode, S_IRWXO);
690
691 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000692 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000693
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000694 return 0;
Steve French97837582007-12-31 07:47:21 +0000695}
696
697
Steve Frenchbcb02032007-09-25 16:17:24 +0000698static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
699{
700 /* BB need to add parm so we can store the SID BB */
701
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000702 /* validate that we do not go past end of ACL - sid must be at least 8
703 bytes long (assuming no sub-auths - e.g. the null SID */
704 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500705 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000706 return -EINVAL;
707 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000708
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000709#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500710 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000711 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500712 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
713 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000714
Steve Frenchaf6f4612007-10-16 18:40:37 +0000715 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500716 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
717 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000718 }
719
Steve Frenchd12fd122007-10-03 19:43:19 +0000720 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000721 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -0500722 cifs_dbg(FYI, "RID 0x%x\n",
723 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000724 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500725#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000726
Steve Frenchbcb02032007-09-25 16:17:24 +0000727 return 0;
728}
729
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000730
Steve Frenchbcb02032007-09-25 16:17:24 +0000731/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500732static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
733 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000734{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500735 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000736 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
737 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000738 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000739 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000740
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400741 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000742 return -EIO;
743
Steve Frenchbcb02032007-09-25 16:17:24 +0000744 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000745 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000746 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000747 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000748 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000749 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -0500750 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 +0000751 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
752 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000754/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000755 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500756 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500757 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000758 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500759 }
760 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
761 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500762 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
763 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500764 return rc;
765 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000766
767 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500768 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500769 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
770 __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) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500775 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
776 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500777 return rc;
778 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000779
Steve French7505e052007-11-01 18:03:01 +0000780 if (dacloffset)
781 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400782 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000783 else
Joe Perchesf96637b2013-05-04 22:12:25 -0500784 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000785
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500786 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000787}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000788
Steve French97837582007-12-31 07:47:21 +0000789/* Convert permission bits from mode to equivalent CIFS ACL */
790static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800791 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000792{
793 int rc = 0;
794 __u32 dacloffset;
795 __u32 ndacloffset;
796 __u32 sidsoffset;
797 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500798 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000799 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
800 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
801
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500802 if (nmode != NO_CHANGE_64) { /* chmod */
803 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000804 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500805 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000806 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500807 dacloffset = le32_to_cpu(pntsd->dacloffset);
808 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
809 ndacloffset = sizeof(struct cifs_ntsd);
810 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
811 ndacl_ptr->revision = dacl_ptr->revision;
812 ndacl_ptr->size = 0;
813 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000814
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500815 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
816 nmode);
817 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
818 /* copy sec desc control portion & owner and group sids */
819 copy_sec_desc(pntsd, pnntsd, sidsoffset);
820 *aclflag = CIFS_ACL_DACL;
821 } else {
822 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800823 if (uid_valid(uid)) { /* chown */
824 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500825 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
826 le32_to_cpu(pnntsd->osidoffset));
827 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
828 GFP_KERNEL);
829 if (!nowner_sid_ptr)
830 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800831 id = from_kuid(&init_user_ns, uid);
832 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500833 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500834 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
835 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500836 kfree(nowner_sid_ptr);
837 return rc;
838 }
Jeff Layton36960e42012-11-03 09:37:28 -0400839 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500840 kfree(nowner_sid_ptr);
841 *aclflag = CIFS_ACL_OWNER;
842 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800843 if (gid_valid(gid)) { /* chgrp */
844 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500845 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
846 le32_to_cpu(pnntsd->gsidoffset));
847 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
848 GFP_KERNEL);
849 if (!ngroup_sid_ptr)
850 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800851 id = from_kgid(&init_user_ns, gid);
852 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500853 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500854 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
855 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500856 kfree(ngroup_sid_ptr);
857 return rc;
858 }
Jeff Layton36960e42012-11-03 09:37:28 -0400859 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500860 kfree(ngroup_sid_ptr);
861 *aclflag = CIFS_ACL_GROUP;
862 }
863 }
Steve French97837582007-12-31 07:47:21 +0000864
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000865 return rc;
Steve French97837582007-12-31 07:47:21 +0000866}
867
Steve French42eacf92014-02-10 14:08:16 -0600868struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
869 const struct cifs_fid *cifsfid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000870{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000871 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400872 unsigned int xid;
873 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400874 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
875
876 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600877 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000878
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400879 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -0600880 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
881 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400882 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000883
Jeff Layton7ffec372010-09-29 19:51:11 -0400884 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000885
Joe Perchesf96637b2013-05-04 22:12:25 -0500886 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600887 if (rc)
888 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400889 return pntsd;
890}
891
892static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
893 const char *path, u32 *pacllen)
894{
895 struct cifs_ntsd *pntsd = NULL;
896 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400897 unsigned int xid;
898 int rc, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +0000899 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400900 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400901 struct cifs_fid fid;
902 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400903
Jeff Layton7ffec372010-09-29 19:51:11 -0400904 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600905 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400906
907 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400908 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400909
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500910 if (backup_cred(cifs_sb))
911 create_options |= CREATE_OPEN_BACKUP_INTENT;
912
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400913 oparms.tcon = tcon;
914 oparms.cifs_sb = cifs_sb;
915 oparms.desired_access = READ_CONTROL;
916 oparms.create_options = create_options;
917 oparms.disposition = FILE_OPEN;
918 oparms.path = path;
919 oparms.fid = &fid;
920 oparms.reconnect = false;
921
922 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600923 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400924 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
925 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000926 }
927
Jeff Layton7ffec372010-09-29 19:51:11 -0400928 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400929 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600930
Joe Perchesf96637b2013-05-04 22:12:25 -0500931 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600932 if (rc)
933 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000934 return pntsd;
935}
936
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400937/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600938struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400939 struct inode *inode, const char *path,
940 u32 *pacllen)
941{
942 struct cifs_ntsd *pntsd = NULL;
943 struct cifsFileInfo *open_file = NULL;
944
945 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400946 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400947 if (!open_file)
948 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
949
Steve French42eacf92014-02-10 14:08:16 -0600950 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400951 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400952 return pntsd;
953}
954
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500955 /* Set an ACL on the server */
956int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
957 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400958{
959 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400960 unsigned int xid;
961 int rc, access_flags, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +0000962 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500963 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400964 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400965 struct cifs_fid fid;
966 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +0000967
Jeff Layton7ffec372010-09-29 19:51:11 -0400968 if (IS_ERR(tlink))
969 return PTR_ERR(tlink);
970
971 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400972 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000973
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500974 if (backup_cred(cifs_sb))
975 create_options |= CREATE_OPEN_BACKUP_INTENT;
976
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500977 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
978 access_flags = WRITE_OWNER;
979 else
980 access_flags = WRITE_DAC;
981
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400982 oparms.tcon = tcon;
983 oparms.cifs_sb = cifs_sb;
984 oparms.desired_access = access_flags;
985 oparms.create_options = create_options;
986 oparms.disposition = FILE_OPEN;
987 oparms.path = path;
988 oparms.fid = &fid;
989 oparms.reconnect = false;
990
991 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400992 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500993 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400994 goto out;
Steve French97837582007-12-31 07:47:21 +0000995 }
996
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400997 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -0500998 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +0000999
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +04001000 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001001out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001002 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001003 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001004 return rc;
1005}
Steve French97837582007-12-31 07:47:21 +00001006
Steve French7505e052007-11-01 18:03:01 +00001007/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001008int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001009cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve French42eacf92014-02-10 14:08:16 -06001010 struct inode *inode, const char *path,
1011 const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001012{
1013 struct cifs_ntsd *pntsd = NULL;
1014 u32 acllen = 0;
1015 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001016 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1017 struct cifs_tcon *tcon;
Steve French7505e052007-11-01 18:03:01 +00001018
Joe Perchesf96637b2013-05-04 22:12:25 -05001019 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001020
Steve French42eacf92014-02-10 14:08:16 -06001021 if (IS_ERR(tlink))
1022 return PTR_ERR(tlink);
1023 tcon = tlink_tcon(tlink);
Steve French7505e052007-11-01 18:03:01 +00001024
Steve French42eacf92014-02-10 14:08:16 -06001025 if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
1026 pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
1027 &acllen);
1028 else if (tcon->ses->server->ops->get_acl)
1029 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1030 &acllen);
1031 else {
1032 cifs_put_tlink(tlink);
1033 return -EOPNOTSUPP;
1034 }
Steve French7505e052007-11-01 18:03:01 +00001035 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001036 if (IS_ERR(pntsd)) {
1037 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001038 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001039 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001040 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001041 kfree(pntsd);
1042 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001043 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001044 }
Steve French7505e052007-11-01 18:03:01 +00001045
Steve French42eacf92014-02-10 14:08:16 -06001046 cifs_put_tlink(tlink);
1047
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001048 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001049}
Steve French953f8682007-10-31 04:54:42 +00001050
Steve French7505e052007-11-01 18:03:01 +00001051/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001052int
1053id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001054 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001055{
1056 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001057 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001058 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001059 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1060 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001061 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1062 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1063 struct cifs_tcon *tcon;
1064
1065 if (IS_ERR(tlink))
1066 return PTR_ERR(tlink);
1067 tcon = tlink_tcon(tlink);
Steve French953f8682007-10-31 04:54:42 +00001068
Joe Perchesf96637b2013-05-04 22:12:25 -05001069 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001070
1071 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001072
1073 if (tcon->ses->server->ops->get_acl == NULL) {
1074 cifs_put_tlink(tlink);
1075 return -EOPNOTSUPP;
1076 }
1077
1078 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1079 &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001080 if (IS_ERR(pntsd)) {
1081 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001082 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001083 cifs_put_tlink(tlink);
1084 return rc;
Steve French97837582007-12-31 07:47:21 +00001085 }
1086
Jeff Laytonc78cd832012-11-25 08:00:35 -05001087 /*
1088 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1089 * as chmod disables ACEs and set the security descriptor. Allocate
1090 * memory for the smb header, set security descriptor request security
1091 * descriptor parameters, and secuirty descriptor itself
1092 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001093 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001094 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1095 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001096 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001097 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001098 return -ENOMEM;
1099 }
1100
1101 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1102 &aclflag);
1103
Joe Perchesf96637b2013-05-04 22:12:25 -05001104 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001105
Steve French83e3bc22014-02-02 23:31:47 -06001106 if (tcon->ses->server->ops->set_acl == NULL)
1107 rc = -EOPNOTSUPP;
1108
Jeff Laytonc78cd832012-11-25 08:00:35 -05001109 if (!rc) {
1110 /* Set the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001111 rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
1112 path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001113 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001114 }
Steve French83e3bc22014-02-02 23:31:47 -06001115 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001116
1117 kfree(pnntsd);
1118 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001119 return rc;
Steve French953f8682007-10-31 04:54:42 +00001120}