blob: 71e8a56e9479567e9f5ad0fb201a2ea3e91d6e99 [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 = {
Fabian Frederickbc09d142014-12-10 15:41:15 -080041 1, 1, {0, 0, 0, 0, 0, 5}, {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)) {
David Howells146aa8b2015-10-21 14:04:48 +010061 key->payload.data[0] = NULL;
62 memcpy(&key->payload, prep->data, prep->datalen);
63 } else {
64 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
65 if (!payload)
66 return -ENOMEM;
67 key->payload.data[0] = payload;
Jeff Layton41a9f1f2012-12-03 06:05:29 -050068 }
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050069
David Howellscf7f6012012-09-13 13:06:29 +010070 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050071 return 0;
72}
73
74static inline void
75cifs_idmap_key_destroy(struct key *key)
76{
Jeff Layton1f630682012-12-03 06:05:31 -050077 if (key->datalen > sizeof(key->payload))
David Howells146aa8b2015-10-21 14:04:48 +010078 kfree(key->payload.data[0]);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050079}
80
Jeff Laytonb1a6dc22012-11-25 08:00:38 -050081static struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -050082 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050083 .instantiate = cifs_idmap_key_instantiate,
84 .destroy = cifs_idmap_key_destroy,
85 .describe = user_describe,
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050086};
87
Jeff Laytonfaa65f02012-12-03 06:05:29 -050088static char *
89sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050090{
Jeff Laytonfaa65f02012-12-03 06:05:29 -050091 int i, len;
Jeff Laytonee13b2b2012-11-25 08:00:38 -050092 unsigned int saval;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050093 char *sidstr, *strptr;
Jeff Layton193cdd82012-12-10 06:10:44 -050094 unsigned long long id_auth_val;
Jeff Laytonfaa65f02012-12-03 06:05:29 -050095
96 /* 3 bytes for prefix */
97 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
98 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
99 GFP_KERNEL);
100 if (!sidstr)
101 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500102
103 strptr = sidstr;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500104 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
105 sidptr->revision);
106 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500107
Jeff Layton193cdd82012-12-10 06:10:44 -0500108 /* The authority field is a single 48-bit number */
109 id_auth_val = (unsigned long long)sidptr->authority[5];
110 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
111 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
112 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
113 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
114 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
115
116 /*
117 * MS-DTYP states that if the authority is >= 2^32, then it should be
118 * expressed as a hex value.
119 */
120 if (id_auth_val <= UINT_MAX)
121 len = sprintf(strptr, "-%llu", id_auth_val);
122 else
123 len = sprintf(strptr, "-0x%llx", id_auth_val);
124
125 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500126
127 for (i = 0; i < sidptr->num_subauth; ++i) {
128 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500129 len = sprintf(strptr, "-%u", saval);
130 strptr += len;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500131 }
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500132
133 return sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500134}
135
Jeff Layton436bb432012-11-25 08:00:36 -0500136/*
137 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
138 * the same returns zero, if they do not match returns non-zero.
139 */
140static int
141compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
142{
143 int i;
144 int num_subauth, num_sat, num_saw;
145
146 if ((!ctsid) || (!cwsid))
147 return 1;
148
149 /* compare the revision */
150 if (ctsid->revision != cwsid->revision) {
151 if (ctsid->revision > cwsid->revision)
152 return 1;
153 else
154 return -1;
155 }
156
157 /* compare all of the six auth values */
158 for (i = 0; i < NUM_AUTHS; ++i) {
159 if (ctsid->authority[i] != cwsid->authority[i]) {
160 if (ctsid->authority[i] > cwsid->authority[i])
161 return 1;
162 else
163 return -1;
164 }
165 }
166
167 /* compare all of the subauth values if any */
168 num_sat = ctsid->num_subauth;
169 num_saw = cwsid->num_subauth;
170 num_subauth = num_sat < num_saw ? num_sat : num_saw;
171 if (num_subauth) {
172 for (i = 0; i < num_subauth; ++i) {
173 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
174 if (le32_to_cpu(ctsid->sub_auth[i]) >
175 le32_to_cpu(cwsid->sub_auth[i]))
176 return 1;
177 else
178 return -1;
179 }
180 }
181 }
182
183 return 0; /* sids compare/match */
184}
185
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500186static void
Jeff Layton36960e42012-11-03 09:37:28 -0400187cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
188{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500189 int i;
190
191 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500192 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500193 for (i = 0; i < NUM_AUTHS; ++i)
194 dst->authority[i] = src->authority[i];
195 for (i = 0; i < dst->num_subauth; ++i)
196 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400197}
198
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500199static int
200id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500201{
202 int rc;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500203 struct key *sidkey;
Jeff Layton2ae03022012-12-03 06:05:30 -0500204 struct cifs_sid *ksid;
205 unsigned int ksid_size;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500206 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500207 const struct cred *saved_cred;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500208
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500209 rc = snprintf(desc, sizeof(desc), "%ci:%u",
210 sidtype == SIDOWNER ? 'o' : 'g', cid);
211 if (rc >= sizeof(desc))
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500212 return -EINVAL;
213
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500214 rc = 0;
215 saved_cred = override_creds(root_cred);
216 sidkey = request_key(&cifs_idmap_key_type, desc, "");
217 if (IS_ERR(sidkey)) {
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500218 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500219 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
220 __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500221 goto out_revert_creds;
222 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
223 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500224 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
225 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500226 goto invalidate_key;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500227 }
Jeff Layton2ae03022012-12-03 06:05:30 -0500228
Jeff Layton1f630682012-12-03 06:05:31 -0500229 /*
230 * A sid is usually too large to be embedded in payload.value, but if
231 * there are no subauthorities and the host has 8-byte pointers, then
232 * it could be.
233 */
234 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
David Howells146aa8b2015-10-21 14:04:48 +0100235 (struct cifs_sid *)&sidkey->payload :
236 (struct cifs_sid *)sidkey->payload.data[0];
Jeff Layton1f630682012-12-03 06:05:31 -0500237
Jeff Layton2ae03022012-12-03 06:05:30 -0500238 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
239 if (ksid_size > sidkey->datalen) {
240 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500241 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
242 __func__, sidkey->datalen, ksid_size);
Jeff Layton2ae03022012-12-03 06:05:30 -0500243 goto invalidate_key;
244 }
Jeff Layton1f630682012-12-03 06:05:31 -0500245
Jeff Layton2ae03022012-12-03 06:05:30 -0500246 cifs_copy_sid(ssid, ksid);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500247out_key_put:
248 key_put(sidkey);
249out_revert_creds:
250 revert_creds(saved_cred);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500251 return rc;
Jeff Layton2ae03022012-12-03 06:05:30 -0500252
253invalidate_key:
254 key_invalidate(sidkey);
255 goto out_key_put;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500256}
257
258static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500259sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
260 struct cifs_fattr *fattr, uint sidtype)
261{
262 int rc;
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500263 struct key *sidkey;
264 char *sidstr;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500265 const struct cred *saved_cred;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800266 kuid_t fuid = cifs_sb->mnt_uid;
267 kgid_t fgid = cifs_sb->mnt_gid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500268
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500269 /*
270 * If we have too many subauthorities, then something is really wrong.
271 * Just return an error.
272 */
273 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500274 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
275 __func__, psid->num_subauth);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500276 return -EIO;
277 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500278
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500279 sidstr = sid_to_key_str(psid, sidtype);
280 if (!sidstr)
281 return -ENOMEM;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500282
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500283 saved_cred = override_creds(root_cred);
284 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
285 if (IS_ERR(sidkey)) {
286 rc = -EINVAL;
Joe Perchesf96637b2013-05-04 22:12:25 -0500287 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
288 __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500289 goto out_revert_creds;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500290 }
291
292 /*
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500293 * FIXME: Here we assume that uid_t and gid_t are same size. It's
294 * probably a safe assumption but might be better to check based on
295 * sidtype.
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500296 */
Eric W. Biederman355958f2013-02-06 00:10:23 -0800297 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
Jeff Layton41a9f1f2012-12-03 06:05:29 -0500298 if (sidkey->datalen != sizeof(uid_t)) {
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500299 rc = -EIO;
Joe Perchesf96637b2013-05-04 22:12:25 -0500300 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
301 __func__, sidkey->datalen);
Jeff Layton2ae03022012-12-03 06:05:30 -0500302 key_invalidate(sidkey);
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500303 goto out_key_put;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500304 }
305
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800306 if (sidtype == SIDOWNER) {
307 kuid_t uid;
308 uid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100309 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800310 uid = make_kuid(&init_user_ns, id);
311 if (uid_valid(uid))
312 fuid = uid;
313 } else {
314 kgid_t gid;
315 gid_t id;
David Howells146aa8b2015-10-21 14:04:48 +0100316 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800317 gid = make_kgid(&init_user_ns, id);
318 if (gid_valid(gid))
319 fgid = gid;
320 }
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500321
Jeff Laytonfaa65f02012-12-03 06:05:29 -0500322out_key_put:
323 key_put(sidkey);
324out_revert_creds:
325 revert_creds(saved_cred);
326 kfree(sidstr);
327
328 /*
329 * Note that we return 0 here unconditionally. If the mapping
330 * fails then we just fall back to using the mnt_uid/mnt_gid.
331 */
332 if (sidtype == SIDOWNER)
333 fattr->cf_uid = fuid;
334 else
335 fattr->cf_gid = fgid;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500336 return 0;
337}
338
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500339int
340init_cifs_idmap(void)
341{
342 struct cred *cred;
343 struct key *keyring;
344 int ret;
345
Joe Perchesf96637b2013-05-04 22:12:25 -0500346 cifs_dbg(FYI, "Registering the %s key type\n",
347 cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500348
349 /* create an override credential set with a special thread keyring in
350 * which requests are cached
351 *
352 * this is used to prevent malicious redirections from being installed
353 * with add_key().
354 */
355 cred = prepare_kernel_cred(NULL);
356 if (!cred)
357 return -ENOMEM;
358
Eric W. Biederman8e3028b2013-02-06 00:21:22 -0800359 keyring = keyring_alloc(".cifs_idmap",
360 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
David Howellsf8aa23a2012-10-02 19:24:56 +0100361 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
362 KEY_USR_VIEW | KEY_USR_READ,
David Howells5ac7eac2016-04-06 16:14:24 +0100363 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500364 if (IS_ERR(keyring)) {
365 ret = PTR_ERR(keyring);
366 goto failed_put_cred;
367 }
368
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500369 ret = register_key_type(&cifs_idmap_key_type);
370 if (ret < 0)
371 goto failed_put_key;
372
373 /* instruct request_key() to use this special keyring as a cache for
374 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000375 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500376 cred->thread_keyring = keyring;
377 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
378 root_cred = cred;
379
Joe Perchesf96637b2013-05-04 22:12:25 -0500380 cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500381 return 0;
382
383failed_put_key:
384 key_put(keyring);
385failed_put_cred:
386 put_cred(cred);
387 return ret;
388}
389
390void
391exit_cifs_idmap(void)
392{
393 key_revoke(root_cred->thread_keyring);
394 unregister_key_type(&cifs_idmap_key_type);
395 put_cred(root_cred);
Joe Perchesf96637b2013-05-04 22:12:25 -0500396 cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500397}
398
Steve French97837582007-12-31 07:47:21 +0000399/* copy ntsd, owner sid, and group sid from a security descriptor to another */
400static void copy_sec_desc(const struct cifs_ntsd *pntsd,
401 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
402{
Steve French97837582007-12-31 07:47:21 +0000403 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
404 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
405
406 /* copy security descriptor control portion */
407 pnntsd->revision = pntsd->revision;
408 pnntsd->type = pntsd->type;
409 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
410 pnntsd->sacloffset = 0;
411 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
412 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
413
414 /* copy owner sid */
415 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
416 le32_to_cpu(pntsd->osidoffset));
417 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400418 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000419
420 /* copy group sid */
421 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
422 le32_to_cpu(pntsd->gsidoffset));
423 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
424 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400425 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000426
427 return;
428}
429
430
Steve French630f3f0c2007-10-25 21:17:17 +0000431/*
432 change posix mode to reflect permissions
433 pmode is the existing mode (we only want to overwrite part of this
434 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
435*/
Al Viro9b5e6852007-12-05 08:24:38 +0000436static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000437 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000438{
Al Viro9b5e6852007-12-05 08:24:38 +0000439 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000440 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000441 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000442 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000443 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000444 for the operation you are trying to perform for your user */
445
446 /* For deny ACEs we change the mask so that subsequent allow access
447 control entries do not turn on the bits we are denying */
448 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000449 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000450 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000451
Al Viro9b5e6852007-12-05 08:24:38 +0000452 if ((flags & GENERIC_WRITE) ||
453 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000454 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000455 if ((flags & GENERIC_READ) ||
456 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000457 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000458 if ((flags & GENERIC_EXECUTE) ||
459 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000460 *pbits_to_set &= ~S_IXUGO;
461 return;
462 } else if (type != ACCESS_ALLOWED) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500463 cifs_dbg(VFS, "unknown access control type %d\n", type);
Steve French15b03952007-11-08 17:57:40 +0000464 return;
465 }
466 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000467
Al Viro9b5e6852007-12-05 08:24:38 +0000468 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000469 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesf96637b2013-05-04 22:12:25 -0500470 cifs_dbg(NOISY, "all perms\n");
Steve Frenchd61e5802007-10-26 04:32:43 +0000471 return;
472 }
Al Viro9b5e6852007-12-05 08:24:38 +0000473 if ((flags & GENERIC_WRITE) ||
474 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000475 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000476 if ((flags & GENERIC_READ) ||
477 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000478 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000479 if ((flags & GENERIC_EXECUTE) ||
480 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000481 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000482
Joe Perchesf96637b2013-05-04 22:12:25 -0500483 cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000484 return;
485}
486
Steve Frenchce06c9f2007-11-08 21:12:01 +0000487/*
488 Generate access flags to reflect permissions mode is the existing mode.
489 This function is called for every ACE in the DACL whose SID matches
490 with either owner or group or everyone.
491*/
492
493static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
494 __u32 *pace_flags)
495{
496 /* reset access mask */
497 *pace_flags = 0x0;
498
499 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
500 mode &= bits_to_use;
501
502 /* check for R/W/X UGO since we do not know whose flags
503 is this but we have cleared all the bits sans RWX for
504 either user or group or other as per bits_to_use */
505 if (mode & S_IRUGO)
506 *pace_flags |= SET_FILE_READ_RIGHTS;
507 if (mode & S_IWUGO)
508 *pace_flags |= SET_FILE_WRITE_RIGHTS;
509 if (mode & S_IXUGO)
510 *pace_flags |= SET_FILE_EXEC_RIGHTS;
511
Joe Perchesf96637b2013-05-04 22:12:25 -0500512 cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
513 mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000514 return;
515}
516
Al Viro2b210ad2008-03-29 03:09:18 +0000517static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000518 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
519{
520 int i;
521 __u16 size = 0;
522 __u32 access_req = 0;
523
524 pntace->type = ACCESS_ALLOWED;
525 pntace->flags = 0x0;
526 mode_to_access_flags(nmode, bits, &access_req);
527 if (!access_req)
528 access_req = SET_MINIMUM_RIGHTS;
529 pntace->access_req = cpu_to_le32(access_req);
530
531 pntace->sid.revision = psid->revision;
532 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500533 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000534 pntace->sid.authority[i] = psid->authority[i];
535 for (i = 0; i < psid->num_subauth; i++)
536 pntace->sid.sub_auth[i] = psid->sub_auth[i];
537
538 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
539 pntace->size = cpu_to_le16(size);
540
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000541 return size;
Steve French97837582007-12-31 07:47:21 +0000542}
543
Steve French297647c2007-10-12 04:11:59 +0000544
Steve French953f8682007-10-31 04:54:42 +0000545#ifdef CONFIG_CIFS_DEBUG2
546static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000547{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000548 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000549
550 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000551
Steve French44093ca2007-10-23 21:22:55 +0000552 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500553 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000554 return;
555 }
556
557 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500558 cifs_dbg(VFS, "ACL too small to parse ACE\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000559 return;
Steve French44093ca2007-10-23 21:22:55 +0000560 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000561
Steve French44093ca2007-10-23 21:22:55 +0000562 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000563 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000564 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500565 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
566 pace->sid.revision, pace->sid.num_subauth, pace->type,
567 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000568 for (i = 0; i < num_subauth; ++i) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500569 cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
570 i, le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000571 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000572
Steve Frenchd12fd122007-10-03 19:43:19 +0000573 /* BB add length check to make sure that we do not have huge
574 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000575 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000576
Steve Frenchd12fd122007-10-03 19:43:19 +0000577 return;
578}
Steve French953f8682007-10-31 04:54:42 +0000579#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000580
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000581
Steve Frencha750e772007-10-17 22:50:39 +0000582static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000583 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400584 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000585{
586 int i;
587 int num_aces = 0;
588 int acl_size;
589 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000590 struct cifs_ace **ppace;
591
592 /* BB need to add parm so we can store the SID BB */
593
Steve French2b834572007-11-25 10:01:00 +0000594 if (!pdacl) {
595 /* no DACL in the security descriptor, set
596 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400597 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000598 return;
599 }
600
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000601 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000602 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500603 cifs_dbg(VFS, "ACL too small to parse DACL\n");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000604 return;
605 }
606
Joe Perchesf96637b2013-05-04 22:12:25 -0500607 cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
608 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
609 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000610
Steve French7505e052007-11-01 18:03:01 +0000611 /* reset rwx permissions for user/group/other.
612 Also, if num_aces is 0 i.e. DACL has no ACEs,
613 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400614 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000615
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000616 acl_base = (char *)pdacl;
617 acl_size = sizeof(struct cifs_acl);
618
Steve Frenchadbc0352007-10-17 02:12:46 +0000619 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500620 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000621 umode_t user_mask = S_IRWXU;
622 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600623 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000624
Dan Carpenter72501702012-01-11 10:46:27 +0300625 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
626 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000627 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
628 GFP_KERNEL);
Joe Perchesf96637b2013-05-04 22:12:25 -0500629 if (!ppace)
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300630 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000631
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000632 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000633 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000634#ifdef CONFIG_CIFS_DEBUG2
635 dump_ace(ppace[i], end_of_acl);
636#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500637 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000638 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000639 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400640 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000641 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500642 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000643 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000644 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400645 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000646 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500647 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000648 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000649 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400650 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000651 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500652 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600653 access_flags_to_mode(ppace[i]->access_req,
654 ppace[i]->type,
655 &fattr->cf_mode,
656 &other_mask);
657
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000658
Steve French44093ca2007-10-23 21:22:55 +0000659/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000660 (void *)ppace[i],
661 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000662
Steve French44093ca2007-10-23 21:22:55 +0000663 acl_base = (char *)ppace[i];
664 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000665 }
666
667 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000668 }
669
670 return;
671}
672
Steve Frenchbcb02032007-09-25 16:17:24 +0000673
Steve French97837582007-12-31 07:47:21 +0000674static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
675 struct cifs_sid *pgrpsid, __u64 nmode)
676{
Al Viro2b210ad2008-03-29 03:09:18 +0000677 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000678 struct cifs_acl *pnndacl;
679
680 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
681
682 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
683 pownersid, nmode, S_IRWXU);
684 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
685 pgrpsid, nmode, S_IRWXG);
686 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
687 &sid_everyone, nmode, S_IRWXO);
688
689 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000690 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000691
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000692 return 0;
Steve French97837582007-12-31 07:47:21 +0000693}
694
695
Steve Frenchbcb02032007-09-25 16:17:24 +0000696static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
697{
698 /* BB need to add parm so we can store the SID BB */
699
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000700 /* validate that we do not go past end of ACL - sid must be at least 8
701 bytes long (assuming no sub-auths - e.g. the null SID */
702 if (end_of_acl < (char *)psid + 8) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500703 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000704 return -EINVAL;
705 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000706
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000707#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500708 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000709 int i;
Joe Perchesf96637b2013-05-04 22:12:25 -0500710 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
711 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000712
Steve Frenchaf6f4612007-10-16 18:40:37 +0000713 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500714 cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
715 i, le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000716 }
717
Steve Frenchd12fd122007-10-03 19:43:19 +0000718 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000719 num auths and therefore go off the end */
Joe Perchesf96637b2013-05-04 22:12:25 -0500720 cifs_dbg(FYI, "RID 0x%x\n",
721 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000722 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500723#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000724
Steve Frenchbcb02032007-09-25 16:17:24 +0000725 return 0;
726}
727
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000728
Steve Frenchbcb02032007-09-25 16:17:24 +0000729/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500730static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
731 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000732{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500733 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000734 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
735 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000736 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000737 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000738
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400739 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000740 return -EIO;
741
Steve Frenchbcb02032007-09-25 16:17:24 +0000742 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000743 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000744 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000745 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000746 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000747 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesf96637b2013-05-04 22:12:25 -0500748 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 +0000749 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
750 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000751 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000752/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000753 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500754 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500755 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000756 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500757 }
758 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
759 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500760 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
761 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500762 return rc;
763 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000764
765 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500766 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500767 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
768 __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000769 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500770 }
771 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
772 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500773 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
774 __func__, rc);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500775 return rc;
776 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000777
Steve French7505e052007-11-01 18:03:01 +0000778 if (dacloffset)
779 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400780 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000781 else
Joe Perchesf96637b2013-05-04 22:12:25 -0500782 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000783
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500784 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000785}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000786
Steve French97837582007-12-31 07:47:21 +0000787/* Convert permission bits from mode to equivalent CIFS ACL */
788static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800789 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +0000790{
791 int rc = 0;
792 __u32 dacloffset;
793 __u32 ndacloffset;
794 __u32 sidsoffset;
795 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500796 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +0000797 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
798 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
799
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500800 if (nmode != NO_CHANGE_64) { /* chmod */
801 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000802 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500803 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +0000804 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500805 dacloffset = le32_to_cpu(pntsd->dacloffset);
806 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
807 ndacloffset = sizeof(struct cifs_ntsd);
808 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
809 ndacl_ptr->revision = dacl_ptr->revision;
810 ndacl_ptr->size = 0;
811 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +0000812
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500813 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
814 nmode);
815 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
816 /* copy sec desc control portion & owner and group sids */
817 copy_sec_desc(pntsd, pnntsd, sidsoffset);
818 *aclflag = CIFS_ACL_DACL;
819 } else {
820 memcpy(pnntsd, pntsd, secdesclen);
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800821 if (uid_valid(uid)) { /* chown */
822 uid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500823 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
824 le32_to_cpu(pnntsd->osidoffset));
825 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
826 GFP_KERNEL);
827 if (!nowner_sid_ptr)
828 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800829 id = from_kuid(&init_user_ns, uid);
830 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500831 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500832 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
833 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500834 kfree(nowner_sid_ptr);
835 return rc;
836 }
Jeff Layton36960e42012-11-03 09:37:28 -0400837 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500838 kfree(nowner_sid_ptr);
839 *aclflag = CIFS_ACL_OWNER;
840 }
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800841 if (gid_valid(gid)) { /* chgrp */
842 gid_t id;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500843 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
844 le32_to_cpu(pnntsd->gsidoffset));
845 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
846 GFP_KERNEL);
847 if (!ngroup_sid_ptr)
848 return -ENOMEM;
Eric W. Biederman8abf2772013-02-06 00:33:17 -0800849 id = from_kgid(&init_user_ns, gid);
850 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500851 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500852 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
853 __func__, rc, id);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500854 kfree(ngroup_sid_ptr);
855 return rc;
856 }
Jeff Layton36960e42012-11-03 09:37:28 -0400857 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500858 kfree(ngroup_sid_ptr);
859 *aclflag = CIFS_ACL_GROUP;
860 }
861 }
Steve French97837582007-12-31 07:47:21 +0000862
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000863 return rc;
Steve French97837582007-12-31 07:47:21 +0000864}
865
Steve French42eacf92014-02-10 14:08:16 -0600866struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
867 const struct cifs_fid *cifsfid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000868{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000869 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400870 unsigned int xid;
871 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400872 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
873
874 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600875 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000876
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400877 xid = get_xid();
Steve French42eacf92014-02-10 14:08:16 -0600878 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
879 pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400880 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000881
Jeff Layton7ffec372010-09-29 19:51:11 -0400882 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000883
Joe Perchesf96637b2013-05-04 22:12:25 -0500884 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600885 if (rc)
886 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400887 return pntsd;
888}
889
890static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
891 const char *path, u32 *pacllen)
892{
893 struct cifs_ntsd *pntsd = NULL;
894 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400895 unsigned int xid;
896 int rc, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +0000897 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400898 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400899 struct cifs_fid fid;
900 struct cifs_open_parms oparms;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400901
Jeff Layton7ffec372010-09-29 19:51:11 -0400902 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600903 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400904
905 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400906 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400907
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500908 if (backup_cred(cifs_sb))
909 create_options |= CREATE_OPEN_BACKUP_INTENT;
910
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400911 oparms.tcon = tcon;
912 oparms.cifs_sb = cifs_sb;
913 oparms.desired_access = READ_CONTROL;
914 oparms.create_options = create_options;
915 oparms.disposition = FILE_OPEN;
916 oparms.path = path;
917 oparms.fid = &fid;
918 oparms.reconnect = false;
919
920 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600921 if (!rc) {
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400922 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
923 CIFSSMBClose(xid, tcon, fid.netfid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000924 }
925
Jeff Layton7ffec372010-09-29 19:51:11 -0400926 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400927 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600928
Joe Perchesf96637b2013-05-04 22:12:25 -0500929 cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600930 if (rc)
931 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000932 return pntsd;
933}
934
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400935/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600936struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400937 struct inode *inode, const char *path,
938 u32 *pacllen)
939{
940 struct cifs_ntsd *pntsd = NULL;
941 struct cifsFileInfo *open_file = NULL;
942
943 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400944 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400945 if (!open_file)
946 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
947
Steve French42eacf92014-02-10 14:08:16 -0600948 pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400949 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400950 return pntsd;
951}
952
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500953 /* Set an ACL on the server */
954int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
955 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400956{
957 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400958 unsigned int xid;
959 int rc, access_flags, create_options = 0;
Steve French96daf2b2011-05-27 04:34:02 +0000960 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500961 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -0400962 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400963 struct cifs_fid fid;
964 struct cifs_open_parms oparms;
Steve French97837582007-12-31 07:47:21 +0000965
Jeff Layton7ffec372010-09-29 19:51:11 -0400966 if (IS_ERR(tlink))
967 return PTR_ERR(tlink);
968
969 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +0400970 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +0000971
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -0500972 if (backup_cred(cifs_sb))
973 create_options |= CREATE_OPEN_BACKUP_INTENT;
974
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500975 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
976 access_flags = WRITE_OWNER;
977 else
978 access_flags = WRITE_DAC;
979
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400980 oparms.tcon = tcon;
981 oparms.cifs_sb = cifs_sb;
982 oparms.desired_access = access_flags;
983 oparms.create_options = create_options;
984 oparms.disposition = FILE_OPEN;
985 oparms.path = path;
986 oparms.fid = &fid;
987 oparms.reconnect = false;
988
989 rc = CIFS_open(xid, &oparms, &oplock, NULL);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400990 if (rc) {
Joe Perchesf96637b2013-05-04 22:12:25 -0500991 cifs_dbg(VFS, "Unable to open file to set ACL\n");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400992 goto out;
Steve French97837582007-12-31 07:47:21 +0000993 }
994
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400995 rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -0500996 cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
Steve French97837582007-12-31 07:47:21 +0000997
Pavel Shilovskyd81b8a42014-01-16 15:53:36 +0400998 CIFSSMBClose(xid, tcon, fid.netfid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400999out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001000 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001001 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001002 return rc;
1003}
Steve French97837582007-12-31 07:47:21 +00001004
Steve French7505e052007-11-01 18:03:01 +00001005/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001006int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001007cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
Steve French42eacf92014-02-10 14:08:16 -06001008 struct inode *inode, const char *path,
1009 const struct cifs_fid *pfid)
Steve French7505e052007-11-01 18:03:01 +00001010{
1011 struct cifs_ntsd *pntsd = NULL;
1012 u32 acllen = 0;
1013 int rc = 0;
Steve French42eacf92014-02-10 14:08:16 -06001014 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1015 struct cifs_tcon *tcon;
Steve French7505e052007-11-01 18:03:01 +00001016
Joe Perchesf96637b2013-05-04 22:12:25 -05001017 cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001018
Steve French42eacf92014-02-10 14:08:16 -06001019 if (IS_ERR(tlink))
1020 return PTR_ERR(tlink);
1021 tcon = tlink_tcon(tlink);
Steve French7505e052007-11-01 18:03:01 +00001022
Steve French42eacf92014-02-10 14:08:16 -06001023 if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
1024 pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
1025 &acllen);
1026 else if (tcon->ses->server->ops->get_acl)
1027 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1028 &acllen);
1029 else {
1030 cifs_put_tlink(tlink);
1031 return -EOPNOTSUPP;
1032 }
Steve French7505e052007-11-01 18:03:01 +00001033 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001034 if (IS_ERR(pntsd)) {
1035 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001036 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001037 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001038 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001039 kfree(pntsd);
1040 if (rc)
Joe Perchesf96637b2013-05-04 22:12:25 -05001041 cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001042 }
Steve French7505e052007-11-01 18:03:01 +00001043
Steve French42eacf92014-02-10 14:08:16 -06001044 cifs_put_tlink(tlink);
1045
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001046 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001047}
Steve French953f8682007-10-31 04:54:42 +00001048
Steve French7505e052007-11-01 18:03:01 +00001049/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001050int
1051id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
Eric W. Biederman8abf2772013-02-06 00:33:17 -08001052 kuid_t uid, kgid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001053{
1054 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001055 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001056 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001057 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1058 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French83e3bc22014-02-02 23:31:47 -06001059 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1060 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1061 struct cifs_tcon *tcon;
1062
1063 if (IS_ERR(tlink))
1064 return PTR_ERR(tlink);
1065 tcon = tlink_tcon(tlink);
Steve French953f8682007-10-31 04:54:42 +00001066
Joe Perchesf96637b2013-05-04 22:12:25 -05001067 cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
Steve French953f8682007-10-31 04:54:42 +00001068
1069 /* Get the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001070
1071 if (tcon->ses->server->ops->get_acl == NULL) {
1072 cifs_put_tlink(tlink);
1073 return -EOPNOTSUPP;
1074 }
1075
1076 pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
1077 &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001078 if (IS_ERR(pntsd)) {
1079 rc = PTR_ERR(pntsd);
Joe Perchesf96637b2013-05-04 22:12:25 -05001080 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
Steve French83e3bc22014-02-02 23:31:47 -06001081 cifs_put_tlink(tlink);
1082 return rc;
Steve French97837582007-12-31 07:47:21 +00001083 }
1084
Jeff Laytonc78cd832012-11-25 08:00:35 -05001085 /*
1086 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1087 * as chmod disables ACEs and set the security descriptor. Allocate
1088 * memory for the smb header, set security descriptor request security
1089 * descriptor parameters, and secuirty descriptor itself
1090 */
Jeff Layton7ee0b4c2012-12-03 06:05:31 -05001091 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001092 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1093 if (!pnntsd) {
Jeff Laytonc78cd832012-11-25 08:00:35 -05001094 kfree(pntsd);
Steve French83e3bc22014-02-02 23:31:47 -06001095 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001096 return -ENOMEM;
1097 }
1098
1099 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1100 &aclflag);
1101
Joe Perchesf96637b2013-05-04 22:12:25 -05001102 cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001103
Steve French83e3bc22014-02-02 23:31:47 -06001104 if (tcon->ses->server->ops->set_acl == NULL)
1105 rc = -EOPNOTSUPP;
1106
Jeff Laytonc78cd832012-11-25 08:00:35 -05001107 if (!rc) {
1108 /* Set the security descriptor */
Steve French83e3bc22014-02-02 23:31:47 -06001109 rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
1110 path, aclflag);
Joe Perchesf96637b2013-05-04 22:12:25 -05001111 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001112 }
Steve French83e3bc22014-02-02 23:31:47 -06001113 cifs_put_tlink(tlink);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001114
1115 kfree(pnntsd);
1116 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001117 return rc;
Steve French953f8682007-10-31 04:54:42 +00001118}