blob: a8a753c8fcd5cab3da970a71be7cdcb519506823 [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
170cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
171{
172 char *payload;
173
174 payload = kmalloc(datalen, GFP_KERNEL);
175 if (!payload)
176 return -ENOMEM;
177
178 memcpy(payload, data, datalen);
179 key->payload.data = payload;
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500180 key->datalen = 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
228id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
229 struct cifs_sid_id **psidid, char *typestr)
230{
231 int rc;
232 char *strptr;
233 struct rb_node *node = root->rb_node;
234 struct rb_node *parent = NULL;
235 struct rb_node **linkto = &(root->rb_node);
236 struct cifs_sid_id *lsidid;
237
238 while (node) {
239 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
240 parent = node;
241 rc = compare_sids(sidptr, &((lsidid)->sid));
242 if (rc > 0) {
243 linkto = &(node->rb_left);
244 node = node->rb_left;
245 } else if (rc < 0) {
246 linkto = &(node->rb_right);
247 node = node->rb_right;
248 }
249 }
250
251 memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
252 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
253 (*psidid)->refcount = 0;
254
255 sprintf((*psidid)->sidstr, "%s", typestr);
256 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
257 sid_to_str(&(*psidid)->sid, strptr);
258
259 clear_bit(SID_ID_PENDING, &(*psidid)->state);
260 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
261
262 rb_link_node(&(*psidid)->rbnode, parent, linkto);
263 rb_insert_color(&(*psidid)->rbnode, root);
264}
265
266static struct cifs_sid_id *
267id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
268{
269 int rc;
270 struct rb_node *node = root->rb_node;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500271 struct cifs_sid_id *lsidid;
272
273 while (node) {
274 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500275 rc = compare_sids(sidptr, &((lsidid)->sid));
276 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500277 node = node->rb_left;
278 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500279 node = node->rb_right;
280 } else /* node found */
281 return lsidid;
282 }
283
284 return NULL;
285}
286
287static int
288sidid_pending_wait(void *unused)
289{
290 schedule();
291 return signal_pending(current) ? -ERESTARTSYS : 0;
292}
293
294static int
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500295id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
296{
297 int rc = 0;
298 struct key *sidkey;
299 const struct cred *saved_cred;
300 struct cifs_sid *lsid;
301 struct cifs_sid_id *psidid, *npsidid;
302 struct rb_root *cidtree;
303 spinlock_t *cidlock;
304
305 if (sidtype == SIDOWNER) {
306 cidlock = &siduidlock;
307 cidtree = &uidtree;
308 } else if (sidtype == SIDGROUP) {
309 cidlock = &sidgidlock;
310 cidtree = &gidtree;
311 } else
312 return -EINVAL;
313
314 spin_lock(cidlock);
315 psidid = sid_rb_search(cidtree, cid);
316
317 if (!psidid) { /* node does not exist, allocate one & attempt adding */
318 spin_unlock(cidlock);
319 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
320 if (!npsidid)
321 return -ENOMEM;
322
323 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
324 if (!npsidid->sidstr) {
325 kfree(npsidid);
326 return -ENOMEM;
327 }
328
329 spin_lock(cidlock);
330 psidid = sid_rb_search(cidtree, cid);
331 if (psidid) { /* node happened to get inserted meanwhile */
332 ++psidid->refcount;
333 spin_unlock(cidlock);
334 kfree(npsidid->sidstr);
335 kfree(npsidid);
336 } else {
337 psidid = npsidid;
338 sid_rb_insert(cidtree, cid, &psidid,
339 sidtype == SIDOWNER ? "oi:" : "gi:");
340 ++psidid->refcount;
341 spin_unlock(cidlock);
342 }
343 } else {
344 ++psidid->refcount;
345 spin_unlock(cidlock);
346 }
347
348 /*
349 * If we are here, it is safe to access psidid and its fields
350 * since a reference was taken earlier while holding the spinlock.
351 * A reference on the node is put without holding the spinlock
352 * and it is OK to do so in this case, shrinker will not erase
353 * this node until all references are put and we do not access
354 * any fields of the node after a reference is put .
355 */
356 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
357 memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
358 psidid->time = jiffies; /* update ts for accessing */
359 goto id_sid_out;
360 }
361
362 if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
363 rc = -EINVAL;
364 goto id_sid_out;
365 }
366
367 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
368 saved_cred = override_creds(root_cred);
369 sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
370 if (IS_ERR(sidkey)) {
371 rc = -EINVAL;
372 cFYI(1, "%s: Can't map and id to a SID", __func__);
373 } else {
374 lsid = (struct cifs_sid *)sidkey->payload.data;
375 memcpy(&psidid->sid, lsid,
376 sidkey->datalen < sizeof(struct cifs_sid) ?
377 sidkey->datalen : sizeof(struct cifs_sid));
378 memcpy(ssid, &psidid->sid,
379 sidkey->datalen < sizeof(struct cifs_sid) ?
380 sidkey->datalen : sizeof(struct cifs_sid));
381 set_bit(SID_ID_MAPPED, &psidid->state);
382 key_put(sidkey);
383 kfree(psidid->sidstr);
384 }
385 psidid->time = jiffies; /* update ts for accessing */
386 revert_creds(saved_cred);
387 clear_bit(SID_ID_PENDING, &psidid->state);
388 wake_up_bit(&psidid->state, SID_ID_PENDING);
389 } else {
390 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
391 sidid_pending_wait, TASK_INTERRUPTIBLE);
392 if (rc) {
393 cFYI(1, "%s: sidid_pending_wait interrupted %d",
394 __func__, rc);
395 --psidid->refcount;
396 return rc;
397 }
398 if (test_bit(SID_ID_MAPPED, &psidid->state))
399 memcpy(ssid, &psidid->sid, sizeof(struct cifs_sid));
400 else
401 rc = -EINVAL;
402 }
403id_sid_out:
404 --psidid->refcount;
405 return rc;
406}
407
408static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500409sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
410 struct cifs_fattr *fattr, uint sidtype)
411{
412 int rc;
413 unsigned long cid;
414 struct key *idkey;
415 const struct cred *saved_cred;
416 struct cifs_sid_id *psidid, *npsidid;
417 struct rb_root *cidtree;
418 spinlock_t *cidlock;
419
420 if (sidtype == SIDOWNER) {
421 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
422 cidlock = &siduidlock;
423 cidtree = &uidtree;
424 } else if (sidtype == SIDGROUP) {
425 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
426 cidlock = &sidgidlock;
427 cidtree = &gidtree;
428 } else
429 return -ENOENT;
430
431 spin_lock(cidlock);
432 psidid = id_rb_search(cidtree, psid);
433
434 if (!psidid) { /* node does not exist, allocate one & attempt adding */
435 spin_unlock(cidlock);
436 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
437 if (!npsidid)
438 return -ENOMEM;
439
440 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
441 if (!npsidid->sidstr) {
442 kfree(npsidid);
443 return -ENOMEM;
444 }
445
446 spin_lock(cidlock);
447 psidid = id_rb_search(cidtree, psid);
448 if (psidid) { /* node happened to get inserted meanwhile */
449 ++psidid->refcount;
450 spin_unlock(cidlock);
451 kfree(npsidid->sidstr);
452 kfree(npsidid);
453 } else {
454 psidid = npsidid;
455 id_rb_insert(cidtree, psid, &psidid,
456 sidtype == SIDOWNER ? "os:" : "gs:");
457 ++psidid->refcount;
458 spin_unlock(cidlock);
459 }
460 } else {
461 ++psidid->refcount;
462 spin_unlock(cidlock);
463 }
464
465 /*
466 * If we are here, it is safe to access psidid and its fields
467 * since a reference was taken earlier while holding the spinlock.
468 * A reference on the node is put without holding the spinlock
469 * and it is OK to do so in this case, shrinker will not erase
470 * this node until all references are put and we do not access
471 * any fields of the node after a reference is put .
472 */
473 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
474 cid = psidid->id;
475 psidid->time = jiffies; /* update ts for accessing */
476 goto sid_to_id_out;
477 }
478
479 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
480 goto sid_to_id_out;
481
482 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
483 saved_cred = override_creds(root_cred);
484 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
485 if (IS_ERR(idkey))
486 cFYI(1, "%s: Can't map SID to an id", __func__);
487 else {
488 cid = *(unsigned long *)idkey->payload.value;
489 psidid->id = cid;
490 set_bit(SID_ID_MAPPED, &psidid->state);
491 key_put(idkey);
492 kfree(psidid->sidstr);
493 }
494 revert_creds(saved_cred);
495 psidid->time = jiffies; /* update ts for accessing */
496 clear_bit(SID_ID_PENDING, &psidid->state);
497 wake_up_bit(&psidid->state, SID_ID_PENDING);
498 } else {
499 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
500 sidid_pending_wait, TASK_INTERRUPTIBLE);
501 if (rc) {
502 cFYI(1, "%s: sidid_pending_wait interrupted %d",
503 __func__, rc);
504 --psidid->refcount; /* decremented without spinlock */
505 return rc;
506 }
507 if (test_bit(SID_ID_MAPPED, &psidid->state))
508 cid = psidid->id;
509 }
510
511sid_to_id_out:
512 --psidid->refcount; /* decremented without spinlock */
513 if (sidtype == SIDOWNER)
514 fattr->cf_uid = cid;
515 else
516 fattr->cf_gid = cid;
517
518 return 0;
519}
520
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500521int
522init_cifs_idmap(void)
523{
524 struct cred *cred;
525 struct key *keyring;
526 int ret;
527
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400528 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500529
530 /* create an override credential set with a special thread keyring in
531 * which requests are cached
532 *
533 * this is used to prevent malicious redirections from being installed
534 * with add_key().
535 */
536 cred = prepare_kernel_cred(NULL);
537 if (!cred)
538 return -ENOMEM;
539
David Howellsf8aa23a2012-10-02 19:24:56 +0100540 keyring = keyring_alloc(".cifs_idmap", 0, 0, cred,
541 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
542 KEY_USR_VIEW | KEY_USR_READ,
543 KEY_ALLOC_NOT_IN_QUOTA, NULL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500544 if (IS_ERR(keyring)) {
545 ret = PTR_ERR(keyring);
546 goto failed_put_cred;
547 }
548
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500549 ret = register_key_type(&cifs_idmap_key_type);
550 if (ret < 0)
551 goto failed_put_key;
552
553 /* instruct request_key() to use this special keyring as a cache for
554 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000555 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500556 cred->thread_keyring = keyring;
557 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
558 root_cred = cred;
559
560 spin_lock_init(&siduidlock);
561 uidtree = RB_ROOT;
562 spin_lock_init(&sidgidlock);
563 gidtree = RB_ROOT;
564
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500565 spin_lock_init(&uidsidlock);
566 siduidtree = RB_ROOT;
567 spin_lock_init(&gidsidlock);
568 sidgidtree = RB_ROOT;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500569 register_shrinker(&cifs_shrinker);
570
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400571 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500572 return 0;
573
574failed_put_key:
575 key_put(keyring);
576failed_put_cred:
577 put_cred(cred);
578 return ret;
579}
580
581void
582exit_cifs_idmap(void)
583{
584 key_revoke(root_cred->thread_keyring);
585 unregister_key_type(&cifs_idmap_key_type);
586 put_cred(root_cred);
587 unregister_shrinker(&cifs_shrinker);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400588 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500589}
590
591void
592cifs_destroy_idmaptrees(void)
593{
594 struct rb_root *root;
595 struct rb_node *node;
596
597 root = &uidtree;
598 spin_lock(&siduidlock);
599 while ((node = rb_first(root)))
600 rb_erase(node, root);
601 spin_unlock(&siduidlock);
602
603 root = &gidtree;
604 spin_lock(&sidgidlock);
605 while ((node = rb_first(root)))
606 rb_erase(node, root);
607 spin_unlock(&sidgidlock);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500608
609 root = &siduidtree;
610 spin_lock(&uidsidlock);
611 while ((node = rb_first(root)))
612 rb_erase(node, root);
613 spin_unlock(&uidsidlock);
614
615 root = &sidgidtree;
616 spin_lock(&gidsidlock);
617 while ((node = rb_first(root)))
618 rb_erase(node, root);
619 spin_unlock(&gidsidlock);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500620}
Steve French297647c2007-10-12 04:11:59 +0000621
Steve Frencha750e772007-10-17 22:50:39 +0000622/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
623 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000624int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000625{
626 int i;
627 int num_subauth, num_sat, num_saw;
628
629 if ((!ctsid) || (!cwsid))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500630 return 1;
Steve French297647c2007-10-12 04:11:59 +0000631
632 /* compare the revision */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500633 if (ctsid->revision != cwsid->revision) {
634 if (ctsid->revision > cwsid->revision)
635 return 1;
636 else
637 return -1;
638 }
Steve French297647c2007-10-12 04:11:59 +0000639
640 /* compare all of the six auth values */
641 for (i = 0; i < 6; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500642 if (ctsid->authority[i] != cwsid->authority[i]) {
643 if (ctsid->authority[i] > cwsid->authority[i])
644 return 1;
645 else
646 return -1;
647 }
Steve French297647c2007-10-12 04:11:59 +0000648 }
649
650 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000651 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000652 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000653 num_subauth = num_sat < num_saw ? num_sat : num_saw;
654 if (num_subauth) {
655 for (i = 0; i < num_subauth; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500656 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
Steve French383c5532011-05-27 15:19:12 +0000657 if (le32_to_cpu(ctsid->sub_auth[i]) >
658 le32_to_cpu(cwsid->sub_auth[i]))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500659 return 1;
660 else
661 return -1;
662 }
Steve French297647c2007-10-12 04:11:59 +0000663 }
664 }
665
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500666 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000667}
668
Steve French97837582007-12-31 07:47:21 +0000669
670/* copy ntsd, owner sid, and group sid from a security descriptor to another */
671static void copy_sec_desc(const struct cifs_ntsd *pntsd,
672 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
673{
674 int i;
675
676 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
677 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
678
679 /* copy security descriptor control portion */
680 pnntsd->revision = pntsd->revision;
681 pnntsd->type = pntsd->type;
682 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
683 pnntsd->sacloffset = 0;
684 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
685 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
686
687 /* copy owner sid */
688 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
689 le32_to_cpu(pntsd->osidoffset));
690 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
691
692 nowner_sid_ptr->revision = owner_sid_ptr->revision;
693 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
694 for (i = 0; i < 6; i++)
695 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
696 for (i = 0; i < 5; i++)
697 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
698
699 /* copy group sid */
700 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
701 le32_to_cpu(pntsd->gsidoffset));
702 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
703 sizeof(struct cifs_sid));
704
705 ngroup_sid_ptr->revision = group_sid_ptr->revision;
706 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
707 for (i = 0; i < 6; i++)
708 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
709 for (i = 0; i < 5; i++)
Shirish Pargaonkarb1910ad2008-07-24 14:53:20 +0000710 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
Steve French97837582007-12-31 07:47:21 +0000711
712 return;
713}
714
715
Steve French630f3f0c2007-10-25 21:17:17 +0000716/*
717 change posix mode to reflect permissions
718 pmode is the existing mode (we only want to overwrite part of this
719 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
720*/
Al Viro9b5e6852007-12-05 08:24:38 +0000721static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000722 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000723{
Al Viro9b5e6852007-12-05 08:24:38 +0000724 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000725 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000726 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000727 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000728 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000729 for the operation you are trying to perform for your user */
730
731 /* For deny ACEs we change the mask so that subsequent allow access
732 control entries do not turn on the bits we are denying */
733 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000734 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000735 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000736
Al Viro9b5e6852007-12-05 08:24:38 +0000737 if ((flags & GENERIC_WRITE) ||
738 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000739 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000740 if ((flags & GENERIC_READ) ||
741 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000742 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000743 if ((flags & GENERIC_EXECUTE) ||
744 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000745 *pbits_to_set &= ~S_IXUGO;
746 return;
747 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000748 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000749 return;
750 }
751 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000752
Al Viro9b5e6852007-12-05 08:24:38 +0000753 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000754 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000756 return;
757 }
Al Viro9b5e6852007-12-05 08:24:38 +0000758 if ((flags & GENERIC_WRITE) ||
759 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000760 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000761 if ((flags & GENERIC_READ) ||
762 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000763 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000764 if ((flags & GENERIC_EXECUTE) ||
765 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000766 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000767
Joe Perchesb6b38f72010-04-21 03:50:45 +0000768 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000769 return;
770}
771
Steve Frenchce06c9f2007-11-08 21:12:01 +0000772/*
773 Generate access flags to reflect permissions mode is the existing mode.
774 This function is called for every ACE in the DACL whose SID matches
775 with either owner or group or everyone.
776*/
777
778static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
779 __u32 *pace_flags)
780{
781 /* reset access mask */
782 *pace_flags = 0x0;
783
784 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
785 mode &= bits_to_use;
786
787 /* check for R/W/X UGO since we do not know whose flags
788 is this but we have cleared all the bits sans RWX for
789 either user or group or other as per bits_to_use */
790 if (mode & S_IRUGO)
791 *pace_flags |= SET_FILE_READ_RIGHTS;
792 if (mode & S_IWUGO)
793 *pace_flags |= SET_FILE_WRITE_RIGHTS;
794 if (mode & S_IXUGO)
795 *pace_flags |= SET_FILE_EXEC_RIGHTS;
796
Joe Perchesb6b38f72010-04-21 03:50:45 +0000797 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000798 return;
799}
800
Al Viro2b210ad2008-03-29 03:09:18 +0000801static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000802 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
803{
804 int i;
805 __u16 size = 0;
806 __u32 access_req = 0;
807
808 pntace->type = ACCESS_ALLOWED;
809 pntace->flags = 0x0;
810 mode_to_access_flags(nmode, bits, &access_req);
811 if (!access_req)
812 access_req = SET_MINIMUM_RIGHTS;
813 pntace->access_req = cpu_to_le32(access_req);
814
815 pntace->sid.revision = psid->revision;
816 pntace->sid.num_subauth = psid->num_subauth;
817 for (i = 0; i < 6; i++)
818 pntace->sid.authority[i] = psid->authority[i];
819 for (i = 0; i < psid->num_subauth; i++)
820 pntace->sid.sub_auth[i] = psid->sub_auth[i];
821
822 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
823 pntace->size = cpu_to_le16(size);
824
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000825 return size;
Steve French97837582007-12-31 07:47:21 +0000826}
827
Steve French297647c2007-10-12 04:11:59 +0000828
Steve French953f8682007-10-31 04:54:42 +0000829#ifdef CONFIG_CIFS_DEBUG2
830static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000831{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000832 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000833
834 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000835
Steve French44093ca2007-10-23 21:22:55 +0000836 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000837 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000838 return;
839 }
840
841 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000842 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000843 return;
Steve French44093ca2007-10-23 21:22:55 +0000844 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000845
Steve French44093ca2007-10-23 21:22:55 +0000846 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000847 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000848 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000849 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000850 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000851 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000852 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000853 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
854 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000855 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000856
Steve Frenchd12fd122007-10-03 19:43:19 +0000857 /* BB add length check to make sure that we do not have huge
858 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000859 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000860
Steve Frenchd12fd122007-10-03 19:43:19 +0000861 return;
862}
Steve French953f8682007-10-31 04:54:42 +0000863#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000864
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000865
Steve Frencha750e772007-10-17 22:50:39 +0000866static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000867 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400868 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000869{
870 int i;
871 int num_aces = 0;
872 int acl_size;
873 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000874 struct cifs_ace **ppace;
875
876 /* BB need to add parm so we can store the SID BB */
877
Steve French2b834572007-11-25 10:01:00 +0000878 if (!pdacl) {
879 /* no DACL in the security descriptor, set
880 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400881 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000882 return;
883 }
884
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000885 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000886 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000887 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000888 return;
889 }
890
Joe Perchesb6b38f72010-04-21 03:50:45 +0000891 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000892 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000893 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000894
Steve French7505e052007-11-01 18:03:01 +0000895 /* reset rwx permissions for user/group/other.
896 Also, if num_aces is 0 i.e. DACL has no ACEs,
897 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400898 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000899
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000900 acl_base = (char *)pdacl;
901 acl_size = sizeof(struct cifs_acl);
902
Steve Frenchadbc0352007-10-17 02:12:46 +0000903 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500904 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000905 umode_t user_mask = S_IRWXU;
906 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600907 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000908
Dan Carpenter72501702012-01-11 10:46:27 +0300909 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
910 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000911 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
912 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300913 if (!ppace) {
914 cERROR(1, "DACL memory allocation error");
915 return;
916 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000917
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000918 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000919 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000920#ifdef CONFIG_CIFS_DEBUG2
921 dump_ace(ppace[i], end_of_acl);
922#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500923 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000924 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000925 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400926 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000927 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500928 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000929 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000930 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400931 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000932 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500933 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000934 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000935 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400936 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000937 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500938 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600939 access_flags_to_mode(ppace[i]->access_req,
940 ppace[i]->type,
941 &fattr->cf_mode,
942 &other_mask);
943
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000944
Steve French44093ca2007-10-23 21:22:55 +0000945/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000946 (void *)ppace[i],
947 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000948
Steve French44093ca2007-10-23 21:22:55 +0000949 acl_base = (char *)ppace[i];
950 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000951 }
952
953 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000954 }
955
956 return;
957}
958
Steve Frenchbcb02032007-09-25 16:17:24 +0000959
Steve French97837582007-12-31 07:47:21 +0000960static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
961 struct cifs_sid *pgrpsid, __u64 nmode)
962{
Al Viro2b210ad2008-03-29 03:09:18 +0000963 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000964 struct cifs_acl *pnndacl;
965
966 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
967
968 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
969 pownersid, nmode, S_IRWXU);
970 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
971 pgrpsid, nmode, S_IRWXG);
972 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
973 &sid_everyone, nmode, S_IRWXO);
974
975 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000976 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000977
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000978 return 0;
Steve French97837582007-12-31 07:47:21 +0000979}
980
981
Steve Frenchbcb02032007-09-25 16:17:24 +0000982static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
983{
984 /* BB need to add parm so we can store the SID BB */
985
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000986 /* validate that we do not go past end of ACL - sid must be at least 8
987 bytes long (assuming no sub-auths - e.g. the null SID */
988 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000989 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000990 return -EINVAL;
991 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000992
Steve Frenchaf6f4612007-10-16 18:40:37 +0000993 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000994#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000995 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000996 cFYI(1, "SID revision %d num_auth %d",
997 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000998
Steve Frenchaf6f4612007-10-16 18:40:37 +0000999 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001000 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
1001 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001002 }
1003
Steve Frenchd12fd122007-10-03 19:43:19 +00001004 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001005 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001006 cFYI(1, "RID 0x%x",
1007 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +00001008#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001009 }
1010
Steve Frenchbcb02032007-09-25 16:17:24 +00001011 return 0;
1012}
1013
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001014
Steve Frenchbcb02032007-09-25 16:17:24 +00001015/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001016static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
1017 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +00001018{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001019 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001020 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1021 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001022 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001023 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001024
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001025 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001026 return -EIO;
1027
Steve Frenchbcb02032007-09-25 16:17:24 +00001028 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001029 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001030 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001031 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001032 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001033 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001034 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +00001035 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +00001036 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1037 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001038 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001039/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001040 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001041 if (rc) {
1042 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001043 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001044 }
1045 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1046 if (rc) {
1047 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
1048 return rc;
1049 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001050
1051 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001052 if (rc) {
1053 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001054 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001055 }
1056 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1057 if (rc) {
1058 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
1059 return rc;
1060 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001061
Steve French7505e052007-11-01 18:03:01 +00001062 if (dacloffset)
1063 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001064 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +00001065 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001066 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001067
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001068 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001069}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001070
Steve French97837582007-12-31 07:47:21 +00001071/* Convert permission bits from mode to equivalent CIFS ACL */
1072static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001073 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001074{
1075 int rc = 0;
1076 __u32 dacloffset;
1077 __u32 ndacloffset;
1078 __u32 sidsoffset;
1079 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001080 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001081 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1082 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1083
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001084 if (nmode != NO_CHANGE_64) { /* chmod */
1085 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001086 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001087 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001088 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001089 dacloffset = le32_to_cpu(pntsd->dacloffset);
1090 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1091 ndacloffset = sizeof(struct cifs_ntsd);
1092 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1093 ndacl_ptr->revision = dacl_ptr->revision;
1094 ndacl_ptr->size = 0;
1095 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001096
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001097 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1098 nmode);
1099 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1100 /* copy sec desc control portion & owner and group sids */
1101 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1102 *aclflag = CIFS_ACL_DACL;
1103 } else {
1104 memcpy(pnntsd, pntsd, secdesclen);
1105 if (uid != NO_CHANGE_32) { /* chown */
1106 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1107 le32_to_cpu(pnntsd->osidoffset));
1108 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1109 GFP_KERNEL);
1110 if (!nowner_sid_ptr)
1111 return -ENOMEM;
1112 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1113 if (rc) {
1114 cFYI(1, "%s: Mapping error %d for owner id %d",
1115 __func__, rc, uid);
1116 kfree(nowner_sid_ptr);
1117 return rc;
1118 }
1119 memcpy(owner_sid_ptr, nowner_sid_ptr,
1120 sizeof(struct cifs_sid));
1121 kfree(nowner_sid_ptr);
1122 *aclflag = CIFS_ACL_OWNER;
1123 }
1124 if (gid != NO_CHANGE_32) { /* chgrp */
1125 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1126 le32_to_cpu(pnntsd->gsidoffset));
1127 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1128 GFP_KERNEL);
1129 if (!ngroup_sid_ptr)
1130 return -ENOMEM;
1131 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
1132 if (rc) {
1133 cFYI(1, "%s: Mapping error %d for group id %d",
1134 __func__, rc, gid);
1135 kfree(ngroup_sid_ptr);
1136 return rc;
1137 }
1138 memcpy(group_sid_ptr, ngroup_sid_ptr,
1139 sizeof(struct cifs_sid));
1140 kfree(ngroup_sid_ptr);
1141 *aclflag = CIFS_ACL_GROUP;
1142 }
1143 }
Steve French97837582007-12-31 07:47:21 +00001144
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001145 return rc;
Steve French97837582007-12-31 07:47:21 +00001146}
1147
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001148static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1149 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001150{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001151 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001152 unsigned int xid;
1153 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001154 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1155
1156 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001157 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001158
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001159 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001160 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001161 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001162
Jeff Layton7ffec372010-09-29 19:51:11 -04001163 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001164
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001165 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1166 if (rc)
1167 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001168 return pntsd;
1169}
1170
1171static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1172 const char *path, u32 *pacllen)
1173{
1174 struct cifs_ntsd *pntsd = NULL;
1175 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001176 unsigned int xid;
1177 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001178 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001179 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001180 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001181
Jeff Layton7ffec372010-09-29 19:51:11 -04001182 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001183 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001184
1185 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001186 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001187
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001188 if (backup_cred(cifs_sb))
1189 create_options |= CREATE_OPEN_BACKUP_INTENT;
1190
1191 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
1192 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1193 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001194 if (!rc) {
1195 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1196 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001197 }
1198
Jeff Layton7ffec372010-09-29 19:51:11 -04001199 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001200 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001201
1202 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1203 if (rc)
1204 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001205 return pntsd;
1206}
1207
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001208/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001209struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001210 struct inode *inode, const char *path,
1211 u32 *pacllen)
1212{
1213 struct cifs_ntsd *pntsd = NULL;
1214 struct cifsFileInfo *open_file = NULL;
1215
1216 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001217 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001218 if (!open_file)
1219 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1220
1221 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001222 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001223 return pntsd;
1224}
1225
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001226 /* Set an ACL on the server */
1227int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1228 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001229{
1230 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001231 unsigned int xid;
1232 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +00001233 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001234 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001235 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001236 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001237
Jeff Layton7ffec372010-09-29 19:51:11 -04001238 if (IS_ERR(tlink))
1239 return PTR_ERR(tlink);
1240
1241 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001242 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001243
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001244 if (backup_cred(cifs_sb))
1245 create_options |= CREATE_OPEN_BACKUP_INTENT;
1246
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001247 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1248 access_flags = WRITE_OWNER;
1249 else
1250 access_flags = WRITE_DAC;
1251
1252 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1253 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1254 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001255 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001256 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001257 goto out;
Steve French97837582007-12-31 07:47:21 +00001258 }
1259
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001260 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001261 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001262
Jeff Layton7ffec372010-09-29 19:51:11 -04001263 CIFSSMBClose(xid, tcon, fid);
1264out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001265 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001266 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001267 return rc;
1268}
Steve French97837582007-12-31 07:47:21 +00001269
Steve French7505e052007-11-01 18:03:01 +00001270/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001271int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001272cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1273 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001274{
1275 struct cifs_ntsd *pntsd = NULL;
1276 u32 acllen = 0;
1277 int rc = 0;
1278
Joe Perchesb6b38f72010-04-21 03:50:45 +00001279 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001280
1281 if (pfid)
1282 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1283 else
1284 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001285
1286 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001287 if (IS_ERR(pntsd)) {
1288 rc = PTR_ERR(pntsd);
1289 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1290 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001291 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001292 kfree(pntsd);
1293 if (rc)
1294 cERROR(1, "parse sec desc failed rc = %d", rc);
1295 }
Steve French7505e052007-11-01 18:03:01 +00001296
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001297 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001298}
Steve French953f8682007-10-31 04:54:42 +00001299
Steve French7505e052007-11-01 18:03:01 +00001300/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001301int
1302id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1303 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001304{
1305 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001306 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001307 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001308 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1309 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001310
Joe Perchesb6b38f72010-04-21 03:50:45 +00001311 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001312
1313 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001314 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +00001315
Steve French97837582007-12-31 07:47:21 +00001316 /* Add three ACEs for owner, group, everyone getting rid of
1317 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +00001318
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001319 if (IS_ERR(pntsd)) {
1320 rc = PTR_ERR(pntsd);
1321 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1322 } else {
Steve French97837582007-12-31 07:47:21 +00001323 /* allocate memory for the smb header,
1324 set security descriptor request security descriptor
1325 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +00001326
Steve Frenchcce246e2008-04-09 20:55:31 +00001327 secdesclen = secdesclen < DEFSECDESCLEN ?
1328 DEFSECDESCLEN : secdesclen;
1329 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +00001330 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001331 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +00001332 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001333 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +00001334 }
Steve French7505e052007-11-01 18:03:01 +00001335
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001336 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1337 &aclflag);
Steve French97837582007-12-31 07:47:21 +00001338
Joe Perchesb6b38f72010-04-21 03:50:45 +00001339 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001340
1341 if (!rc) {
1342 /* Set the security descriptor */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001343 rc = set_cifs_acl(pnntsd, secdesclen, inode,
1344 path, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001345 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001346 }
1347
1348 kfree(pnntsd);
1349 kfree(pntsd);
1350 }
1351
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001352 return rc;
Steve French953f8682007-10-31 04:54:42 +00001353}