]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - fs/cifs/cifsacl.c
Merge tag 'please-pull-ia64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-zesty-kernel.git] / fs / cifs / cifsacl.c
CommitLineData
bcb02034
SF
1/*
2 * fs/cifs/cifsacl.c
3 *
8b1327f6 4 * Copyright (C) International Business Machines Corp., 2007,2008
bcb02034
SF
5 * 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
65874007 24#include <linux/fs.h>
5a0e3ad6 25#include <linux/slab.h>
4d79dba0
SP
26#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
65874007
SF
30#include "cifspdu.h"
31#include "cifsglob.h"
d0d66c44 32#include "cifsacl.h"
65874007
SF
33#include "cifsproto.h"
34#include "cifs_debug.h"
65874007 35
2fbc2f17 36/* security id for everyone/world system group */
e01b6400
SP
37static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
2fbc2f17
SP
39/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
4f61258f 41 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
bcb02034 42/* group users */
ad7a2926 43static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 44
9409ae58
SP
45const 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}
4d79dba0
SP
72
73/*
74 * Run idmap cache shrinker.
75 */
76static int
ef1d5759 77cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc)
4d79dba0 78{
ef1d5759 79 int nr_to_scan = sc->nr_to_scan;
9409ae58
SP
80 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
21fed0d5
SP
94 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
9409ae58 104 return nr_rem;
4d79dba0
SP
105}
106
21fed0d5
SP
107static 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
4d79dba0
SP
164static 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;
21fed0d5 180 key->datalen = datalen;
4d79dba0
SP
181 return 0;
182}
183
184static inline void
185cifs_idmap_key_destroy(struct key *key)
186{
187 kfree(key->payload.data);
188}
189
4d79dba0 190struct key_type cifs_idmap_key_type = {
c4aca0c0 191 .name = "cifs.idmap",
4d79dba0
SP
192 .instantiate = cifs_idmap_key_instantiate,
193 .destroy = cifs_idmap_key_destroy,
194 .describe = user_describe,
195 .match = user_match,
196};
197
9409ae58
SP
198static 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;
9409ae58
SP
271 struct cifs_sid_id *lsidid;
272
273 while (node) {
274 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
9409ae58
SP
275 rc = compare_sids(sidptr, &((lsidid)->sid));
276 if (rc > 0) {
9409ae58
SP
277 node = node->rb_left;
278 } else if (rc < 0) {
9409ae58
SP
279 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
21fed0d5
SP
294static int
295id_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
9409ae58
SP
408static int
409sid_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
4d79dba0
SP
521int
522init_cifs_idmap(void)
523{
524 struct cred *cred;
525 struct key *keyring;
526 int ret;
527
ac3aa2f8 528 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
4d79dba0
SP
529
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
540 keyring = key_alloc(&key_type_keyring, ".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);
544 if (IS_ERR(keyring)) {
545 ret = PTR_ERR(keyring);
546 goto failed_put_cred;
547 }
548
549 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
550 if (ret < 0)
551 goto failed_put_key;
552
553 ret = register_key_type(&cifs_idmap_key_type);
554 if (ret < 0)
555 goto failed_put_key;
556
557 /* instruct request_key() to use this special keyring as a cache for
558 * the results it looks up */
700920eb 559 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
4d79dba0
SP
560 cred->thread_keyring = keyring;
561 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
562 root_cred = cred;
563
564 spin_lock_init(&siduidlock);
565 uidtree = RB_ROOT;
566 spin_lock_init(&sidgidlock);
567 gidtree = RB_ROOT;
568
21fed0d5
SP
569 spin_lock_init(&uidsidlock);
570 siduidtree = RB_ROOT;
571 spin_lock_init(&gidsidlock);
572 sidgidtree = RB_ROOT;
4d79dba0
SP
573 register_shrinker(&cifs_shrinker);
574
ac3aa2f8 575 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
4d79dba0
SP
576 return 0;
577
578failed_put_key:
579 key_put(keyring);
580failed_put_cred:
581 put_cred(cred);
582 return ret;
583}
584
585void
586exit_cifs_idmap(void)
587{
588 key_revoke(root_cred->thread_keyring);
589 unregister_key_type(&cifs_idmap_key_type);
590 put_cred(root_cred);
591 unregister_shrinker(&cifs_shrinker);
ac3aa2f8 592 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
4d79dba0
SP
593}
594
595void
596cifs_destroy_idmaptrees(void)
597{
598 struct rb_root *root;
599 struct rb_node *node;
600
601 root = &uidtree;
602 spin_lock(&siduidlock);
603 while ((node = rb_first(root)))
604 rb_erase(node, root);
605 spin_unlock(&siduidlock);
606
607 root = &gidtree;
608 spin_lock(&sidgidlock);
609 while ((node = rb_first(root)))
610 rb_erase(node, root);
611 spin_unlock(&sidgidlock);
21fed0d5
SP
612
613 root = &siduidtree;
614 spin_lock(&uidsidlock);
615 while ((node = rb_first(root)))
616 rb_erase(node, root);
617 spin_unlock(&uidsidlock);
618
619 root = &sidgidtree;
620 spin_lock(&gidsidlock);
621 while ((node = rb_first(root)))
622 rb_erase(node, root);
623 spin_unlock(&gidsidlock);
4d79dba0 624}
297647c2 625
a750e77c
SF
626/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
627 the same returns 1, if they do not match returns 0 */
630f3f0c 628int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
297647c2
SF
629{
630 int i;
631 int num_subauth, num_sat, num_saw;
632
633 if ((!ctsid) || (!cwsid))
9409ae58 634 return 1;
297647c2
SF
635
636 /* compare the revision */
9409ae58
SP
637 if (ctsid->revision != cwsid->revision) {
638 if (ctsid->revision > cwsid->revision)
639 return 1;
640 else
641 return -1;
642 }
297647c2
SF
643
644 /* compare all of the six auth values */
645 for (i = 0; i < 6; ++i) {
9409ae58
SP
646 if (ctsid->authority[i] != cwsid->authority[i]) {
647 if (ctsid->authority[i] > cwsid->authority[i])
648 return 1;
649 else
650 return -1;
651 }
297647c2
SF
652 }
653
654 /* compare all of the subauth values if any */
adbc0358 655 num_sat = ctsid->num_subauth;
adddd49d 656 num_saw = cwsid->num_subauth;
297647c2
SF
657 num_subauth = num_sat < num_saw ? num_sat : num_saw;
658 if (num_subauth) {
659 for (i = 0; i < num_subauth; ++i) {
9409ae58 660 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
383c5535
SF
661 if (le32_to_cpu(ctsid->sub_auth[i]) >
662 le32_to_cpu(cwsid->sub_auth[i]))
9409ae58
SP
663 return 1;
664 else
665 return -1;
666 }
297647c2
SF
667 }
668 }
669
9409ae58 670 return 0; /* sids compare/match */
297647c2
SF
671}
672
97837582
SF
673
674/* copy ntsd, owner sid, and group sid from a security descriptor to another */
675static void copy_sec_desc(const struct cifs_ntsd *pntsd,
676 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
677{
678 int i;
679
680 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
681 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
682
683 /* copy security descriptor control portion */
684 pnntsd->revision = pntsd->revision;
685 pnntsd->type = pntsd->type;
686 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
687 pnntsd->sacloffset = 0;
688 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
689 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
690
691 /* copy owner sid */
692 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
693 le32_to_cpu(pntsd->osidoffset));
694 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
695
696 nowner_sid_ptr->revision = owner_sid_ptr->revision;
697 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
698 for (i = 0; i < 6; i++)
699 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
700 for (i = 0; i < 5; i++)
701 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
702
703 /* copy group sid */
704 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
705 le32_to_cpu(pntsd->gsidoffset));
706 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
707 sizeof(struct cifs_sid));
708
709 ngroup_sid_ptr->revision = group_sid_ptr->revision;
710 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
711 for (i = 0; i < 6; i++)
712 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
713 for (i = 0; i < 5; i++)
b1910ad6 714 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
97837582
SF
715
716 return;
717}
718
719
630f3f0c
SF
720/*
721 change posix mode to reflect permissions
722 pmode is the existing mode (we only want to overwrite part of this
723 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
724*/
9b5e6857 725static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
15b03959 726 umode_t *pbits_to_set)
630f3f0c 727{
9b5e6857 728 __u32 flags = le32_to_cpu(ace_flags);
15b03959 729 /* the order of ACEs is important. The canonical order is to begin with
ce06c9f0 730 DENY entries followed by ALLOW, otherwise an allow entry could be
15b03959 731 encountered first, making the subsequent deny entry like "dead code"
ce06c9f0 732 which would be superflous since Windows stops when a match is made
15b03959
SF
733 for the operation you are trying to perform for your user */
734
735 /* For deny ACEs we change the mask so that subsequent allow access
736 control entries do not turn on the bits we are denying */
737 if (type == ACCESS_DENIED) {
ad7a2926 738 if (flags & GENERIC_ALL)
15b03959 739 *pbits_to_set &= ~S_IRWXUGO;
ad7a2926 740
9b5e6857
AV
741 if ((flags & GENERIC_WRITE) ||
742 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 743 *pbits_to_set &= ~S_IWUGO;
9b5e6857
AV
744 if ((flags & GENERIC_READ) ||
745 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 746 *pbits_to_set &= ~S_IRUGO;
9b5e6857
AV
747 if ((flags & GENERIC_EXECUTE) ||
748 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959
SF
749 *pbits_to_set &= ~S_IXUGO;
750 return;
751 } else if (type != ACCESS_ALLOWED) {
b6b38f70 752 cERROR(1, "unknown access control type %d", type);
15b03959
SF
753 return;
754 }
755 /* else ACCESS_ALLOWED type */
630f3f0c 756
9b5e6857 757 if (flags & GENERIC_ALL) {
15b03959 758 *pmode |= (S_IRWXUGO & (*pbits_to_set));
b6b38f70 759 cFYI(DBG2, "all perms");
d61e5808
SF
760 return;
761 }
9b5e6857
AV
762 if ((flags & GENERIC_WRITE) ||
763 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 764 *pmode |= (S_IWUGO & (*pbits_to_set));
9b5e6857
AV
765 if ((flags & GENERIC_READ) ||
766 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 767 *pmode |= (S_IRUGO & (*pbits_to_set));
9b5e6857
AV
768 if ((flags & GENERIC_EXECUTE) ||
769 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 770 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 771
b6b38f70 772 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
630f3f0c
SF
773 return;
774}
775
ce06c9f0
SF
776/*
777 Generate access flags to reflect permissions mode is the existing mode.
778 This function is called for every ACE in the DACL whose SID matches
779 with either owner or group or everyone.
780*/
781
782static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
783 __u32 *pace_flags)
784{
785 /* reset access mask */
786 *pace_flags = 0x0;
787
788 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
789 mode &= bits_to_use;
790
791 /* check for R/W/X UGO since we do not know whose flags
792 is this but we have cleared all the bits sans RWX for
793 either user or group or other as per bits_to_use */
794 if (mode & S_IRUGO)
795 *pace_flags |= SET_FILE_READ_RIGHTS;
796 if (mode & S_IWUGO)
797 *pace_flags |= SET_FILE_WRITE_RIGHTS;
798 if (mode & S_IXUGO)
799 *pace_flags |= SET_FILE_EXEC_RIGHTS;
800
b6b38f70 801 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
ce06c9f0
SF
802 return;
803}
804
2b210adc 805static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
97837582
SF
806 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
807{
808 int i;
809 __u16 size = 0;
810 __u32 access_req = 0;
811
812 pntace->type = ACCESS_ALLOWED;
813 pntace->flags = 0x0;
814 mode_to_access_flags(nmode, bits, &access_req);
815 if (!access_req)
816 access_req = SET_MINIMUM_RIGHTS;
817 pntace->access_req = cpu_to_le32(access_req);
818
819 pntace->sid.revision = psid->revision;
820 pntace->sid.num_subauth = psid->num_subauth;
821 for (i = 0; i < 6; i++)
822 pntace->sid.authority[i] = psid->authority[i];
823 for (i = 0; i < psid->num_subauth; i++)
824 pntace->sid.sub_auth[i] = psid->sub_auth[i];
825
826 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
827 pntace->size = cpu_to_le16(size);
828
ef571cad 829 return size;
97837582
SF
830}
831
297647c2 832
953f8681
SF
833#ifdef CONFIG_CIFS_DEBUG2
834static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 835{
d0d66c44 836 int num_subauth;
d0d66c44
SP
837
838 /* validate that we do not go past end of acl */
297647c2 839
44093ca2 840 if (le16_to_cpu(pace->size) < 16) {
b6b38f70 841 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
44093ca2
SF
842 return;
843 }
844
845 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
b6b38f70 846 cERROR(1, "ACL too small to parse ACE");
d0d66c44 847 return;
44093ca2 848 }
d0d66c44 849
44093ca2 850 num_subauth = pace->sid.num_subauth;
d0d66c44 851 if (num_subauth) {
8f18c131 852 int i;
b6b38f70 853 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
44093ca2 854 pace->sid.revision, pace->sid.num_subauth, pace->type,
b6b38f70 855 pace->flags, le16_to_cpu(pace->size));
d12fd121 856 for (i = 0; i < num_subauth; ++i) {
b6b38f70
JP
857 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
858 le32_to_cpu(pace->sid.sub_auth[i]));
d12fd121
SF
859 }
860
861 /* BB add length check to make sure that we do not have huge
862 num auths and therefore go off the end */
d12fd121
SF
863 }
864
865 return;
866}
953f8681 867#endif
d12fd121 868
d0d66c44 869
a750e77c 870static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 871 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
0b8f18e3 872 struct cifs_fattr *fattr)
d0d66c44
SP
873{
874 int i;
875 int num_aces = 0;
876 int acl_size;
877 char *acl_base;
d0d66c44
SP
878 struct cifs_ace **ppace;
879
880 /* BB need to add parm so we can store the SID BB */
881
2b83457b
SF
882 if (!pdacl) {
883 /* no DACL in the security descriptor, set
884 all the permissions for user/group/other */
0b8f18e3 885 fattr->cf_mode |= S_IRWXUGO;
2b83457b
SF
886 return;
887 }
888
d0d66c44 889 /* validate that we do not go past end of acl */
af6f4612 890 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
b6b38f70 891 cERROR(1, "ACL too small to parse DACL");
d0d66c44
SP
892 return;
893 }
894
b6b38f70 895 cFYI(DBG2, "DACL revision %d size %d num aces %d",
af6f4612 896 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
b6b38f70 897 le32_to_cpu(pdacl->num_aces));
d0d66c44 898
7505e052
SF
899 /* reset rwx permissions for user/group/other.
900 Also, if num_aces is 0 i.e. DACL has no ACEs,
901 user/group/other have no permissions */
0b8f18e3 902 fattr->cf_mode &= ~(S_IRWXUGO);
7505e052 903
d0d66c44
SP
904 acl_base = (char *)pdacl;
905 acl_size = sizeof(struct cifs_acl);
906
adbc0358 907 num_aces = le32_to_cpu(pdacl->num_aces);
a5ff3769 908 if (num_aces > 0) {
15b03959
SF
909 umode_t user_mask = S_IRWXU;
910 umode_t group_mask = S_IRWXG;
2fbc2f17 911 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
15b03959 912
7250170c
DC
913 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
914 return;
d0d66c44
SP
915 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
916 GFP_KERNEL);
8132b65b
SF
917 if (!ppace) {
918 cERROR(1, "DACL memory allocation error");
919 return;
920 }
d0d66c44 921
d0d66c44 922 for (i = 0; i < num_aces; ++i) {
44093ca2 923 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
924#ifdef CONFIG_CIFS_DEBUG2
925 dump_ace(ppace[i], end_of_acl);
926#endif
9409ae58 927 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
e01b6400 928 access_flags_to_mode(ppace[i]->access_req,
15b03959 929 ppace[i]->type,
0b8f18e3 930 &fattr->cf_mode,
15b03959 931 &user_mask);
9409ae58 932 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
e01b6400 933 access_flags_to_mode(ppace[i]->access_req,
15b03959 934 ppace[i]->type,
0b8f18e3 935 &fattr->cf_mode,
15b03959 936 &group_mask);
9409ae58 937 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
e01b6400 938 access_flags_to_mode(ppace[i]->access_req,
15b03959 939 ppace[i]->type,
0b8f18e3 940 &fattr->cf_mode,
15b03959 941 &other_mask);
9409ae58 942 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
2fbc2f17
SP
943 access_flags_to_mode(ppace[i]->access_req,
944 ppace[i]->type,
945 &fattr->cf_mode,
946 &other_mask);
947
e01b6400 948
44093ca2 949/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
950 (void *)ppace[i],
951 sizeof(struct cifs_ace)); */
d0d66c44 952
44093ca2
SF
953 acl_base = (char *)ppace[i];
954 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
955 }
956
957 kfree(ppace);
d0d66c44
SP
958 }
959
960 return;
961}
962
bcb02034 963
97837582
SF
964static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
965 struct cifs_sid *pgrpsid, __u64 nmode)
966{
2b210adc 967 u16 size = 0;
97837582
SF
968 struct cifs_acl *pnndacl;
969
970 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
971
972 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
973 pownersid, nmode, S_IRWXU);
974 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
975 pgrpsid, nmode, S_IRWXG);
976 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
977 &sid_everyone, nmode, S_IRWXO);
978
979 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
d9f382ef 980 pndacl->num_aces = cpu_to_le32(3);
97837582 981
ef571cad 982 return 0;
97837582
SF
983}
984
985
bcb02034
SF
986static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
987{
988 /* BB need to add parm so we can store the SID BB */
989
b9c7a2bb
SF
990 /* validate that we do not go past end of ACL - sid must be at least 8
991 bytes long (assuming no sub-auths - e.g. the null SID */
992 if (end_of_acl < (char *)psid + 8) {
b6b38f70 993 cERROR(1, "ACL too small to parse SID %p", psid);
bcb02034
SF
994 return -EINVAL;
995 }
d0d66c44 996
af6f4612 997 if (psid->num_subauth) {
bcb02034 998#ifdef CONFIG_CIFS_DEBUG2
8f18c131 999 int i;
b6b38f70
JP
1000 cFYI(1, "SID revision %d num_auth %d",
1001 psid->revision, psid->num_subauth);
bcb02034 1002
af6f4612 1003 for (i = 0; i < psid->num_subauth; i++) {
b6b38f70
JP
1004 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
1005 le32_to_cpu(psid->sub_auth[i]));
d0d66c44
SP
1006 }
1007
d12fd121 1008 /* BB add length check to make sure that we do not have huge
d0d66c44 1009 num auths and therefore go off the end */
b6b38f70
JP
1010 cFYI(1, "RID 0x%x",
1011 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
bcb02034 1012#endif
d0d66c44
SP
1013 }
1014
bcb02034
SF
1015 return 0;
1016}
1017
d0d66c44 1018
bcb02034 1019/* Convert CIFS ACL to POSIX form */
9409ae58
SP
1020static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
1021 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
bcb02034 1022{
9409ae58 1023 int rc = 0;
bcb02034
SF
1024 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1025 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 1026 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 1027 __u32 dacloffset;
bcb02034 1028
0b8f18e3 1029 if (pntsd == NULL)
b9c7a2bb
SF
1030 return -EIO;
1031
bcb02034 1032 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 1033 le32_to_cpu(pntsd->osidoffset));
bcb02034 1034 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 1035 le32_to_cpu(pntsd->gsidoffset));
7505e052 1036 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 1037 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
b6b38f70 1038 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
bcb02034 1039 "sacloffset 0x%x dacloffset 0x%x",
af6f4612
SF
1040 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1041 le32_to_cpu(pntsd->gsidoffset),
b6b38f70 1042 le32_to_cpu(pntsd->sacloffset), dacloffset);
b9c7a2bb 1043/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034 1044 rc = parse_sid(owner_sid_ptr, end_of_acl);
9409ae58
SP
1045 if (rc) {
1046 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
1047 return rc;
1048 }
1049 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1050 if (rc) {
1051 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
bcb02034 1052 return rc;
9409ae58 1053 }
bcb02034
SF
1054
1055 rc = parse_sid(group_sid_ptr, end_of_acl);
9409ae58
SP
1056 if (rc) {
1057 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
bcb02034 1058 return rc;
9409ae58
SP
1059 }
1060 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1061 if (rc) {
1062 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
1063 return rc;
1064 }
bcb02034 1065
7505e052
SF
1066 if (dacloffset)
1067 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
0b8f18e3 1068 group_sid_ptr, fattr);
7505e052 1069 else
b6b38f70 1070 cFYI(1, "no ACL"); /* BB grant all or default perms? */
d0d66c44 1071
9409ae58 1072 return rc;
bcb02034 1073}
b9c7a2bb 1074
97837582
SF
1075/* Convert permission bits from mode to equivalent CIFS ACL */
1076static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
a5ff3769 1077 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
97837582
SF
1078{
1079 int rc = 0;
1080 __u32 dacloffset;
1081 __u32 ndacloffset;
1082 __u32 sidsoffset;
1083 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
a5ff3769 1084 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
97837582
SF
1085 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1086 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1087
a5ff3769
SP
1088 if (nmode != NO_CHANGE_64) { /* chmod */
1089 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
97837582 1090 le32_to_cpu(pntsd->osidoffset));
a5ff3769 1091 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
97837582 1092 le32_to_cpu(pntsd->gsidoffset));
a5ff3769
SP
1093 dacloffset = le32_to_cpu(pntsd->dacloffset);
1094 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1095 ndacloffset = sizeof(struct cifs_ntsd);
1096 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1097 ndacl_ptr->revision = dacl_ptr->revision;
1098 ndacl_ptr->size = 0;
1099 ndacl_ptr->num_aces = 0;
1100
1101 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1102 nmode);
1103 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1104 /* copy sec desc control portion & owner and group sids */
1105 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1106 *aclflag = CIFS_ACL_DACL;
1107 } else {
1108 memcpy(pnntsd, pntsd, secdesclen);
1109 if (uid != NO_CHANGE_32) { /* chown */
1110 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1111 le32_to_cpu(pnntsd->osidoffset));
1112 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1113 GFP_KERNEL);
1114 if (!nowner_sid_ptr)
1115 return -ENOMEM;
1116 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1117 if (rc) {
1118 cFYI(1, "%s: Mapping error %d for owner id %d",
1119 __func__, rc, uid);
1120 kfree(nowner_sid_ptr);
1121 return rc;
1122 }
1123 memcpy(owner_sid_ptr, nowner_sid_ptr,
1124 sizeof(struct cifs_sid));
1125 kfree(nowner_sid_ptr);
1126 *aclflag = CIFS_ACL_OWNER;
1127 }
1128 if (gid != NO_CHANGE_32) { /* chgrp */
1129 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1130 le32_to_cpu(pnntsd->gsidoffset));
1131 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1132 GFP_KERNEL);
1133 if (!ngroup_sid_ptr)
1134 return -ENOMEM;
1135 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
1136 if (rc) {
1137 cFYI(1, "%s: Mapping error %d for group id %d",
1138 __func__, rc, gid);
1139 kfree(ngroup_sid_ptr);
1140 return rc;
1141 }
1142 memcpy(group_sid_ptr, ngroup_sid_ptr,
1143 sizeof(struct cifs_sid));
1144 kfree(ngroup_sid_ptr);
1145 *aclflag = CIFS_ACL_GROUP;
1146 }
1147 }
97837582 1148
ef571cad 1149 return rc;
97837582
SF
1150}
1151
1bf4072d
CH
1152static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1153 __u16 fid, u32 *pacllen)
b9c7a2bb 1154{
b9c7a2bb 1155 struct cifs_ntsd *pntsd = NULL;
6d5786a3
PS
1156 unsigned int xid;
1157 int rc;
7ffec372
JL
1158 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1159
1160 if (IS_ERR(tlink))
987b21d7 1161 return ERR_CAST(tlink);
b9c7a2bb 1162
6d5786a3 1163 xid = get_xid();
7ffec372 1164 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
6d5786a3 1165 free_xid(xid);
b9c7a2bb 1166
7ffec372 1167 cifs_put_tlink(tlink);
b9c7a2bb 1168
987b21d7
SP
1169 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1170 if (rc)
1171 return ERR_PTR(rc);
1bf4072d
CH
1172 return pntsd;
1173}
8b1327f6 1174
1bf4072d
CH
1175static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1176 const char *path, u32 *pacllen)
1177{
1178 struct cifs_ntsd *pntsd = NULL;
1179 int oplock = 0;
6d5786a3
PS
1180 unsigned int xid;
1181 int rc, create_options = 0;
1bf4072d 1182 __u16 fid;
96daf2b0 1183 struct cifs_tcon *tcon;
7ffec372
JL
1184 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1185
1186 if (IS_ERR(tlink))
987b21d7 1187 return ERR_CAST(tlink);
b9c7a2bb 1188
7ffec372 1189 tcon = tlink_tcon(tlink);
6d5786a3 1190 xid = get_xid();
1bf4072d 1191
3d3ea8e6
SP
1192 if (backup_cred(cifs_sb))
1193 create_options |= CREATE_OPEN_BACKUP_INTENT;
1194
1195 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
1196 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1197 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
987b21d7
SP
1198 if (!rc) {
1199 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1200 CIFSSMBClose(xid, tcon, fid);
b9c7a2bb
SF
1201 }
1202
7ffec372 1203 cifs_put_tlink(tlink);
6d5786a3 1204 free_xid(xid);
987b21d7
SP
1205
1206 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1207 if (rc)
1208 return ERR_PTR(rc);
7505e052
SF
1209 return pntsd;
1210}
1211
1bf4072d 1212/* Retrieve an ACL from the server */
fbeba8bb 1213struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1bf4072d
CH
1214 struct inode *inode, const char *path,
1215 u32 *pacllen)
1216{
1217 struct cifs_ntsd *pntsd = NULL;
1218 struct cifsFileInfo *open_file = NULL;
1219
1220 if (inode)
6508d904 1221 open_file = find_readable_file(CIFS_I(inode), true);
1bf4072d
CH
1222 if (!open_file)
1223 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1224
1225 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
6ab409b5 1226 cifsFileInfo_put(open_file);
1bf4072d
CH
1227 return pntsd;
1228}
1229
a5ff3769
SP
1230 /* Set an ACL on the server */
1231int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1232 struct inode *inode, const char *path, int aclflag)
b96d31a6
CH
1233{
1234 int oplock = 0;
6d5786a3
PS
1235 unsigned int xid;
1236 int rc, access_flags, create_options = 0;
b96d31a6 1237 __u16 fid;
96daf2b0 1238 struct cifs_tcon *tcon;
a5ff3769 1239 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
7ffec372 1240 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
97837582 1241
7ffec372
JL
1242 if (IS_ERR(tlink))
1243 return PTR_ERR(tlink);
1244
1245 tcon = tlink_tcon(tlink);
6d5786a3 1246 xid = get_xid();
97837582 1247
3d3ea8e6
SP
1248 if (backup_cred(cifs_sb))
1249 create_options |= CREATE_OPEN_BACKUP_INTENT;
1250
a5ff3769
SP
1251 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1252 access_flags = WRITE_OWNER;
1253 else
1254 access_flags = WRITE_DAC;
1255
1256 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1257 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1258 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
b96d31a6 1259 if (rc) {
b6b38f70 1260 cERROR(1, "Unable to open file to set ACL");
b96d31a6 1261 goto out;
97837582
SF
1262 }
1263
a5ff3769 1264 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
b6b38f70 1265 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
97837582 1266
7ffec372
JL
1267 CIFSSMBClose(xid, tcon, fid);
1268out:
6d5786a3 1269 free_xid(xid);
7ffec372 1270 cifs_put_tlink(tlink);
b96d31a6
CH
1271 return rc;
1272}
97837582 1273
7505e052 1274/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
987b21d7 1275int
0b8f18e3
JL
1276cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1277 struct inode *inode, const char *path, const __u16 *pfid)
7505e052
SF
1278{
1279 struct cifs_ntsd *pntsd = NULL;
1280 u32 acllen = 0;
1281 int rc = 0;
1282
b6b38f70 1283 cFYI(DBG2, "converting ACL to mode for %s", path);
1bf4072d
CH
1284
1285 if (pfid)
1286 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1287 else
1288 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
7505e052
SF
1289
1290 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
987b21d7
SP
1291 if (IS_ERR(pntsd)) {
1292 rc = PTR_ERR(pntsd);
1293 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1294 } else {
9409ae58 1295 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
987b21d7
SP
1296 kfree(pntsd);
1297 if (rc)
1298 cERROR(1, "parse sec desc failed rc = %d", rc);
1299 }
7505e052 1300
987b21d7 1301 return rc;
b9c7a2bb 1302}
953f8681 1303
7505e052 1304/* Convert mode bits to an ACL so we can update the ACL on the server */
a5ff3769
SP
1305int
1306id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1307 uid_t uid, gid_t gid)
953f8681
SF
1308{
1309 int rc = 0;
a5ff3769 1310 int aclflag = CIFS_ACL_DACL; /* default flag to set */
cce246ee 1311 __u32 secdesclen = 0;
97837582
SF
1312 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1313 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
953f8681 1314
b6b38f70 1315 cFYI(DBG2, "set ACL from mode for %s", path);
953f8681
SF
1316
1317 /* Get the security descriptor */
1bf4072d 1318 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
953f8681 1319
97837582
SF
1320 /* Add three ACEs for owner, group, everyone getting rid of
1321 other ACEs as chmod disables ACEs and set the security descriptor */
953f8681 1322
987b21d7
SP
1323 if (IS_ERR(pntsd)) {
1324 rc = PTR_ERR(pntsd);
1325 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1326 } else {
97837582
SF
1327 /* allocate memory for the smb header,
1328 set security descriptor request security descriptor
1329 parameters, and secuirty descriptor itself */
953f8681 1330
cce246ee
SF
1331 secdesclen = secdesclen < DEFSECDESCLEN ?
1332 DEFSECDESCLEN : secdesclen;
1333 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
97837582 1334 if (!pnntsd) {
b6b38f70 1335 cERROR(1, "Unable to allocate security descriptor");
97837582 1336 kfree(pntsd);
ef571cad 1337 return -ENOMEM;
97837582 1338 }
7505e052 1339
a5ff3769
SP
1340 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1341 &aclflag);
97837582 1342
b6b38f70 1343 cFYI(DBG2, "build_sec_desc rc: %d", rc);
97837582
SF
1344
1345 if (!rc) {
1346 /* Set the security descriptor */
a5ff3769
SP
1347 rc = set_cifs_acl(pnntsd, secdesclen, inode,
1348 path, aclflag);
b6b38f70 1349 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
97837582
SF
1350 }
1351
1352 kfree(pnntsd);
1353 kfree(pntsd);
1354 }
1355
ef571cad 1356 return rc;
953f8681 1357}