blob: 5f02b4ee9a030fa2dcfa42c2ce845e145522739c [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
Steve French8b1327f2008-03-14 22:37:16 +00004 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050026#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
Steve French65874002007-09-25 19:53:44 +000030#include "cifspdu.h"
31#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000032#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000033#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French65874002007-09-25 19:53:44 +000035
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060036/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000037static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060039/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
Steve French383c5532011-05-27 15:19:12 +000041 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
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050045const struct cred *root_cred;
46
47static void
48shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem,
49 int *nr_del)
50{
51 struct rb_node *node;
52 struct rb_node *tmp;
53 struct cifs_sid_id *psidid;
54
55 node = rb_first(root);
56 while (node) {
57 tmp = node;
58 node = rb_next(tmp);
59 psidid = rb_entry(tmp, struct cifs_sid_id, rbnode);
60 if (nr_to_scan == 0 || *nr_del == nr_to_scan)
61 ++(*nr_rem);
62 else {
63 if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE)
64 && psidid->refcount == 0) {
65 rb_erase(tmp, root);
66 ++(*nr_del);
67 } else
68 ++(*nr_rem);
69 }
70 }
71}
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050072
73/*
74 * Run idmap cache shrinker.
75 */
76static int
77cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
78{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050079 int nr_del = 0;
80 int nr_rem = 0;
81 struct rb_root *root;
82
83 root = &uidtree;
84 spin_lock(&siduidlock);
85 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
86 spin_unlock(&siduidlock);
87
88 root = &gidtree;
89 spin_lock(&sidgidlock);
90 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
91 spin_unlock(&sidgidlock);
92
93 return nr_rem;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050094}
95
96static struct shrinker cifs_shrinker = {
97 .shrink = cifs_idmap_shrinker,
98 .seeks = DEFAULT_SEEKS,
99};
100
101static int
102cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
103{
104 char *payload;
105
106 payload = kmalloc(datalen, GFP_KERNEL);
107 if (!payload)
108 return -ENOMEM;
109
110 memcpy(payload, data, datalen);
111 key->payload.data = payload;
112 return 0;
113}
114
115static inline void
116cifs_idmap_key_destroy(struct key *key)
117{
118 kfree(key->payload.data);
119}
120
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500121struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -0500122 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500123 .instantiate = cifs_idmap_key_instantiate,
124 .destroy = cifs_idmap_key_destroy,
125 .describe = user_describe,
126 .match = user_match,
127};
128
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500129static void
130sid_to_str(struct cifs_sid *sidptr, char *sidstr)
131{
132 int i;
133 unsigned long saval;
134 char *strptr;
135
136 strptr = sidstr;
137
138 sprintf(strptr, "%s", "S");
139 strptr = sidstr + strlen(sidstr);
140
141 sprintf(strptr, "-%d", sidptr->revision);
142 strptr = sidstr + strlen(sidstr);
143
144 for (i = 0; i < 6; ++i) {
145 if (sidptr->authority[i]) {
146 sprintf(strptr, "-%d", sidptr->authority[i]);
147 strptr = sidstr + strlen(sidstr);
148 }
149 }
150
151 for (i = 0; i < sidptr->num_subauth; ++i) {
152 saval = le32_to_cpu(sidptr->sub_auth[i]);
153 sprintf(strptr, "-%ld", saval);
154 strptr = sidstr + strlen(sidstr);
155 }
156}
157
158static void
159id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
160 struct cifs_sid_id **psidid, char *typestr)
161{
162 int rc;
163 char *strptr;
164 struct rb_node *node = root->rb_node;
165 struct rb_node *parent = NULL;
166 struct rb_node **linkto = &(root->rb_node);
167 struct cifs_sid_id *lsidid;
168
169 while (node) {
170 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
171 parent = node;
172 rc = compare_sids(sidptr, &((lsidid)->sid));
173 if (rc > 0) {
174 linkto = &(node->rb_left);
175 node = node->rb_left;
176 } else if (rc < 0) {
177 linkto = &(node->rb_right);
178 node = node->rb_right;
179 }
180 }
181
182 memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
183 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
184 (*psidid)->refcount = 0;
185
186 sprintf((*psidid)->sidstr, "%s", typestr);
187 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
188 sid_to_str(&(*psidid)->sid, strptr);
189
190 clear_bit(SID_ID_PENDING, &(*psidid)->state);
191 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
192
193 rb_link_node(&(*psidid)->rbnode, parent, linkto);
194 rb_insert_color(&(*psidid)->rbnode, root);
195}
196
197static struct cifs_sid_id *
198id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
199{
200 int rc;
201 struct rb_node *node = root->rb_node;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500202 struct cifs_sid_id *lsidid;
203
204 while (node) {
205 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500206 rc = compare_sids(sidptr, &((lsidid)->sid));
207 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500208 node = node->rb_left;
209 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500210 node = node->rb_right;
211 } else /* node found */
212 return lsidid;
213 }
214
215 return NULL;
216}
217
218static int
219sidid_pending_wait(void *unused)
220{
221 schedule();
222 return signal_pending(current) ? -ERESTARTSYS : 0;
223}
224
225static int
226sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
227 struct cifs_fattr *fattr, uint sidtype)
228{
229 int rc;
230 unsigned long cid;
231 struct key *idkey;
232 const struct cred *saved_cred;
233 struct cifs_sid_id *psidid, *npsidid;
234 struct rb_root *cidtree;
235 spinlock_t *cidlock;
236
237 if (sidtype == SIDOWNER) {
238 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
239 cidlock = &siduidlock;
240 cidtree = &uidtree;
241 } else if (sidtype == SIDGROUP) {
242 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
243 cidlock = &sidgidlock;
244 cidtree = &gidtree;
245 } else
246 return -ENOENT;
247
248 spin_lock(cidlock);
249 psidid = id_rb_search(cidtree, psid);
250
251 if (!psidid) { /* node does not exist, allocate one & attempt adding */
252 spin_unlock(cidlock);
253 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
254 if (!npsidid)
255 return -ENOMEM;
256
257 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
258 if (!npsidid->sidstr) {
259 kfree(npsidid);
260 return -ENOMEM;
261 }
262
263 spin_lock(cidlock);
264 psidid = id_rb_search(cidtree, psid);
265 if (psidid) { /* node happened to get inserted meanwhile */
266 ++psidid->refcount;
267 spin_unlock(cidlock);
268 kfree(npsidid->sidstr);
269 kfree(npsidid);
270 } else {
271 psidid = npsidid;
272 id_rb_insert(cidtree, psid, &psidid,
273 sidtype == SIDOWNER ? "os:" : "gs:");
274 ++psidid->refcount;
275 spin_unlock(cidlock);
276 }
277 } else {
278 ++psidid->refcount;
279 spin_unlock(cidlock);
280 }
281
282 /*
283 * If we are here, it is safe to access psidid and its fields
284 * since a reference was taken earlier while holding the spinlock.
285 * A reference on the node is put without holding the spinlock
286 * and it is OK to do so in this case, shrinker will not erase
287 * this node until all references are put and we do not access
288 * any fields of the node after a reference is put .
289 */
290 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
291 cid = psidid->id;
292 psidid->time = jiffies; /* update ts for accessing */
293 goto sid_to_id_out;
294 }
295
296 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
297 goto sid_to_id_out;
298
299 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
300 saved_cred = override_creds(root_cred);
301 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
302 if (IS_ERR(idkey))
303 cFYI(1, "%s: Can't map SID to an id", __func__);
304 else {
305 cid = *(unsigned long *)idkey->payload.value;
306 psidid->id = cid;
307 set_bit(SID_ID_MAPPED, &psidid->state);
308 key_put(idkey);
309 kfree(psidid->sidstr);
310 }
311 revert_creds(saved_cred);
312 psidid->time = jiffies; /* update ts for accessing */
313 clear_bit(SID_ID_PENDING, &psidid->state);
314 wake_up_bit(&psidid->state, SID_ID_PENDING);
315 } else {
316 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
317 sidid_pending_wait, TASK_INTERRUPTIBLE);
318 if (rc) {
319 cFYI(1, "%s: sidid_pending_wait interrupted %d",
320 __func__, rc);
321 --psidid->refcount; /* decremented without spinlock */
322 return rc;
323 }
324 if (test_bit(SID_ID_MAPPED, &psidid->state))
325 cid = psidid->id;
326 }
327
328sid_to_id_out:
329 --psidid->refcount; /* decremented without spinlock */
330 if (sidtype == SIDOWNER)
331 fattr->cf_uid = cid;
332 else
333 fattr->cf_gid = cid;
334
335 return 0;
336}
337
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500338int
339init_cifs_idmap(void)
340{
341 struct cred *cred;
342 struct key *keyring;
343 int ret;
344
345 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
346
347 /* create an override credential set with a special thread keyring in
348 * which requests are cached
349 *
350 * this is used to prevent malicious redirections from being installed
351 * with add_key().
352 */
353 cred = prepare_kernel_cred(NULL);
354 if (!cred)
355 return -ENOMEM;
356
357 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
358 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
359 KEY_USR_VIEW | KEY_USR_READ,
360 KEY_ALLOC_NOT_IN_QUOTA);
361 if (IS_ERR(keyring)) {
362 ret = PTR_ERR(keyring);
363 goto failed_put_cred;
364 }
365
366 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
367 if (ret < 0)
368 goto failed_put_key;
369
370 ret = register_key_type(&cifs_idmap_key_type);
371 if (ret < 0)
372 goto failed_put_key;
373
374 /* instruct request_key() to use this special keyring as a cache for
375 * the results it looks up */
376 cred->thread_keyring = keyring;
377 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
378 root_cred = cred;
379
380 spin_lock_init(&siduidlock);
381 uidtree = RB_ROOT;
382 spin_lock_init(&sidgidlock);
383 gidtree = RB_ROOT;
384
385 register_shrinker(&cifs_shrinker);
386
387 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
388 return 0;
389
390failed_put_key:
391 key_put(keyring);
392failed_put_cred:
393 put_cred(cred);
394 return ret;
395}
396
397void
398exit_cifs_idmap(void)
399{
400 key_revoke(root_cred->thread_keyring);
401 unregister_key_type(&cifs_idmap_key_type);
402 put_cred(root_cred);
403 unregister_shrinker(&cifs_shrinker);
404 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
405}
406
407void
408cifs_destroy_idmaptrees(void)
409{
410 struct rb_root *root;
411 struct rb_node *node;
412
413 root = &uidtree;
414 spin_lock(&siduidlock);
415 while ((node = rb_first(root)))
416 rb_erase(node, root);
417 spin_unlock(&siduidlock);
418
419 root = &gidtree;
420 spin_lock(&sidgidlock);
421 while ((node = rb_first(root)))
422 rb_erase(node, root);
423 spin_unlock(&sidgidlock);
424}
Steve French297647c2007-10-12 04:11:59 +0000425
Steve Frencha750e772007-10-17 22:50:39 +0000426/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
427 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000428int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000429{
430 int i;
431 int num_subauth, num_sat, num_saw;
432
433 if ((!ctsid) || (!cwsid))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500434 return 1;
Steve French297647c2007-10-12 04:11:59 +0000435
436 /* compare the revision */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500437 if (ctsid->revision != cwsid->revision) {
438 if (ctsid->revision > cwsid->revision)
439 return 1;
440 else
441 return -1;
442 }
Steve French297647c2007-10-12 04:11:59 +0000443
444 /* compare all of the six auth values */
445 for (i = 0; i < 6; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500446 if (ctsid->authority[i] != cwsid->authority[i]) {
447 if (ctsid->authority[i] > cwsid->authority[i])
448 return 1;
449 else
450 return -1;
451 }
Steve French297647c2007-10-12 04:11:59 +0000452 }
453
454 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000455 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000456 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000457 num_subauth = num_sat < num_saw ? num_sat : num_saw;
458 if (num_subauth) {
459 for (i = 0; i < num_subauth; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500460 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
Steve French383c5532011-05-27 15:19:12 +0000461 if (le32_to_cpu(ctsid->sub_auth[i]) >
462 le32_to_cpu(cwsid->sub_auth[i]))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500463 return 1;
464 else
465 return -1;
466 }
Steve French297647c2007-10-12 04:11:59 +0000467 }
468 }
469
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500470 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000471}
472
Steve French97837582007-12-31 07:47:21 +0000473
474/* copy ntsd, owner sid, and group sid from a security descriptor to another */
475static void copy_sec_desc(const struct cifs_ntsd *pntsd,
476 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
477{
478 int i;
479
480 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
481 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
482
483 /* copy security descriptor control portion */
484 pnntsd->revision = pntsd->revision;
485 pnntsd->type = pntsd->type;
486 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
487 pnntsd->sacloffset = 0;
488 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
489 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
490
491 /* copy owner sid */
492 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
493 le32_to_cpu(pntsd->osidoffset));
494 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
495
496 nowner_sid_ptr->revision = owner_sid_ptr->revision;
497 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
498 for (i = 0; i < 6; i++)
499 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
500 for (i = 0; i < 5; i++)
501 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
502
503 /* copy group sid */
504 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
505 le32_to_cpu(pntsd->gsidoffset));
506 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
507 sizeof(struct cifs_sid));
508
509 ngroup_sid_ptr->revision = group_sid_ptr->revision;
510 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
511 for (i = 0; i < 6; i++)
512 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
513 for (i = 0; i < 5; i++)
Shirish Pargaonkarb1910ad2008-07-24 14:53:20 +0000514 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
Steve French97837582007-12-31 07:47:21 +0000515
516 return;
517}
518
519
Steve French630f3f0c2007-10-25 21:17:17 +0000520/*
521 change posix mode to reflect permissions
522 pmode is the existing mode (we only want to overwrite part of this
523 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
524*/
Al Viro9b5e6852007-12-05 08:24:38 +0000525static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000526 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000527{
Al Viro9b5e6852007-12-05 08:24:38 +0000528 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000529 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000530 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000531 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000532 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000533 for the operation you are trying to perform for your user */
534
535 /* For deny ACEs we change the mask so that subsequent allow access
536 control entries do not turn on the bits we are denying */
537 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000538 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000539 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000540
Al Viro9b5e6852007-12-05 08:24:38 +0000541 if ((flags & GENERIC_WRITE) ||
542 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000543 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000544 if ((flags & GENERIC_READ) ||
545 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000546 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000547 if ((flags & GENERIC_EXECUTE) ||
548 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000549 *pbits_to_set &= ~S_IXUGO;
550 return;
551 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000552 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000553 return;
554 }
555 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000556
Al Viro9b5e6852007-12-05 08:24:38 +0000557 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000558 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000559 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000560 return;
561 }
Al Viro9b5e6852007-12-05 08:24:38 +0000562 if ((flags & GENERIC_WRITE) ||
563 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000564 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000565 if ((flags & GENERIC_READ) ||
566 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000567 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000568 if ((flags & GENERIC_EXECUTE) ||
569 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000570 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000571
Joe Perchesb6b38f72010-04-21 03:50:45 +0000572 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000573 return;
574}
575
Steve Frenchce06c9f2007-11-08 21:12:01 +0000576/*
577 Generate access flags to reflect permissions mode is the existing mode.
578 This function is called for every ACE in the DACL whose SID matches
579 with either owner or group or everyone.
580*/
581
582static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
583 __u32 *pace_flags)
584{
585 /* reset access mask */
586 *pace_flags = 0x0;
587
588 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
589 mode &= bits_to_use;
590
591 /* check for R/W/X UGO since we do not know whose flags
592 is this but we have cleared all the bits sans RWX for
593 either user or group or other as per bits_to_use */
594 if (mode & S_IRUGO)
595 *pace_flags |= SET_FILE_READ_RIGHTS;
596 if (mode & S_IWUGO)
597 *pace_flags |= SET_FILE_WRITE_RIGHTS;
598 if (mode & S_IXUGO)
599 *pace_flags |= SET_FILE_EXEC_RIGHTS;
600
Joe Perchesb6b38f72010-04-21 03:50:45 +0000601 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000602 return;
603}
604
Al Viro2b210ad2008-03-29 03:09:18 +0000605static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000606 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
607{
608 int i;
609 __u16 size = 0;
610 __u32 access_req = 0;
611
612 pntace->type = ACCESS_ALLOWED;
613 pntace->flags = 0x0;
614 mode_to_access_flags(nmode, bits, &access_req);
615 if (!access_req)
616 access_req = SET_MINIMUM_RIGHTS;
617 pntace->access_req = cpu_to_le32(access_req);
618
619 pntace->sid.revision = psid->revision;
620 pntace->sid.num_subauth = psid->num_subauth;
621 for (i = 0; i < 6; i++)
622 pntace->sid.authority[i] = psid->authority[i];
623 for (i = 0; i < psid->num_subauth; i++)
624 pntace->sid.sub_auth[i] = psid->sub_auth[i];
625
626 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
627 pntace->size = cpu_to_le16(size);
628
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000629 return size;
Steve French97837582007-12-31 07:47:21 +0000630}
631
Steve French297647c2007-10-12 04:11:59 +0000632
Steve French953f8682007-10-31 04:54:42 +0000633#ifdef CONFIG_CIFS_DEBUG2
634static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000635{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000636 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000637
638 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000639
Steve French44093ca2007-10-23 21:22:55 +0000640 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000642 return;
643 }
644
645 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000646 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000647 return;
Steve French44093ca2007-10-23 21:22:55 +0000648 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000649
Steve French44093ca2007-10-23 21:22:55 +0000650 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000651 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000652 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000653 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000654 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000655 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000656 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000657 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
658 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000659 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000660
Steve Frenchd12fd122007-10-03 19:43:19 +0000661 /* BB add length check to make sure that we do not have huge
662 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000663 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000664
Steve Frenchd12fd122007-10-03 19:43:19 +0000665 return;
666}
Steve French953f8682007-10-31 04:54:42 +0000667#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000668
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000669
Steve Frencha750e772007-10-17 22:50:39 +0000670static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000671 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400672 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000673{
674 int i;
675 int num_aces = 0;
676 int acl_size;
677 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000678 struct cifs_ace **ppace;
679
680 /* BB need to add parm so we can store the SID BB */
681
Steve French2b834572007-11-25 10:01:00 +0000682 if (!pdacl) {
683 /* no DACL in the security descriptor, set
684 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400685 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000686 return;
687 }
688
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000689 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000690 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000691 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000692 return;
693 }
694
Joe Perchesb6b38f72010-04-21 03:50:45 +0000695 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000696 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000698
Steve French7505e052007-11-01 18:03:01 +0000699 /* reset rwx permissions for user/group/other.
700 Also, if num_aces is 0 i.e. DACL has no ACEs,
701 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400702 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000703
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000704 acl_base = (char *)pdacl;
705 acl_size = sizeof(struct cifs_acl);
706
Steve Frenchadbc0352007-10-17 02:12:46 +0000707 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000708 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000709 umode_t user_mask = S_IRWXU;
710 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600711 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000712
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000713 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
714 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300715 if (!ppace) {
716 cERROR(1, "DACL memory allocation error");
717 return;
718 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000719
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000720 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000721 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000722#ifdef CONFIG_CIFS_DEBUG2
723 dump_ace(ppace[i], end_of_acl);
724#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500725 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000726 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000727 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400728 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000729 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500730 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000731 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000732 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400733 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000734 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500735 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000736 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000737 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400738 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000739 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500740 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600741 access_flags_to_mode(ppace[i]->access_req,
742 ppace[i]->type,
743 &fattr->cf_mode,
744 &other_mask);
745
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000746
Steve French44093ca2007-10-23 21:22:55 +0000747/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000748 (void *)ppace[i],
749 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000750
Steve French44093ca2007-10-23 21:22:55 +0000751 acl_base = (char *)ppace[i];
752 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000753 }
754
755 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000756 }
757
758 return;
759}
760
Steve Frenchbcb02032007-09-25 16:17:24 +0000761
Steve French97837582007-12-31 07:47:21 +0000762static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
763 struct cifs_sid *pgrpsid, __u64 nmode)
764{
Al Viro2b210ad2008-03-29 03:09:18 +0000765 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000766 struct cifs_acl *pnndacl;
767
768 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
769
770 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
771 pownersid, nmode, S_IRWXU);
772 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
773 pgrpsid, nmode, S_IRWXG);
774 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
775 &sid_everyone, nmode, S_IRWXO);
776
777 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000778 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000779
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000780 return 0;
Steve French97837582007-12-31 07:47:21 +0000781}
782
783
Steve Frenchbcb02032007-09-25 16:17:24 +0000784static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
785{
786 /* BB need to add parm so we can store the SID BB */
787
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000788 /* validate that we do not go past end of ACL - sid must be at least 8
789 bytes long (assuming no sub-auths - e.g. the null SID */
790 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000791 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000792 return -EINVAL;
793 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000794
Steve Frenchaf6f4612007-10-16 18:40:37 +0000795 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000796#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000797 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000798 cFYI(1, "SID revision %d num_auth %d",
799 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000800
Steve Frenchaf6f4612007-10-16 18:40:37 +0000801 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000802 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
803 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000804 }
805
Steve Frenchd12fd122007-10-03 19:43:19 +0000806 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000807 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000808 cFYI(1, "RID 0x%x",
809 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +0000810#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000811 }
812
Steve Frenchbcb02032007-09-25 16:17:24 +0000813 return 0;
814}
815
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000816
Steve Frenchbcb02032007-09-25 16:17:24 +0000817/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500818static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
819 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000820{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500821 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000822 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
823 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000824 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000825 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000826
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400827 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000828 return -EIO;
829
Steve Frenchbcb02032007-09-25 16:17:24 +0000830 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000831 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000832 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000833 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000834 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000835 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000836 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000837 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000838 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
839 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000840 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000841/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000842 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500843 if (rc) {
844 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000845 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500846 }
847 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
848 if (rc) {
849 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
850 return rc;
851 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000852
853 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500854 if (rc) {
855 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000856 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500857 }
858 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
859 if (rc) {
860 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
861 return rc;
862 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000863
Steve French7505e052007-11-01 18:03:01 +0000864 if (dacloffset)
865 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400866 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000867 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000868 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000869
Steve Frenchbcb02032007-09-25 16:17:24 +0000870/* cifscred->uid = owner_sid_ptr->rid;
871 cifscred->gid = group_sid_ptr->rid;
872 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000873 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000874 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000875 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000876
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500877 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000878}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000879
880
Steve French97837582007-12-31 07:47:21 +0000881/* Convert permission bits from mode to equivalent CIFS ACL */
882static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve Frenchcce246e2008-04-09 20:55:31 +0000883 struct inode *inode, __u64 nmode)
Steve French97837582007-12-31 07:47:21 +0000884{
885 int rc = 0;
886 __u32 dacloffset;
887 __u32 ndacloffset;
888 __u32 sidsoffset;
889 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
890 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
891 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
892
893 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000894 return -EIO;
Steve French97837582007-12-31 07:47:21 +0000895
896 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
897 le32_to_cpu(pntsd->osidoffset));
898 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
899 le32_to_cpu(pntsd->gsidoffset));
900
901 dacloffset = le32_to_cpu(pntsd->dacloffset);
902 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
903
904 ndacloffset = sizeof(struct cifs_ntsd);
905 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
906 ndacl_ptr->revision = dacl_ptr->revision;
907 ndacl_ptr->size = 0;
908 ndacl_ptr->num_aces = 0;
909
910 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
911
912 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
913
914 /* copy security descriptor control portion and owner and group sid */
915 copy_sec_desc(pntsd, pnntsd, sidsoffset);
916
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000917 return rc;
Steve French97837582007-12-31 07:47:21 +0000918}
919
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400920static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
921 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000922{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000923 struct cifs_ntsd *pntsd = NULL;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400924 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400925 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
926
927 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600928 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000929
930 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400931 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400932 FreeXid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000933
Jeff Layton7ffec372010-09-29 19:51:11 -0400934 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000935
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600936 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
937 if (rc)
938 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400939 return pntsd;
940}
941
942static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
943 const char *path, u32 *pacllen)
944{
945 struct cifs_ntsd *pntsd = NULL;
946 int oplock = 0;
947 int xid, rc;
948 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +0000949 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -0400950 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400951
Jeff Layton7ffec372010-09-29 19:51:11 -0400952 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600953 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -0400954
955 tcon = tlink_tcon(tlink);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400956 xid = GetXid();
957
Jeff Layton7ffec372010-09-29 19:51:11 -0400958 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400959 &fid, &oplock, NULL, cifs_sb->local_nls,
960 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600961 if (!rc) {
962 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
963 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000964 }
965
Jeff Layton7ffec372010-09-29 19:51:11 -0400966 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000967 FreeXid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600968
969 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
970 if (rc)
971 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +0000972 return pntsd;
973}
974
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400975/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -0600976struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400977 struct inode *inode, const char *path,
978 u32 *pacllen)
979{
980 struct cifs_ntsd *pntsd = NULL;
981 struct cifsFileInfo *open_file = NULL;
982
983 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -0400984 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400985 if (!open_file)
986 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
987
988 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -0400989 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400990 return pntsd;
991}
992
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400993static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
994 struct cifs_ntsd *pnntsd, u32 acllen)
Steve French97837582007-12-31 07:47:21 +0000995{
Christoph Hellwigb96d31a2009-05-27 09:37:33 -0400996 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400997 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
998
999 if (IS_ERR(tlink))
1000 return PTR_ERR(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001001
1002 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001003 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001004 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001005 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001006
Joe Perchesb6b38f72010-04-21 03:50:45 +00001007 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001008 return rc;
1009}
1010
1011static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
1012 struct cifs_ntsd *pnntsd, u32 acllen)
1013{
1014 int oplock = 0;
1015 int xid, rc;
Steve French97837582007-12-31 07:47:21 +00001016 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001017 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001018 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001019
Jeff Layton7ffec372010-09-29 19:51:11 -04001020 if (IS_ERR(tlink))
1021 return PTR_ERR(tlink);
1022
1023 tcon = tlink_tcon(tlink);
Steve French97837582007-12-31 07:47:21 +00001024 xid = GetXid();
1025
Jeff Layton7ffec372010-09-29 19:51:11 -04001026 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001027 &fid, &oplock, NULL, cifs_sb->local_nls,
1028 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1029 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001030 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001031 goto out;
Steve French97837582007-12-31 07:47:21 +00001032 }
1033
Jeff Layton7ffec372010-09-29 19:51:11 -04001034 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001035 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001036
Jeff Layton7ffec372010-09-29 19:51:11 -04001037 CIFSSMBClose(xid, tcon, fid);
1038out:
Steve French97837582007-12-31 07:47:21 +00001039 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001040 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001041 return rc;
1042}
Steve French97837582007-12-31 07:47:21 +00001043
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001044/* Set an ACL on the server */
Steve Frenchb73b9a42011-04-19 18:27:10 +00001045int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001046 struct inode *inode, const char *path)
1047{
1048 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1049 struct cifsFileInfo *open_file;
1050 int rc;
1051
Joe Perchesb6b38f72010-04-21 03:50:45 +00001052 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001053
Jeff Layton6508d902010-09-29 19:51:11 -04001054 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001055 if (!open_file)
1056 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
1057
1058 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001059 cifsFileInfo_put(open_file);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001060 return rc;
Steve French97837582007-12-31 07:47:21 +00001061}
1062
Steve French7505e052007-11-01 18:03:01 +00001063/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001064int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001065cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1066 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001067{
1068 struct cifs_ntsd *pntsd = NULL;
1069 u32 acllen = 0;
1070 int rc = 0;
1071
Joe Perchesb6b38f72010-04-21 03:50:45 +00001072 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001073
1074 if (pfid)
1075 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1076 else
1077 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001078
1079 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001080 if (IS_ERR(pntsd)) {
1081 rc = PTR_ERR(pntsd);
1082 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1083 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001084 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001085 kfree(pntsd);
1086 if (rc)
1087 cERROR(1, "parse sec desc failed rc = %d", rc);
1088 }
Steve French7505e052007-11-01 18:03:01 +00001089
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001090 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001091}
Steve French953f8682007-10-31 04:54:42 +00001092
Steve French7505e052007-11-01 18:03:01 +00001093/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06001094int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
Steve French953f8682007-10-31 04:54:42 +00001095{
1096 int rc = 0;
Steve Frenchcce246e2008-04-09 20:55:31 +00001097 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001098 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1099 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001100
Joe Perchesb6b38f72010-04-21 03:50:45 +00001101 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001102
1103 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001104 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +00001105
Steve French97837582007-12-31 07:47:21 +00001106 /* Add three ACEs for owner, group, everyone getting rid of
1107 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +00001108
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001109 if (IS_ERR(pntsd)) {
1110 rc = PTR_ERR(pntsd);
1111 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1112 } else {
Steve French97837582007-12-31 07:47:21 +00001113 /* allocate memory for the smb header,
1114 set security descriptor request security descriptor
1115 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +00001116
Steve Frenchcce246e2008-04-09 20:55:31 +00001117 secdesclen = secdesclen < DEFSECDESCLEN ?
1118 DEFSECDESCLEN : secdesclen;
1119 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +00001120 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001121 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +00001122 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001123 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +00001124 }
Steve French7505e052007-11-01 18:03:01 +00001125
Steve Frenchcce246e2008-04-09 20:55:31 +00001126 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
Steve French97837582007-12-31 07:47:21 +00001127
Joe Perchesb6b38f72010-04-21 03:50:45 +00001128 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001129
1130 if (!rc) {
1131 /* Set the security descriptor */
Steve Frenchcce246e2008-04-09 20:55:31 +00001132 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001133 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001134 }
1135
1136 kfree(pnntsd);
1137 kfree(pntsd);
1138 }
1139
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001140 return rc;
Steve French953f8682007-10-31 04:54:42 +00001141}