blob: 0fb15bbbe43cd955150336dec51b415ee1901c5a [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
Steve French8b1327f2008-03-14 22:37:16 +00004 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050026#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
Steve French65874002007-09-25 19:53:44 +000030#include "cifspdu.h"
31#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000032#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000033#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French65874002007-09-25 19:53:44 +000035
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060036/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000037static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060039/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
Steve French4f612582011-05-27 20:40:18 +000041 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
Steve Frenchbcb02032007-09-25 16:17:24 +000042/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000043static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000044
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
Al Viroef1d5752011-05-29 13:46:08 +010077cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050078{
Al Viroef1d5752011-05-29 13:46:08 +010079 int nr_to_scan = sc->nr_to_scan;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050080 int nr_del = 0;
81 int nr_rem = 0;
82 struct rb_root *root;
83
84 root = &uidtree;
85 spin_lock(&siduidlock);
86 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
87 spin_unlock(&siduidlock);
88
89 root = &gidtree;
90 spin_lock(&sidgidlock);
91 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
92 spin_unlock(&sidgidlock);
93
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -050094 root = &siduidtree;
95 spin_lock(&uidsidlock);
96 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
97 spin_unlock(&uidsidlock);
98
99 root = &sidgidtree;
100 spin_lock(&gidsidlock);
101 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
102 spin_unlock(&gidsidlock);
103
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500104 return nr_rem;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500105}
106
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500107static void
108sid_rb_insert(struct rb_root *root, unsigned long cid,
109 struct cifs_sid_id **psidid, char *typestr)
110{
111 char *strptr;
112 struct rb_node *node = root->rb_node;
113 struct rb_node *parent = NULL;
114 struct rb_node **linkto = &(root->rb_node);
115 struct cifs_sid_id *lsidid;
116
117 while (node) {
118 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
119 parent = node;
120 if (cid > lsidid->id) {
121 linkto = &(node->rb_left);
122 node = node->rb_left;
123 }
124 if (cid < lsidid->id) {
125 linkto = &(node->rb_right);
126 node = node->rb_right;
127 }
128 }
129
130 (*psidid)->id = cid;
131 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
132 (*psidid)->refcount = 0;
133
134 sprintf((*psidid)->sidstr, "%s", typestr);
135 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
136 sprintf(strptr, "%ld", cid);
137
138 clear_bit(SID_ID_PENDING, &(*psidid)->state);
139 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
140
141 rb_link_node(&(*psidid)->rbnode, parent, linkto);
142 rb_insert_color(&(*psidid)->rbnode, root);
143}
144
145static struct cifs_sid_id *
146sid_rb_search(struct rb_root *root, unsigned long cid)
147{
148 struct rb_node *node = root->rb_node;
149 struct cifs_sid_id *lsidid;
150
151 while (node) {
152 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
153 if (cid > lsidid->id)
154 node = node->rb_left;
155 else if (cid < lsidid->id)
156 node = node->rb_right;
157 else /* node found */
158 return lsidid;
159 }
160
161 return NULL;
162}
163
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500164static struct shrinker cifs_shrinker = {
165 .shrink = cifs_idmap_shrinker,
166 .seeks = DEFAULT_SEEKS,
167};
168
169static int
David Howellscf7f6012012-09-13 13:06:29 +0100170cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500171{
172 char *payload;
173
David Howellscf7f6012012-09-13 13:06:29 +0100174 payload = kmalloc(prep->datalen, GFP_KERNEL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500175 if (!payload)
176 return -ENOMEM;
177
David Howellscf7f6012012-09-13 13:06:29 +0100178 memcpy(payload, prep->data, prep->datalen);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500179 key->payload.data = payload;
David Howellscf7f6012012-09-13 13:06:29 +0100180 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500181 return 0;
182}
183
184static inline void
185cifs_idmap_key_destroy(struct key *key)
186{
187 kfree(key->payload.data);
188}
189
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500190struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -0500191 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500192 .instantiate = cifs_idmap_key_instantiate,
193 .destroy = cifs_idmap_key_destroy,
194 .describe = user_describe,
195 .match = user_match,
196};
197
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500198static void
199sid_to_str(struct cifs_sid *sidptr, char *sidstr)
200{
201 int i;
202 unsigned long saval;
203 char *strptr;
204
205 strptr = sidstr;
206
207 sprintf(strptr, "%s", "S");
208 strptr = sidstr + strlen(sidstr);
209
210 sprintf(strptr, "-%d", sidptr->revision);
211 strptr = sidstr + strlen(sidstr);
212
213 for (i = 0; i < 6; ++i) {
214 if (sidptr->authority[i]) {
215 sprintf(strptr, "-%d", sidptr->authority[i]);
216 strptr = sidstr + strlen(sidstr);
217 }
218 }
219
220 for (i = 0; i < sidptr->num_subauth; ++i) {
221 saval = le32_to_cpu(sidptr->sub_auth[i]);
222 sprintf(strptr, "-%ld", saval);
223 strptr = sidstr + strlen(sidstr);
224 }
225}
226
227static void
Jeff Layton36960e42012-11-03 09:37:28 -0400228cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
229{
230 memcpy(dst, src, sizeof(*dst));
231 dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS);
232}
233
234static void
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500235id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
236 struct cifs_sid_id **psidid, char *typestr)
237{
238 int rc;
239 char *strptr;
240 struct rb_node *node = root->rb_node;
241 struct rb_node *parent = NULL;
242 struct rb_node **linkto = &(root->rb_node);
243 struct cifs_sid_id *lsidid;
244
245 while (node) {
246 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
247 parent = node;
248 rc = compare_sids(sidptr, &((lsidid)->sid));
249 if (rc > 0) {
250 linkto = &(node->rb_left);
251 node = node->rb_left;
252 } else if (rc < 0) {
253 linkto = &(node->rb_right);
254 node = node->rb_right;
255 }
256 }
257
Jeff Layton36960e42012-11-03 09:37:28 -0400258 cifs_copy_sid(&(*psidid)->sid, sidptr);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500259 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
260 (*psidid)->refcount = 0;
261
262 sprintf((*psidid)->sidstr, "%s", typestr);
263 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
264 sid_to_str(&(*psidid)->sid, strptr);
265
266 clear_bit(SID_ID_PENDING, &(*psidid)->state);
267 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
268
269 rb_link_node(&(*psidid)->rbnode, parent, linkto);
270 rb_insert_color(&(*psidid)->rbnode, root);
271}
272
273static struct cifs_sid_id *
274id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
275{
276 int rc;
277 struct rb_node *node = root->rb_node;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500278 struct cifs_sid_id *lsidid;
279
280 while (node) {
281 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500282 rc = compare_sids(sidptr, &((lsidid)->sid));
283 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500284 node = node->rb_left;
285 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500286 node = node->rb_right;
287 } else /* node found */
288 return lsidid;
289 }
290
291 return NULL;
292}
293
294static int
295sidid_pending_wait(void *unused)
296{
297 schedule();
298 return signal_pending(current) ? -ERESTARTSYS : 0;
299}
300
301static int
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500302id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
303{
304 int rc = 0;
305 struct key *sidkey;
306 const struct cred *saved_cred;
307 struct cifs_sid *lsid;
308 struct cifs_sid_id *psidid, *npsidid;
309 struct rb_root *cidtree;
310 spinlock_t *cidlock;
311
312 if (sidtype == SIDOWNER) {
313 cidlock = &siduidlock;
314 cidtree = &uidtree;
315 } else if (sidtype == SIDGROUP) {
316 cidlock = &sidgidlock;
317 cidtree = &gidtree;
318 } else
319 return -EINVAL;
320
321 spin_lock(cidlock);
322 psidid = sid_rb_search(cidtree, cid);
323
324 if (!psidid) { /* node does not exist, allocate one & attempt adding */
325 spin_unlock(cidlock);
326 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
327 if (!npsidid)
328 return -ENOMEM;
329
330 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
331 if (!npsidid->sidstr) {
332 kfree(npsidid);
333 return -ENOMEM;
334 }
335
336 spin_lock(cidlock);
337 psidid = sid_rb_search(cidtree, cid);
338 if (psidid) { /* node happened to get inserted meanwhile */
339 ++psidid->refcount;
340 spin_unlock(cidlock);
341 kfree(npsidid->sidstr);
342 kfree(npsidid);
343 } else {
344 psidid = npsidid;
345 sid_rb_insert(cidtree, cid, &psidid,
346 sidtype == SIDOWNER ? "oi:" : "gi:");
347 ++psidid->refcount;
348 spin_unlock(cidlock);
349 }
350 } else {
351 ++psidid->refcount;
352 spin_unlock(cidlock);
353 }
354
355 /*
356 * If we are here, it is safe to access psidid and its fields
357 * since a reference was taken earlier while holding the spinlock.
358 * A reference on the node is put without holding the spinlock
359 * and it is OK to do so in this case, shrinker will not erase
360 * this node until all references are put and we do not access
361 * any fields of the node after a reference is put .
362 */
363 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
Jeff Layton36960e42012-11-03 09:37:28 -0400364 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500365 psidid->time = jiffies; /* update ts for accessing */
366 goto id_sid_out;
367 }
368
369 if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
370 rc = -EINVAL;
371 goto id_sid_out;
372 }
373
374 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
375 saved_cred = override_creds(root_cred);
376 sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
377 if (IS_ERR(sidkey)) {
378 rc = -EINVAL;
379 cFYI(1, "%s: Can't map and id to a SID", __func__);
Jeff Layton36960e42012-11-03 09:37:28 -0400380 } else if (sidkey->datalen < sizeof(struct cifs_sid)) {
381 rc = -EIO;
382 cFYI(1, "%s: Downcall contained malformed key "
383 "(datalen=%hu)", __func__, sidkey->datalen);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500384 } else {
385 lsid = (struct cifs_sid *)sidkey->payload.data;
Jeff Layton36960e42012-11-03 09:37:28 -0400386 cifs_copy_sid(&psidid->sid, lsid);
387 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500388 set_bit(SID_ID_MAPPED, &psidid->state);
389 key_put(sidkey);
390 kfree(psidid->sidstr);
391 }
392 psidid->time = jiffies; /* update ts for accessing */
393 revert_creds(saved_cred);
394 clear_bit(SID_ID_PENDING, &psidid->state);
395 wake_up_bit(&psidid->state, SID_ID_PENDING);
396 } else {
397 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
398 sidid_pending_wait, TASK_INTERRUPTIBLE);
399 if (rc) {
400 cFYI(1, "%s: sidid_pending_wait interrupted %d",
401 __func__, rc);
402 --psidid->refcount;
403 return rc;
404 }
405 if (test_bit(SID_ID_MAPPED, &psidid->state))
Jeff Layton36960e42012-11-03 09:37:28 -0400406 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500407 else
408 rc = -EINVAL;
409 }
410id_sid_out:
411 --psidid->refcount;
412 return rc;
413}
414
415static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500416sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
417 struct cifs_fattr *fattr, uint sidtype)
418{
419 int rc;
420 unsigned long cid;
421 struct key *idkey;
422 const struct cred *saved_cred;
423 struct cifs_sid_id *psidid, *npsidid;
424 struct rb_root *cidtree;
425 spinlock_t *cidlock;
426
427 if (sidtype == SIDOWNER) {
428 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
429 cidlock = &siduidlock;
430 cidtree = &uidtree;
431 } else if (sidtype == SIDGROUP) {
432 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
433 cidlock = &sidgidlock;
434 cidtree = &gidtree;
435 } else
436 return -ENOENT;
437
438 spin_lock(cidlock);
439 psidid = id_rb_search(cidtree, psid);
440
441 if (!psidid) { /* node does not exist, allocate one & attempt adding */
442 spin_unlock(cidlock);
443 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
444 if (!npsidid)
445 return -ENOMEM;
446
447 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
448 if (!npsidid->sidstr) {
449 kfree(npsidid);
450 return -ENOMEM;
451 }
452
453 spin_lock(cidlock);
454 psidid = id_rb_search(cidtree, psid);
455 if (psidid) { /* node happened to get inserted meanwhile */
456 ++psidid->refcount;
457 spin_unlock(cidlock);
458 kfree(npsidid->sidstr);
459 kfree(npsidid);
460 } else {
461 psidid = npsidid;
462 id_rb_insert(cidtree, psid, &psidid,
463 sidtype == SIDOWNER ? "os:" : "gs:");
464 ++psidid->refcount;
465 spin_unlock(cidlock);
466 }
467 } else {
468 ++psidid->refcount;
469 spin_unlock(cidlock);
470 }
471
472 /*
473 * If we are here, it is safe to access psidid and its fields
474 * since a reference was taken earlier while holding the spinlock.
475 * A reference on the node is put without holding the spinlock
476 * and it is OK to do so in this case, shrinker will not erase
477 * this node until all references are put and we do not access
478 * any fields of the node after a reference is put .
479 */
480 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
481 cid = psidid->id;
482 psidid->time = jiffies; /* update ts for accessing */
483 goto sid_to_id_out;
484 }
485
486 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
487 goto sid_to_id_out;
488
489 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
490 saved_cred = override_creds(root_cred);
491 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
492 if (IS_ERR(idkey))
493 cFYI(1, "%s: Can't map SID to an id", __func__);
494 else {
495 cid = *(unsigned long *)idkey->payload.value;
496 psidid->id = cid;
497 set_bit(SID_ID_MAPPED, &psidid->state);
498 key_put(idkey);
499 kfree(psidid->sidstr);
500 }
501 revert_creds(saved_cred);
502 psidid->time = jiffies; /* update ts for accessing */
503 clear_bit(SID_ID_PENDING, &psidid->state);
504 wake_up_bit(&psidid->state, SID_ID_PENDING);
505 } else {
506 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
507 sidid_pending_wait, TASK_INTERRUPTIBLE);
508 if (rc) {
509 cFYI(1, "%s: sidid_pending_wait interrupted %d",
510 __func__, rc);
511 --psidid->refcount; /* decremented without spinlock */
512 return rc;
513 }
514 if (test_bit(SID_ID_MAPPED, &psidid->state))
515 cid = psidid->id;
516 }
517
518sid_to_id_out:
519 --psidid->refcount; /* decremented without spinlock */
520 if (sidtype == SIDOWNER)
521 fattr->cf_uid = cid;
522 else
523 fattr->cf_gid = cid;
524
525 return 0;
526}
527
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500528int
529init_cifs_idmap(void)
530{
531 struct cred *cred;
532 struct key *keyring;
533 int ret;
534
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400535 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500536
537 /* create an override credential set with a special thread keyring in
538 * which requests are cached
539 *
540 * this is used to prevent malicious redirections from being installed
541 * with add_key().
542 */
543 cred = prepare_kernel_cred(NULL);
544 if (!cred)
545 return -ENOMEM;
546
547 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
548 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
549 KEY_USR_VIEW | KEY_USR_READ,
550 KEY_ALLOC_NOT_IN_QUOTA);
551 if (IS_ERR(keyring)) {
552 ret = PTR_ERR(keyring);
553 goto failed_put_cred;
554 }
555
556 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
557 if (ret < 0)
558 goto failed_put_key;
559
560 ret = register_key_type(&cifs_idmap_key_type);
561 if (ret < 0)
562 goto failed_put_key;
563
564 /* instruct request_key() to use this special keyring as a cache for
565 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000566 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500567 cred->thread_keyring = keyring;
568 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
569 root_cred = cred;
570
571 spin_lock_init(&siduidlock);
572 uidtree = RB_ROOT;
573 spin_lock_init(&sidgidlock);
574 gidtree = RB_ROOT;
575
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500576 spin_lock_init(&uidsidlock);
577 siduidtree = RB_ROOT;
578 spin_lock_init(&gidsidlock);
579 sidgidtree = RB_ROOT;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500580 register_shrinker(&cifs_shrinker);
581
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400582 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500583 return 0;
584
585failed_put_key:
586 key_put(keyring);
587failed_put_cred:
588 put_cred(cred);
589 return ret;
590}
591
592void
593exit_cifs_idmap(void)
594{
595 key_revoke(root_cred->thread_keyring);
596 unregister_key_type(&cifs_idmap_key_type);
597 put_cred(root_cred);
598 unregister_shrinker(&cifs_shrinker);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400599 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500600}
601
602void
603cifs_destroy_idmaptrees(void)
604{
605 struct rb_root *root;
606 struct rb_node *node;
607
608 root = &uidtree;
609 spin_lock(&siduidlock);
610 while ((node = rb_first(root)))
611 rb_erase(node, root);
612 spin_unlock(&siduidlock);
613
614 root = &gidtree;
615 spin_lock(&sidgidlock);
616 while ((node = rb_first(root)))
617 rb_erase(node, root);
618 spin_unlock(&sidgidlock);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500619
620 root = &siduidtree;
621 spin_lock(&uidsidlock);
622 while ((node = rb_first(root)))
623 rb_erase(node, root);
624 spin_unlock(&uidsidlock);
625
626 root = &sidgidtree;
627 spin_lock(&gidsidlock);
628 while ((node = rb_first(root)))
629 rb_erase(node, root);
630 spin_unlock(&gidsidlock);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500631}
Steve French297647c2007-10-12 04:11:59 +0000632
Steve Frencha750e772007-10-17 22:50:39 +0000633/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
634 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000635int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000636{
637 int i;
638 int num_subauth, num_sat, num_saw;
639
640 if ((!ctsid) || (!cwsid))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500641 return 1;
Steve French297647c2007-10-12 04:11:59 +0000642
643 /* compare the revision */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500644 if (ctsid->revision != cwsid->revision) {
645 if (ctsid->revision > cwsid->revision)
646 return 1;
647 else
648 return -1;
649 }
Steve French297647c2007-10-12 04:11:59 +0000650
651 /* compare all of the six auth values */
652 for (i = 0; i < 6; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500653 if (ctsid->authority[i] != cwsid->authority[i]) {
654 if (ctsid->authority[i] > cwsid->authority[i])
655 return 1;
656 else
657 return -1;
658 }
Steve French297647c2007-10-12 04:11:59 +0000659 }
660
661 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000662 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000663 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000664 num_subauth = num_sat < num_saw ? num_sat : num_saw;
665 if (num_subauth) {
666 for (i = 0; i < num_subauth; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500667 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
Steve French383c5532011-05-27 15:19:12 +0000668 if (le32_to_cpu(ctsid->sub_auth[i]) >
669 le32_to_cpu(cwsid->sub_auth[i]))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500670 return 1;
671 else
672 return -1;
673 }
Steve French297647c2007-10-12 04:11:59 +0000674 }
675 }
676
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500677 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000678}
679
Steve French97837582007-12-31 07:47:21 +0000680
681/* copy ntsd, owner sid, and group sid from a security descriptor to another */
682static void copy_sec_desc(const struct cifs_ntsd *pntsd,
683 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
684{
Steve French97837582007-12-31 07:47:21 +0000685 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
686 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
687
688 /* copy security descriptor control portion */
689 pnntsd->revision = pntsd->revision;
690 pnntsd->type = pntsd->type;
691 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
692 pnntsd->sacloffset = 0;
693 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
694 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
695
696 /* copy owner sid */
697 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
698 le32_to_cpu(pntsd->osidoffset));
699 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400700 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000701
702 /* copy group sid */
703 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
704 le32_to_cpu(pntsd->gsidoffset));
705 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
706 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400707 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000708
709 return;
710}
711
712
Steve French630f3f0c2007-10-25 21:17:17 +0000713/*
714 change posix mode to reflect permissions
715 pmode is the existing mode (we only want to overwrite part of this
716 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
717*/
Al Viro9b5e6852007-12-05 08:24:38 +0000718static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000719 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000720{
Al Viro9b5e6852007-12-05 08:24:38 +0000721 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000722 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000723 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000724 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000725 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000726 for the operation you are trying to perform for your user */
727
728 /* For deny ACEs we change the mask so that subsequent allow access
729 control entries do not turn on the bits we are denying */
730 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000731 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000732 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000733
Al Viro9b5e6852007-12-05 08:24:38 +0000734 if ((flags & GENERIC_WRITE) ||
735 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000736 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000737 if ((flags & GENERIC_READ) ||
738 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000739 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000740 if ((flags & GENERIC_EXECUTE) ||
741 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000742 *pbits_to_set &= ~S_IXUGO;
743 return;
744 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000745 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000746 return;
747 }
748 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000749
Al Viro9b5e6852007-12-05 08:24:38 +0000750 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000751 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000752 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000753 return;
754 }
Al Viro9b5e6852007-12-05 08:24:38 +0000755 if ((flags & GENERIC_WRITE) ||
756 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000757 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000758 if ((flags & GENERIC_READ) ||
759 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000760 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000761 if ((flags & GENERIC_EXECUTE) ||
762 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000763 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000764
Joe Perchesb6b38f72010-04-21 03:50:45 +0000765 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000766 return;
767}
768
Steve Frenchce06c9f2007-11-08 21:12:01 +0000769/*
770 Generate access flags to reflect permissions mode is the existing mode.
771 This function is called for every ACE in the DACL whose SID matches
772 with either owner or group or everyone.
773*/
774
775static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
776 __u32 *pace_flags)
777{
778 /* reset access mask */
779 *pace_flags = 0x0;
780
781 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
782 mode &= bits_to_use;
783
784 /* check for R/W/X UGO since we do not know whose flags
785 is this but we have cleared all the bits sans RWX for
786 either user or group or other as per bits_to_use */
787 if (mode & S_IRUGO)
788 *pace_flags |= SET_FILE_READ_RIGHTS;
789 if (mode & S_IWUGO)
790 *pace_flags |= SET_FILE_WRITE_RIGHTS;
791 if (mode & S_IXUGO)
792 *pace_flags |= SET_FILE_EXEC_RIGHTS;
793
Joe Perchesb6b38f72010-04-21 03:50:45 +0000794 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000795 return;
796}
797
Al Viro2b210ad2008-03-29 03:09:18 +0000798static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000799 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
800{
801 int i;
802 __u16 size = 0;
803 __u32 access_req = 0;
804
805 pntace->type = ACCESS_ALLOWED;
806 pntace->flags = 0x0;
807 mode_to_access_flags(nmode, bits, &access_req);
808 if (!access_req)
809 access_req = SET_MINIMUM_RIGHTS;
810 pntace->access_req = cpu_to_le32(access_req);
811
812 pntace->sid.revision = psid->revision;
813 pntace->sid.num_subauth = psid->num_subauth;
814 for (i = 0; i < 6; i++)
815 pntace->sid.authority[i] = psid->authority[i];
816 for (i = 0; i < psid->num_subauth; i++)
817 pntace->sid.sub_auth[i] = psid->sub_auth[i];
818
819 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
820 pntace->size = cpu_to_le16(size);
821
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000822 return size;
Steve French97837582007-12-31 07:47:21 +0000823}
824
Steve French297647c2007-10-12 04:11:59 +0000825
Steve French953f8682007-10-31 04:54:42 +0000826#ifdef CONFIG_CIFS_DEBUG2
827static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000828{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000829 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000830
831 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000832
Steve French44093ca2007-10-23 21:22:55 +0000833 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000834 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000835 return;
836 }
837
838 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000839 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000840 return;
Steve French44093ca2007-10-23 21:22:55 +0000841 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000842
Steve French44093ca2007-10-23 21:22:55 +0000843 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000844 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000845 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000846 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000847 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000848 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000849 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000850 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
851 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000852 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000853
Steve Frenchd12fd122007-10-03 19:43:19 +0000854 /* BB add length check to make sure that we do not have huge
855 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000856 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000857
Steve Frenchd12fd122007-10-03 19:43:19 +0000858 return;
859}
Steve French953f8682007-10-31 04:54:42 +0000860#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000861
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000862
Steve Frencha750e772007-10-17 22:50:39 +0000863static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000864 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400865 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000866{
867 int i;
868 int num_aces = 0;
869 int acl_size;
870 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000871 struct cifs_ace **ppace;
872
873 /* BB need to add parm so we can store the SID BB */
874
Steve French2b834572007-11-25 10:01:00 +0000875 if (!pdacl) {
876 /* no DACL in the security descriptor, set
877 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400878 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000879 return;
880 }
881
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000882 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000883 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000884 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000885 return;
886 }
887
Joe Perchesb6b38f72010-04-21 03:50:45 +0000888 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000889 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000890 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000891
Steve French7505e052007-11-01 18:03:01 +0000892 /* reset rwx permissions for user/group/other.
893 Also, if num_aces is 0 i.e. DACL has no ACEs,
894 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400895 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000896
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000897 acl_base = (char *)pdacl;
898 acl_size = sizeof(struct cifs_acl);
899
Steve Frenchadbc0352007-10-17 02:12:46 +0000900 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500901 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000902 umode_t user_mask = S_IRWXU;
903 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600904 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000905
Dan Carpenter72501702012-01-11 10:46:27 +0300906 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
907 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000908 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
909 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300910 if (!ppace) {
911 cERROR(1, "DACL memory allocation error");
912 return;
913 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000914
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000915 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000916 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000917#ifdef CONFIG_CIFS_DEBUG2
918 dump_ace(ppace[i], end_of_acl);
919#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500920 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000921 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000922 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400923 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000924 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500925 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000926 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000927 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400928 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000929 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500930 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000931 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000932 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400933 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000934 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500935 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600936 access_flags_to_mode(ppace[i]->access_req,
937 ppace[i]->type,
938 &fattr->cf_mode,
939 &other_mask);
940
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000941
Steve French44093ca2007-10-23 21:22:55 +0000942/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000943 (void *)ppace[i],
944 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000945
Steve French44093ca2007-10-23 21:22:55 +0000946 acl_base = (char *)ppace[i];
947 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000948 }
949
950 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000951 }
952
953 return;
954}
955
Steve Frenchbcb02032007-09-25 16:17:24 +0000956
Steve French97837582007-12-31 07:47:21 +0000957static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
958 struct cifs_sid *pgrpsid, __u64 nmode)
959{
Al Viro2b210ad2008-03-29 03:09:18 +0000960 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000961 struct cifs_acl *pnndacl;
962
963 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
964
965 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
966 pownersid, nmode, S_IRWXU);
967 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
968 pgrpsid, nmode, S_IRWXG);
969 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
970 &sid_everyone, nmode, S_IRWXO);
971
972 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000973 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000974
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000975 return 0;
Steve French97837582007-12-31 07:47:21 +0000976}
977
978
Steve Frenchbcb02032007-09-25 16:17:24 +0000979static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
980{
981 /* BB need to add parm so we can store the SID BB */
982
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000983 /* validate that we do not go past end of ACL - sid must be at least 8
984 bytes long (assuming no sub-auths - e.g. the null SID */
985 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000986 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000987 return -EINVAL;
988 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000989
Steve Frenchaf6f4612007-10-16 18:40:37 +0000990 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000991#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000992 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000993 cFYI(1, "SID revision %d num_auth %d",
994 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000995
Steve Frenchaf6f4612007-10-16 18:40:37 +0000996 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000997 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
998 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000999 }
1000
Steve Frenchd12fd122007-10-03 19:43:19 +00001001 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001002 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001003 cFYI(1, "RID 0x%x",
1004 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +00001005#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001006 }
1007
Steve Frenchbcb02032007-09-25 16:17:24 +00001008 return 0;
1009}
1010
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001011
Steve Frenchbcb02032007-09-25 16:17:24 +00001012/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001013static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
1014 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +00001015{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001016 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001017 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1018 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001019 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001020 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001021
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001022 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001023 return -EIO;
1024
Steve Frenchbcb02032007-09-25 16:17:24 +00001025 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001026 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001027 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001028 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001029 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001030 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001031 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +00001032 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +00001033 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1034 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001035 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001036/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001037 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001038 if (rc) {
1039 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001040 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001041 }
1042 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1043 if (rc) {
1044 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
1045 return rc;
1046 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001047
1048 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001049 if (rc) {
1050 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001051 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001052 }
1053 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1054 if (rc) {
1055 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
1056 return rc;
1057 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001058
Steve French7505e052007-11-01 18:03:01 +00001059 if (dacloffset)
1060 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001061 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +00001062 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001063 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001064
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001065 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001066}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001067
Steve French97837582007-12-31 07:47:21 +00001068/* Convert permission bits from mode to equivalent CIFS ACL */
1069static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001070 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001071{
1072 int rc = 0;
1073 __u32 dacloffset;
1074 __u32 ndacloffset;
1075 __u32 sidsoffset;
1076 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001077 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001078 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1079 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1080
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001081 if (nmode != NO_CHANGE_64) { /* chmod */
1082 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001083 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001084 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001085 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001086 dacloffset = le32_to_cpu(pntsd->dacloffset);
1087 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1088 ndacloffset = sizeof(struct cifs_ntsd);
1089 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1090 ndacl_ptr->revision = dacl_ptr->revision;
1091 ndacl_ptr->size = 0;
1092 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001093
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001094 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1095 nmode);
1096 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1097 /* copy sec desc control portion & owner and group sids */
1098 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1099 *aclflag = CIFS_ACL_DACL;
1100 } else {
1101 memcpy(pnntsd, pntsd, secdesclen);
1102 if (uid != NO_CHANGE_32) { /* chown */
1103 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1104 le32_to_cpu(pnntsd->osidoffset));
1105 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1106 GFP_KERNEL);
1107 if (!nowner_sid_ptr)
1108 return -ENOMEM;
1109 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1110 if (rc) {
1111 cFYI(1, "%s: Mapping error %d for owner id %d",
1112 __func__, rc, uid);
1113 kfree(nowner_sid_ptr);
1114 return rc;
1115 }
Jeff Layton36960e42012-11-03 09:37:28 -04001116 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001117 kfree(nowner_sid_ptr);
1118 *aclflag = CIFS_ACL_OWNER;
1119 }
1120 if (gid != NO_CHANGE_32) { /* chgrp */
1121 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1122 le32_to_cpu(pnntsd->gsidoffset));
1123 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1124 GFP_KERNEL);
1125 if (!ngroup_sid_ptr)
1126 return -ENOMEM;
1127 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
1128 if (rc) {
1129 cFYI(1, "%s: Mapping error %d for group id %d",
1130 __func__, rc, gid);
1131 kfree(ngroup_sid_ptr);
1132 return rc;
1133 }
Jeff Layton36960e42012-11-03 09:37:28 -04001134 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001135 kfree(ngroup_sid_ptr);
1136 *aclflag = CIFS_ACL_GROUP;
1137 }
1138 }
Steve French97837582007-12-31 07:47:21 +00001139
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001140 return rc;
Steve French97837582007-12-31 07:47:21 +00001141}
1142
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001143static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1144 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001145{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001146 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001147 unsigned int xid;
1148 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001149 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1150
1151 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001152 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001153
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001154 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001155 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001156 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001157
Jeff Layton7ffec372010-09-29 19:51:11 -04001158 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001159
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001160 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1161 if (rc)
1162 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001163 return pntsd;
1164}
1165
1166static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1167 const char *path, u32 *pacllen)
1168{
1169 struct cifs_ntsd *pntsd = NULL;
1170 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001171 unsigned int xid;
1172 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001173 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001174 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001175 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001176
Jeff Layton7ffec372010-09-29 19:51:11 -04001177 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001178 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001179
1180 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001181 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001182
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001183 if (backup_cred(cifs_sb))
1184 create_options |= CREATE_OPEN_BACKUP_INTENT;
1185
1186 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
1187 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1188 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001189 if (!rc) {
1190 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1191 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001192 }
1193
Jeff Layton7ffec372010-09-29 19:51:11 -04001194 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001195 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001196
1197 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1198 if (rc)
1199 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001200 return pntsd;
1201}
1202
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001203/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001204struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001205 struct inode *inode, const char *path,
1206 u32 *pacllen)
1207{
1208 struct cifs_ntsd *pntsd = NULL;
1209 struct cifsFileInfo *open_file = NULL;
1210
1211 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001212 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001213 if (!open_file)
1214 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1215
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001216 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001217 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001218 return pntsd;
1219}
1220
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001221 /* Set an ACL on the server */
1222int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1223 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001224{
1225 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001226 unsigned int xid;
1227 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +00001228 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001229 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001230 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001231 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001232
Jeff Layton7ffec372010-09-29 19:51:11 -04001233 if (IS_ERR(tlink))
1234 return PTR_ERR(tlink);
1235
1236 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001237 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001238
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001239 if (backup_cred(cifs_sb))
1240 create_options |= CREATE_OPEN_BACKUP_INTENT;
1241
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001242 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1243 access_flags = WRITE_OWNER;
1244 else
1245 access_flags = WRITE_DAC;
1246
1247 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1248 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1249 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001250 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001251 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001252 goto out;
Steve French97837582007-12-31 07:47:21 +00001253 }
1254
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001255 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001256 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001257
Jeff Layton7ffec372010-09-29 19:51:11 -04001258 CIFSSMBClose(xid, tcon, fid);
1259out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001260 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001261 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001262 return rc;
1263}
Steve French97837582007-12-31 07:47:21 +00001264
Steve French7505e052007-11-01 18:03:01 +00001265/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001266int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001267cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1268 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001269{
1270 struct cifs_ntsd *pntsd = NULL;
1271 u32 acllen = 0;
1272 int rc = 0;
1273
Joe Perchesb6b38f72010-04-21 03:50:45 +00001274 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001275
1276 if (pfid)
1277 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1278 else
1279 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001280
1281 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001282 if (IS_ERR(pntsd)) {
1283 rc = PTR_ERR(pntsd);
1284 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1285 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001286 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001287 kfree(pntsd);
1288 if (rc)
1289 cERROR(1, "parse sec desc failed rc = %d", rc);
1290 }
Steve French7505e052007-11-01 18:03:01 +00001291
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001292 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001293}
Steve French953f8682007-10-31 04:54:42 +00001294
Steve French7505e052007-11-01 18:03:01 +00001295/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001296int
1297id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1298 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001299{
1300 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001301 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001302 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001303 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1304 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001305
Joe Perchesb6b38f72010-04-21 03:50:45 +00001306 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001307
1308 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001309 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +00001310
Steve French97837582007-12-31 07:47:21 +00001311 /* Add three ACEs for owner, group, everyone getting rid of
1312 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +00001313
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001314 if (IS_ERR(pntsd)) {
1315 rc = PTR_ERR(pntsd);
1316 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1317 } else {
Steve French97837582007-12-31 07:47:21 +00001318 /* allocate memory for the smb header,
1319 set security descriptor request security descriptor
1320 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +00001321
Steve Frenchcce246e2008-04-09 20:55:31 +00001322 secdesclen = secdesclen < DEFSECDESCLEN ?
1323 DEFSECDESCLEN : secdesclen;
1324 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +00001325 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001326 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +00001327 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001328 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +00001329 }
Steve French7505e052007-11-01 18:03:01 +00001330
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001331 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1332 &aclflag);
Steve French97837582007-12-31 07:47:21 +00001333
Joe Perchesb6b38f72010-04-21 03:50:45 +00001334 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001335
1336 if (!rc) {
1337 /* Set the security descriptor */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001338 rc = set_cifs_acl(pnntsd, secdesclen, inode,
1339 path, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001340 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001341 }
1342
1343 kfree(pnntsd);
1344 kfree(pntsd);
1345 }
1346
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001347 return rc;
Steve French953f8682007-10-31 04:54:42 +00001348}