blob: 061fc3afd841c0d0cd356cb8cfda0e4c6e753c90 [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
Steve French297647c2007-10-12 04:11:59 +000036
Steve Frenchaf6f4612007-10-16 18:40:37 +000037static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
Steve French297647c2007-10-12 04:11:59 +000038 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
39 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
Jeff Layton536abdb2008-07-12 13:48:00 -070040 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
41 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
42 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
43 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
44 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
Steve French44093ca2007-10-23 21:22:55 +000045;
Steve French297647c2007-10-12 04:11:59 +000046
47
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060048/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000049static const struct cifs_sid sid_everyone = {
50 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060051/* security id for Authenticated Users system group */
52static const struct cifs_sid sid_authusers = {
53 1, 1, {0, 0, 0, 0, 0, 5}, {11} };
Steve Frenchbcb02032007-09-25 16:17:24 +000054/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000055static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000056
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050057static const struct cred *root_cred;
58
59/*
60 * Run idmap cache shrinker.
61 */
62static int
63cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
64{
65 /* Use a pruning scheme in a subsequent patch instead */
66 cifs_destroy_idmaptrees();
67 return 0;
68}
69
70static struct shrinker cifs_shrinker = {
71 .shrink = cifs_idmap_shrinker,
72 .seeks = DEFAULT_SEEKS,
73};
74
75static int
76cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
77{
78 char *payload;
79
80 payload = kmalloc(datalen, GFP_KERNEL);
81 if (!payload)
82 return -ENOMEM;
83
84 memcpy(payload, data, datalen);
85 key->payload.data = payload;
86 return 0;
87}
88
89static inline void
90cifs_idmap_key_destroy(struct key *key)
91{
92 kfree(key->payload.data);
93}
94
95static
96struct key_type cifs_idmap_key_type = {
97 .name = "cifs.cifs_idmap",
98 .instantiate = cifs_idmap_key_instantiate,
99 .destroy = cifs_idmap_key_destroy,
100 .describe = user_describe,
101 .match = user_match,
102};
103
104int
105init_cifs_idmap(void)
106{
107 struct cred *cred;
108 struct key *keyring;
109 int ret;
110
111 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
112
113 /* create an override credential set with a special thread keyring in
114 * which requests are cached
115 *
116 * this is used to prevent malicious redirections from being installed
117 * with add_key().
118 */
119 cred = prepare_kernel_cred(NULL);
120 if (!cred)
121 return -ENOMEM;
122
123 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
124 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
125 KEY_USR_VIEW | KEY_USR_READ,
126 KEY_ALLOC_NOT_IN_QUOTA);
127 if (IS_ERR(keyring)) {
128 ret = PTR_ERR(keyring);
129 goto failed_put_cred;
130 }
131
132 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
133 if (ret < 0)
134 goto failed_put_key;
135
136 ret = register_key_type(&cifs_idmap_key_type);
137 if (ret < 0)
138 goto failed_put_key;
139
140 /* instruct request_key() to use this special keyring as a cache for
141 * the results it looks up */
142 cred->thread_keyring = keyring;
143 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
144 root_cred = cred;
145
146 spin_lock_init(&siduidlock);
147 uidtree = RB_ROOT;
148 spin_lock_init(&sidgidlock);
149 gidtree = RB_ROOT;
150
151 register_shrinker(&cifs_shrinker);
152
153 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
154 return 0;
155
156failed_put_key:
157 key_put(keyring);
158failed_put_cred:
159 put_cred(cred);
160 return ret;
161}
162
163void
164exit_cifs_idmap(void)
165{
166 key_revoke(root_cred->thread_keyring);
167 unregister_key_type(&cifs_idmap_key_type);
168 put_cred(root_cred);
169 unregister_shrinker(&cifs_shrinker);
170 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
171}
172
173void
174cifs_destroy_idmaptrees(void)
175{
176 struct rb_root *root;
177 struct rb_node *node;
178
179 root = &uidtree;
180 spin_lock(&siduidlock);
181 while ((node = rb_first(root)))
182 rb_erase(node, root);
183 spin_unlock(&siduidlock);
184
185 root = &gidtree;
186 spin_lock(&sidgidlock);
187 while ((node = rb_first(root)))
188 rb_erase(node, root);
189 spin_unlock(&sidgidlock);
190}
Steve French297647c2007-10-12 04:11:59 +0000191
192int match_sid(struct cifs_sid *ctsid)
193{
194 int i, j;
195 int num_subauth, num_sat, num_saw;
196 struct cifs_sid *cwsid;
197
198 if (!ctsid)
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000199 return -1;
Steve French297647c2007-10-12 04:11:59 +0000200
201 for (i = 0; i < NUM_WK_SIDS; ++i) {
202 cwsid = &(wksidarr[i].cifssid);
203
204 /* compare the revision */
205 if (ctsid->revision != cwsid->revision)
206 continue;
207
208 /* compare all of the six auth values */
209 for (j = 0; j < 6; ++j) {
210 if (ctsid->authority[j] != cwsid->authority[j])
211 break;
212 }
213 if (j < 6)
214 continue; /* all of the auth values did not match */
215
216 /* compare all of the subauth values if any */
Dave Kleikampce51ae12007-10-16 21:35:39 +0000217 num_sat = ctsid->num_subauth;
218 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000219 num_subauth = num_sat < num_saw ? num_sat : num_saw;
220 if (num_subauth) {
221 for (j = 0; j < num_subauth; ++j) {
222 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
223 break;
224 }
225 if (j < num_subauth)
226 continue; /* all sub_auth values do not match */
227 }
228
Joe Perchesb6b38f72010-04-21 03:50:45 +0000229 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000230 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000231 }
232
Joe Perchesb6b38f72010-04-21 03:50:45 +0000233 cFYI(1, "No matching sid");
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000234 return -1;
Steve French297647c2007-10-12 04:11:59 +0000235}
236
Steve Frencha750e772007-10-17 22:50:39 +0000237/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
238 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000239int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000240{
241 int i;
242 int num_subauth, num_sat, num_saw;
243
244 if ((!ctsid) || (!cwsid))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000245 return 0;
Steve French297647c2007-10-12 04:11:59 +0000246
247 /* compare the revision */
248 if (ctsid->revision != cwsid->revision)
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000249 return 0;
Steve French297647c2007-10-12 04:11:59 +0000250
251 /* compare all of the six auth values */
252 for (i = 0; i < 6; ++i) {
253 if (ctsid->authority[i] != cwsid->authority[i])
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000254 return 0;
Steve French297647c2007-10-12 04:11:59 +0000255 }
256
257 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000258 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000259 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000260 num_subauth = num_sat < num_saw ? num_sat : num_saw;
261 if (num_subauth) {
262 for (i = 0; i < num_subauth; ++i) {
263 if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000264 return 0;
Steve French297647c2007-10-12 04:11:59 +0000265 }
266 }
267
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000268 return 1; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000269}
270
Steve French97837582007-12-31 07:47:21 +0000271
272/* copy ntsd, owner sid, and group sid from a security descriptor to another */
273static void copy_sec_desc(const struct cifs_ntsd *pntsd,
274 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
275{
276 int i;
277
278 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
279 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
280
281 /* copy security descriptor control portion */
282 pnntsd->revision = pntsd->revision;
283 pnntsd->type = pntsd->type;
284 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
285 pnntsd->sacloffset = 0;
286 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
287 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
288
289 /* copy owner sid */
290 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
291 le32_to_cpu(pntsd->osidoffset));
292 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
293
294 nowner_sid_ptr->revision = owner_sid_ptr->revision;
295 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
296 for (i = 0; i < 6; i++)
297 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
298 for (i = 0; i < 5; i++)
299 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
300
301 /* copy group sid */
302 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
303 le32_to_cpu(pntsd->gsidoffset));
304 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
305 sizeof(struct cifs_sid));
306
307 ngroup_sid_ptr->revision = group_sid_ptr->revision;
308 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
309 for (i = 0; i < 6; i++)
310 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
311 for (i = 0; i < 5; i++)
Shirish Pargaonkarb1910ad2008-07-24 14:53:20 +0000312 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
Steve French97837582007-12-31 07:47:21 +0000313
314 return;
315}
316
317
Steve French630f3f0c2007-10-25 21:17:17 +0000318/*
319 change posix mode to reflect permissions
320 pmode is the existing mode (we only want to overwrite part of this
321 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
322*/
Al Viro9b5e6852007-12-05 08:24:38 +0000323static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000324 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000325{
Al Viro9b5e6852007-12-05 08:24:38 +0000326 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000327 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000328 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000329 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000330 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000331 for the operation you are trying to perform for your user */
332
333 /* For deny ACEs we change the mask so that subsequent allow access
334 control entries do not turn on the bits we are denying */
335 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000336 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000337 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000338
Al Viro9b5e6852007-12-05 08:24:38 +0000339 if ((flags & GENERIC_WRITE) ||
340 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000341 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000342 if ((flags & GENERIC_READ) ||
343 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000344 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000345 if ((flags & GENERIC_EXECUTE) ||
346 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000347 *pbits_to_set &= ~S_IXUGO;
348 return;
349 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000350 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000351 return;
352 }
353 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000354
Al Viro9b5e6852007-12-05 08:24:38 +0000355 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000356 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000357 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000358 return;
359 }
Al Viro9b5e6852007-12-05 08:24:38 +0000360 if ((flags & GENERIC_WRITE) ||
361 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000362 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000363 if ((flags & GENERIC_READ) ||
364 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000365 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000366 if ((flags & GENERIC_EXECUTE) ||
367 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000368 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000369
Joe Perchesb6b38f72010-04-21 03:50:45 +0000370 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000371 return;
372}
373
Steve Frenchce06c9f2007-11-08 21:12:01 +0000374/*
375 Generate access flags to reflect permissions mode is the existing mode.
376 This function is called for every ACE in the DACL whose SID matches
377 with either owner or group or everyone.
378*/
379
380static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
381 __u32 *pace_flags)
382{
383 /* reset access mask */
384 *pace_flags = 0x0;
385
386 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
387 mode &= bits_to_use;
388
389 /* check for R/W/X UGO since we do not know whose flags
390 is this but we have cleared all the bits sans RWX for
391 either user or group or other as per bits_to_use */
392 if (mode & S_IRUGO)
393 *pace_flags |= SET_FILE_READ_RIGHTS;
394 if (mode & S_IWUGO)
395 *pace_flags |= SET_FILE_WRITE_RIGHTS;
396 if (mode & S_IXUGO)
397 *pace_flags |= SET_FILE_EXEC_RIGHTS;
398
Joe Perchesb6b38f72010-04-21 03:50:45 +0000399 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000400 return;
401}
402
Al Viro2b210ad2008-03-29 03:09:18 +0000403static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000404 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
405{
406 int i;
407 __u16 size = 0;
408 __u32 access_req = 0;
409
410 pntace->type = ACCESS_ALLOWED;
411 pntace->flags = 0x0;
412 mode_to_access_flags(nmode, bits, &access_req);
413 if (!access_req)
414 access_req = SET_MINIMUM_RIGHTS;
415 pntace->access_req = cpu_to_le32(access_req);
416
417 pntace->sid.revision = psid->revision;
418 pntace->sid.num_subauth = psid->num_subauth;
419 for (i = 0; i < 6; i++)
420 pntace->sid.authority[i] = psid->authority[i];
421 for (i = 0; i < psid->num_subauth; i++)
422 pntace->sid.sub_auth[i] = psid->sub_auth[i];
423
424 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
425 pntace->size = cpu_to_le16(size);
426
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000427 return size;
Steve French97837582007-12-31 07:47:21 +0000428}
429
Steve French297647c2007-10-12 04:11:59 +0000430
Steve French953f8682007-10-31 04:54:42 +0000431#ifdef CONFIG_CIFS_DEBUG2
432static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000433{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000434 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000435
436 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000437
Steve French44093ca2007-10-23 21:22:55 +0000438 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000439 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000440 return;
441 }
442
443 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000444 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000445 return;
Steve French44093ca2007-10-23 21:22:55 +0000446 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000447
Steve French44093ca2007-10-23 21:22:55 +0000448 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000449 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000450 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000451 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000452 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000453 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000454 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000455 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
456 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000457 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000458
Steve Frenchd12fd122007-10-03 19:43:19 +0000459 /* BB add length check to make sure that we do not have huge
460 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000461 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000462
Steve Frenchd12fd122007-10-03 19:43:19 +0000463 return;
464}
Steve French953f8682007-10-31 04:54:42 +0000465#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000466
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000467
Steve Frencha750e772007-10-17 22:50:39 +0000468static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000469 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400470 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000471{
472 int i;
473 int num_aces = 0;
474 int acl_size;
475 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000476 struct cifs_ace **ppace;
477
478 /* BB need to add parm so we can store the SID BB */
479
Steve French2b834572007-11-25 10:01:00 +0000480 if (!pdacl) {
481 /* no DACL in the security descriptor, set
482 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400483 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000484 return;
485 }
486
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000487 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000488 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000489 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000490 return;
491 }
492
Joe Perchesb6b38f72010-04-21 03:50:45 +0000493 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000494 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000495 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000496
Steve French7505e052007-11-01 18:03:01 +0000497 /* reset rwx permissions for user/group/other.
498 Also, if num_aces is 0 i.e. DACL has no ACEs,
499 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400500 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000501
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000502 acl_base = (char *)pdacl;
503 acl_size = sizeof(struct cifs_acl);
504
Steve Frenchadbc0352007-10-17 02:12:46 +0000505 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000506 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000507 umode_t user_mask = S_IRWXU;
508 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600509 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000510
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000511 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
512 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300513 if (!ppace) {
514 cERROR(1, "DACL memory allocation error");
515 return;
516 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000517
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000518 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000519 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000520#ifdef CONFIG_CIFS_DEBUG2
521 dump_ace(ppace[i], end_of_acl);
522#endif
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000523 if (compare_sids(&(ppace[i]->sid), pownersid))
524 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000525 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400526 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000527 &user_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000528 if (compare_sids(&(ppace[i]->sid), pgrpsid))
529 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000530 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400531 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000532 &group_mask);
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000533 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
534 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000535 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400536 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000537 &other_mask);
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600538 if (compare_sids(&(ppace[i]->sid), &sid_authusers))
539 access_flags_to_mode(ppace[i]->access_req,
540 ppace[i]->type,
541 &fattr->cf_mode,
542 &other_mask);
543
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000544
Steve French44093ca2007-10-23 21:22:55 +0000545/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000546 (void *)ppace[i],
547 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000548
Steve French44093ca2007-10-23 21:22:55 +0000549 acl_base = (char *)ppace[i];
550 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000551 }
552
553 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000554 }
555
556 return;
557}
558
Steve Frenchbcb02032007-09-25 16:17:24 +0000559
Steve French97837582007-12-31 07:47:21 +0000560static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
561 struct cifs_sid *pgrpsid, __u64 nmode)
562{
Al Viro2b210ad2008-03-29 03:09:18 +0000563 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000564 struct cifs_acl *pnndacl;
565
566 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
567
568 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
569 pownersid, nmode, S_IRWXU);
570 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
571 pgrpsid, nmode, S_IRWXG);
572 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
573 &sid_everyone, nmode, S_IRWXO);
574
575 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000576 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000577
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000578 return 0;
Steve French97837582007-12-31 07:47:21 +0000579}
580
581
Steve Frenchbcb02032007-09-25 16:17:24 +0000582static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
583{
584 /* BB need to add parm so we can store the SID BB */
585
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000586 /* validate that we do not go past end of ACL - sid must be at least 8
587 bytes long (assuming no sub-auths - e.g. the null SID */
588 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000589 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000590 return -EINVAL;
591 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000592
Steve Frenchaf6f4612007-10-16 18:40:37 +0000593 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000594#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000595 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000596 cFYI(1, "SID revision %d num_auth %d",
597 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000598
Steve Frenchaf6f4612007-10-16 18:40:37 +0000599 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000600 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
601 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000602 }
603
Steve Frenchd12fd122007-10-03 19:43:19 +0000604 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000605 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000606 cFYI(1, "RID 0x%x",
607 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +0000608#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000609 }
610
Steve Frenchbcb02032007-09-25 16:17:24 +0000611 return 0;
612}
613
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000614
Steve Frenchbcb02032007-09-25 16:17:24 +0000615/* Convert CIFS ACL to POSIX form */
Steve French630f3f0c2007-10-25 21:17:17 +0000616static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400617 struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000618{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000619 int rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000620 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
621 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000622 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000623 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000624
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400625 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000626 return -EIO;
627
Steve Frenchbcb02032007-09-25 16:17:24 +0000628 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000629 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000630 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000631 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000632 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000633 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000634 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000635 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000636 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
637 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000638 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000639/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000640 rc = parse_sid(owner_sid_ptr, end_of_acl);
641 if (rc)
642 return rc;
643
644 rc = parse_sid(group_sid_ptr, end_of_acl);
645 if (rc)
646 return rc;
647
Steve French7505e052007-11-01 18:03:01 +0000648 if (dacloffset)
649 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400650 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000651 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000652 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000653
Steve Frenchbcb02032007-09-25 16:17:24 +0000654/* cifscred->uid = owner_sid_ptr->rid;
655 cifscred->gid = group_sid_ptr->rid;
656 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000657 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000658 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000659 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000660
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000661 return 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000662}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000663
664
Steve French97837582007-12-31 07:47:21 +0000665/* Convert permission bits from mode to equivalent CIFS ACL */
666static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve Frenchcce246e2008-04-09 20:55:31 +0000667 struct inode *inode, __u64 nmode)
Steve French97837582007-12-31 07:47:21 +0000668{
669 int rc = 0;
670 __u32 dacloffset;
671 __u32 ndacloffset;
672 __u32 sidsoffset;
673 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
674 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
675 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
676
677 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000678 return -EIO;
Steve French97837582007-12-31 07:47:21 +0000679
680 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
681 le32_to_cpu(pntsd->osidoffset));
682 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
683 le32_to_cpu(pntsd->gsidoffset));
684
685 dacloffset = le32_to_cpu(pntsd->dacloffset);
686 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
687
688 ndacloffset = sizeof(struct cifs_ntsd);
689 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
690 ndacl_ptr->revision = dacl_ptr->revision;
691 ndacl_ptr->size = 0;
692 ndacl_ptr->num_aces = 0;
693
694 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
695
696 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
697
698 /* copy security descriptor control portion and owner and group sid */
699 copy_sec_desc(pntsd, pnntsd, sidsoffset);
700
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000701 return rc;
Steve French97837582007-12-31 07:47:21 +0000702}
703
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400704static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
705 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000706{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000707 struct cifs_ntsd *pntsd = NULL;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400708 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400709 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
710
711 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600712 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000713
714 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400715 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400716 FreeXid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000717
Jeff Layton7ffec372010-09-29 19:51:11 -0400718 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000719
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600720 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
721 if (rc)
722 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400723 return pntsd;
724}
725
726static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
727 const char *path, u32 *pacllen)
728{
729 struct cifs_ntsd *pntsd = NULL;
730 int oplock = 0;
731 int xid, rc;
732 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400733 struct cifsTconInfo *tcon;
734 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400735
Jeff Layton7ffec372010-09-29 19:51:11 -0400736 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600737 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400738
739 tcon = tlink_tcon(tlink);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400740 xid = GetXid();
741
Jeff Layton7ffec372010-09-29 19:51:11 -0400742 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400743 &fid, &oplock, NULL, cifs_sb->local_nls,
744 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600745 if (!rc) {
746 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
747 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000748 }
749
Jeff Layton7ffec372010-09-29 19:51:11 -0400750 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000751 FreeXid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600752
753 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
754 if (rc)
755 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000756 return pntsd;
757}
758
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400759/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600760struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400761 struct inode *inode, const char *path,
762 u32 *pacllen)
763{
764 struct cifs_ntsd *pntsd = NULL;
765 struct cifsFileInfo *open_file = NULL;
766
767 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400768 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400769 if (!open_file)
770 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
771
772 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400773 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400774 return pntsd;
775}
776
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400777static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
778 struct cifs_ntsd *pnntsd, u32 acllen)
Steve French97837582007-12-31 07:47:21 +0000779{
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400780 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400781 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
782
783 if (IS_ERR(tlink))
784 return PTR_ERR(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400785
786 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400787 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400788 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400789 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400790
Joe Perchesb6b38f72010-04-21 03:50:45 +0000791 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400792 return rc;
793}
794
795static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
796 struct cifs_ntsd *pnntsd, u32 acllen)
797{
798 int oplock = 0;
799 int xid, rc;
Steve French97837582007-12-31 07:47:21 +0000800 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -0400801 struct cifsTconInfo *tcon;
802 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +0000803
Jeff Layton7ffec372010-09-29 19:51:11 -0400804 if (IS_ERR(tlink))
805 return PTR_ERR(tlink);
806
807 tcon = tlink_tcon(tlink);
Steve French97837582007-12-31 07:47:21 +0000808 xid = GetXid();
809
Jeff Layton7ffec372010-09-29 19:51:11 -0400810 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400811 &fid, &oplock, NULL, cifs_sb->local_nls,
812 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
813 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000814 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400815 goto out;
Steve French97837582007-12-31 07:47:21 +0000816 }
817
Jeff Layton7ffec372010-09-29 19:51:11 -0400818 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000819 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +0000820
Jeff Layton7ffec372010-09-29 19:51:11 -0400821 CIFSSMBClose(xid, tcon, fid);
822out:
Steve French97837582007-12-31 07:47:21 +0000823 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -0400824 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400825 return rc;
826}
Steve French97837582007-12-31 07:47:21 +0000827
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400828/* Set an ACL on the server */
Steve Frenchb73b9a42011-04-19 18:27:10 +0000829int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400830 struct inode *inode, const char *path)
831{
832 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
833 struct cifsFileInfo *open_file;
834 int rc;
835
Joe Perchesb6b38f72010-04-21 03:50:45 +0000836 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400837
Jeff Layton6508d902010-09-29 19:51:11 -0400838 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400839 if (!open_file)
840 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
841
842 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400843 cifsFileInfo_put(open_file);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000844 return rc;
Steve French97837582007-12-31 07:47:21 +0000845}
846
Steve French7505e052007-11-01 18:03:01 +0000847/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600848int
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400849cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
850 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +0000851{
852 struct cifs_ntsd *pntsd = NULL;
853 u32 acllen = 0;
854 int rc = 0;
855
Joe Perchesb6b38f72010-04-21 03:50:45 +0000856 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400857
858 if (pfid)
859 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
860 else
861 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +0000862
863 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600864 if (IS_ERR(pntsd)) {
865 rc = PTR_ERR(pntsd);
866 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
867 } else {
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400868 rc = parse_sec_desc(pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600869 kfree(pntsd);
870 if (rc)
871 cERROR(1, "parse sec desc failed rc = %d", rc);
872 }
Steve French7505e052007-11-01 18:03:01 +0000873
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600874 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000875}
Steve French953f8682007-10-31 04:54:42 +0000876
Steve French7505e052007-11-01 18:03:01 +0000877/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkar78415d22010-11-27 11:37:26 -0600878int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
Steve French953f8682007-10-31 04:54:42 +0000879{
880 int rc = 0;
Steve Frenchcce246e2008-04-09 20:55:31 +0000881 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +0000882 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
883 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +0000884
Joe Perchesb6b38f72010-04-21 03:50:45 +0000885 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +0000886
887 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400888 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +0000889
Steve French97837582007-12-31 07:47:21 +0000890 /* Add three ACEs for owner, group, everyone getting rid of
891 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +0000892
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600893 if (IS_ERR(pntsd)) {
894 rc = PTR_ERR(pntsd);
895 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
896 } else {
Steve French97837582007-12-31 07:47:21 +0000897 /* allocate memory for the smb header,
898 set security descriptor request security descriptor
899 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +0000900
Steve Frenchcce246e2008-04-09 20:55:31 +0000901 secdesclen = secdesclen < DEFSECDESCLEN ?
902 DEFSECDESCLEN : secdesclen;
903 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +0000904 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000905 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +0000906 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000907 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +0000908 }
Steve French7505e052007-11-01 18:03:01 +0000909
Steve Frenchcce246e2008-04-09 20:55:31 +0000910 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
Steve French97837582007-12-31 07:47:21 +0000911
Joe Perchesb6b38f72010-04-21 03:50:45 +0000912 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +0000913
914 if (!rc) {
915 /* Set the security descriptor */
Steve Frenchcce246e2008-04-09 20:55:31 +0000916 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000917 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +0000918 }
919
920 kfree(pnntsd);
921 kfree(pntsd);
922 }
923
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000924 return rc;
Steve French953f8682007-10-31 04:54:42 +0000925}