blob: 5a312eb45a926d0bc4221c0e78c74134c6c317bd [file] [log] [blame]
Steve Frenchbcb02032007-09-25 16:17:24 +00001/*
2 * fs/cifs/cifsacl.c
3 *
Steve French8b1327f2008-03-14 22:37:16 +00004 * Copyright (C) International Business Machines Corp., 2007,2008
Steve Frenchbcb02032007-09-25 16:17:24 +00005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
Steve French65874002007-09-25 19:53:44 +000024#include <linux/fs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050026#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
Steve French65874002007-09-25 19:53:44 +000030#include "cifspdu.h"
31#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000032#include "cifsacl.h"
Steve French65874002007-09-25 19:53:44 +000033#include "cifsproto.h"
34#include "cifs_debug.h"
Steve French65874002007-09-25 19:53:44 +000035
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060036/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000037static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060039/* security id for Authenticated Users system group */
40static const struct cifs_sid sid_authusers = {
Steve French4f612582011-05-27 20:40:18 +000041 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
Steve Frenchbcb02032007-09-25 16:17:24 +000042/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000043static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000044
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050045const struct cred *root_cred;
46
47static void
48shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem,
49 int *nr_del)
50{
51 struct rb_node *node;
52 struct rb_node *tmp;
53 struct cifs_sid_id *psidid;
54
55 node = rb_first(root);
56 while (node) {
57 tmp = node;
58 node = rb_next(tmp);
59 psidid = rb_entry(tmp, struct cifs_sid_id, rbnode);
60 if (nr_to_scan == 0 || *nr_del == nr_to_scan)
61 ++(*nr_rem);
62 else {
63 if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE)
64 && psidid->refcount == 0) {
65 rb_erase(tmp, root);
66 ++(*nr_del);
67 } else
68 ++(*nr_rem);
69 }
70 }
71}
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050072
73/*
74 * Run idmap cache shrinker.
75 */
76static int
Al Viroef1d5752011-05-29 13:46:08 +010077cifs_idmap_shrinker(struct shrinker *shrink, struct shrink_control *sc)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050078{
Al Viroef1d5752011-05-29 13:46:08 +010079 int nr_to_scan = sc->nr_to_scan;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050080 int nr_del = 0;
81 int nr_rem = 0;
82 struct rb_root *root;
83
84 root = &uidtree;
85 spin_lock(&siduidlock);
86 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
87 spin_unlock(&siduidlock);
88
89 root = &gidtree;
90 spin_lock(&sidgidlock);
91 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
92 spin_unlock(&sidgidlock);
93
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -050094 root = &siduidtree;
95 spin_lock(&uidsidlock);
96 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
97 spin_unlock(&uidsidlock);
98
99 root = &sidgidtree;
100 spin_lock(&gidsidlock);
101 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
102 spin_unlock(&gidsidlock);
103
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500104 return nr_rem;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500105}
106
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500107static void
108sid_rb_insert(struct rb_root *root, unsigned long cid,
109 struct cifs_sid_id **psidid, char *typestr)
110{
111 char *strptr;
112 struct rb_node *node = root->rb_node;
113 struct rb_node *parent = NULL;
114 struct rb_node **linkto = &(root->rb_node);
115 struct cifs_sid_id *lsidid;
116
117 while (node) {
118 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
119 parent = node;
120 if (cid > lsidid->id) {
121 linkto = &(node->rb_left);
122 node = node->rb_left;
123 }
124 if (cid < lsidid->id) {
125 linkto = &(node->rb_right);
126 node = node->rb_right;
127 }
128 }
129
130 (*psidid)->id = cid;
131 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
132 (*psidid)->refcount = 0;
133
134 sprintf((*psidid)->sidstr, "%s", typestr);
135 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
136 sprintf(strptr, "%ld", cid);
137
138 clear_bit(SID_ID_PENDING, &(*psidid)->state);
139 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
140
141 rb_link_node(&(*psidid)->rbnode, parent, linkto);
142 rb_insert_color(&(*psidid)->rbnode, root);
143}
144
145static struct cifs_sid_id *
146sid_rb_search(struct rb_root *root, unsigned long cid)
147{
148 struct rb_node *node = root->rb_node;
149 struct cifs_sid_id *lsidid;
150
151 while (node) {
152 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
153 if (cid > lsidid->id)
154 node = node->rb_left;
155 else if (cid < lsidid->id)
156 node = node->rb_right;
157 else /* node found */
158 return lsidid;
159 }
160
161 return NULL;
162}
163
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500164static struct shrinker cifs_shrinker = {
165 .shrink = cifs_idmap_shrinker,
166 .seeks = DEFAULT_SEEKS,
167};
168
169static int
David Howellscf7f6012012-09-13 13:06:29 +0100170cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500171{
172 char *payload;
173
David Howellscf7f6012012-09-13 13:06:29 +0100174 payload = kmalloc(prep->datalen, GFP_KERNEL);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500175 if (!payload)
176 return -ENOMEM;
177
David Howellscf7f6012012-09-13 13:06:29 +0100178 memcpy(payload, prep->data, prep->datalen);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500179 key->payload.data = payload;
David Howellscf7f6012012-09-13 13:06:29 +0100180 key->datalen = prep->datalen;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500181 return 0;
182}
183
184static inline void
185cifs_idmap_key_destroy(struct key *key)
186{
187 kfree(key->payload.data);
188}
189
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500190struct key_type cifs_idmap_key_type = {
Shirish Pargaonkarc4aca0c2011-05-06 02:35:00 -0500191 .name = "cifs.idmap",
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500192 .instantiate = cifs_idmap_key_instantiate,
193 .destroy = cifs_idmap_key_destroy,
194 .describe = user_describe,
195 .match = user_match,
196};
197
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500198static void
199sid_to_str(struct cifs_sid *sidptr, char *sidstr)
200{
201 int i;
202 unsigned long saval;
203 char *strptr;
204
205 strptr = sidstr;
206
207 sprintf(strptr, "%s", "S");
208 strptr = sidstr + strlen(sidstr);
209
210 sprintf(strptr, "-%d", sidptr->revision);
211 strptr = sidstr + strlen(sidstr);
212
Jeff Layton852e2292012-11-25 08:00:36 -0500213 for (i = 0; i < NUM_AUTHS; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500214 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
Jeff Layton436bb432012-11-25 08:00:36 -0500227/*
228 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
229 * the same returns zero, if they do not match returns non-zero.
230 */
231static int
232compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
233{
234 int i;
235 int num_subauth, num_sat, num_saw;
236
237 if ((!ctsid) || (!cwsid))
238 return 1;
239
240 /* compare the revision */
241 if (ctsid->revision != cwsid->revision) {
242 if (ctsid->revision > cwsid->revision)
243 return 1;
244 else
245 return -1;
246 }
247
248 /* compare all of the six auth values */
249 for (i = 0; i < NUM_AUTHS; ++i) {
250 if (ctsid->authority[i] != cwsid->authority[i]) {
251 if (ctsid->authority[i] > cwsid->authority[i])
252 return 1;
253 else
254 return -1;
255 }
256 }
257
258 /* compare all of the subauth values if any */
259 num_sat = ctsid->num_subauth;
260 num_saw = cwsid->num_subauth;
261 num_subauth = num_sat < num_saw ? num_sat : num_saw;
262 if (num_subauth) {
263 for (i = 0; i < num_subauth; ++i) {
264 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
265 if (le32_to_cpu(ctsid->sub_auth[i]) >
266 le32_to_cpu(cwsid->sub_auth[i]))
267 return 1;
268 else
269 return -1;
270 }
271 }
272 }
273
274 return 0; /* sids compare/match */
275}
276
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500277static void
Jeff Layton36960e42012-11-03 09:37:28 -0400278cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
279{
280 memcpy(dst, src, sizeof(*dst));
281 dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS);
282}
283
284static void
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500285id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
286 struct cifs_sid_id **psidid, char *typestr)
287{
288 int rc;
289 char *strptr;
290 struct rb_node *node = root->rb_node;
291 struct rb_node *parent = NULL;
292 struct rb_node **linkto = &(root->rb_node);
293 struct cifs_sid_id *lsidid;
294
295 while (node) {
296 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
297 parent = node;
298 rc = compare_sids(sidptr, &((lsidid)->sid));
299 if (rc > 0) {
300 linkto = &(node->rb_left);
301 node = node->rb_left;
302 } else if (rc < 0) {
303 linkto = &(node->rb_right);
304 node = node->rb_right;
305 }
306 }
307
Jeff Layton36960e42012-11-03 09:37:28 -0400308 cifs_copy_sid(&(*psidid)->sid, sidptr);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500309 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
310 (*psidid)->refcount = 0;
311
312 sprintf((*psidid)->sidstr, "%s", typestr);
313 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
314 sid_to_str(&(*psidid)->sid, strptr);
315
316 clear_bit(SID_ID_PENDING, &(*psidid)->state);
317 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
318
319 rb_link_node(&(*psidid)->rbnode, parent, linkto);
320 rb_insert_color(&(*psidid)->rbnode, root);
321}
322
323static struct cifs_sid_id *
324id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
325{
326 int rc;
327 struct rb_node *node = root->rb_node;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500328 struct cifs_sid_id *lsidid;
329
330 while (node) {
331 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500332 rc = compare_sids(sidptr, &((lsidid)->sid));
333 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500334 node = node->rb_left;
335 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500336 node = node->rb_right;
337 } else /* node found */
338 return lsidid;
339 }
340
341 return NULL;
342}
343
344static int
345sidid_pending_wait(void *unused)
346{
347 schedule();
348 return signal_pending(current) ? -ERESTARTSYS : 0;
349}
350
351static int
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500352id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
353{
354 int rc = 0;
355 struct key *sidkey;
356 const struct cred *saved_cred;
357 struct cifs_sid *lsid;
358 struct cifs_sid_id *psidid, *npsidid;
359 struct rb_root *cidtree;
360 spinlock_t *cidlock;
361
362 if (sidtype == SIDOWNER) {
363 cidlock = &siduidlock;
364 cidtree = &uidtree;
365 } else if (sidtype == SIDGROUP) {
366 cidlock = &sidgidlock;
367 cidtree = &gidtree;
368 } else
369 return -EINVAL;
370
371 spin_lock(cidlock);
372 psidid = sid_rb_search(cidtree, cid);
373
374 if (!psidid) { /* node does not exist, allocate one & attempt adding */
375 spin_unlock(cidlock);
376 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
377 if (!npsidid)
378 return -ENOMEM;
379
380 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
381 if (!npsidid->sidstr) {
382 kfree(npsidid);
383 return -ENOMEM;
384 }
385
386 spin_lock(cidlock);
387 psidid = sid_rb_search(cidtree, cid);
388 if (psidid) { /* node happened to get inserted meanwhile */
389 ++psidid->refcount;
390 spin_unlock(cidlock);
391 kfree(npsidid->sidstr);
392 kfree(npsidid);
393 } else {
394 psidid = npsidid;
395 sid_rb_insert(cidtree, cid, &psidid,
396 sidtype == SIDOWNER ? "oi:" : "gi:");
397 ++psidid->refcount;
398 spin_unlock(cidlock);
399 }
400 } else {
401 ++psidid->refcount;
402 spin_unlock(cidlock);
403 }
404
405 /*
406 * If we are here, it is safe to access psidid and its fields
407 * since a reference was taken earlier while holding the spinlock.
408 * A reference on the node is put without holding the spinlock
409 * and it is OK to do so in this case, shrinker will not erase
410 * this node until all references are put and we do not access
411 * any fields of the node after a reference is put .
412 */
413 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
Jeff Layton36960e42012-11-03 09:37:28 -0400414 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500415 psidid->time = jiffies; /* update ts for accessing */
416 goto id_sid_out;
417 }
418
419 if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
420 rc = -EINVAL;
421 goto id_sid_out;
422 }
423
424 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
425 saved_cred = override_creds(root_cred);
426 sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
427 if (IS_ERR(sidkey)) {
428 rc = -EINVAL;
429 cFYI(1, "%s: Can't map and id to a SID", __func__);
Jeff Layton36960e42012-11-03 09:37:28 -0400430 } else if (sidkey->datalen < sizeof(struct cifs_sid)) {
431 rc = -EIO;
432 cFYI(1, "%s: Downcall contained malformed key "
433 "(datalen=%hu)", __func__, sidkey->datalen);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500434 } else {
435 lsid = (struct cifs_sid *)sidkey->payload.data;
Jeff Layton36960e42012-11-03 09:37:28 -0400436 cifs_copy_sid(&psidid->sid, lsid);
437 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500438 set_bit(SID_ID_MAPPED, &psidid->state);
439 key_put(sidkey);
440 kfree(psidid->sidstr);
441 }
442 psidid->time = jiffies; /* update ts for accessing */
443 revert_creds(saved_cred);
444 clear_bit(SID_ID_PENDING, &psidid->state);
445 wake_up_bit(&psidid->state, SID_ID_PENDING);
446 } else {
447 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
448 sidid_pending_wait, TASK_INTERRUPTIBLE);
449 if (rc) {
450 cFYI(1, "%s: sidid_pending_wait interrupted %d",
451 __func__, rc);
452 --psidid->refcount;
453 return rc;
454 }
455 if (test_bit(SID_ID_MAPPED, &psidid->state))
Jeff Layton36960e42012-11-03 09:37:28 -0400456 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500457 else
458 rc = -EINVAL;
459 }
460id_sid_out:
461 --psidid->refcount;
462 return rc;
463}
464
465static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500466sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
467 struct cifs_fattr *fattr, uint sidtype)
468{
469 int rc;
470 unsigned long cid;
471 struct key *idkey;
472 const struct cred *saved_cred;
473 struct cifs_sid_id *psidid, *npsidid;
474 struct rb_root *cidtree;
475 spinlock_t *cidlock;
476
477 if (sidtype == SIDOWNER) {
478 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
479 cidlock = &siduidlock;
480 cidtree = &uidtree;
481 } else if (sidtype == SIDGROUP) {
482 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
483 cidlock = &sidgidlock;
484 cidtree = &gidtree;
485 } else
486 return -ENOENT;
487
488 spin_lock(cidlock);
489 psidid = id_rb_search(cidtree, psid);
490
491 if (!psidid) { /* node does not exist, allocate one & attempt adding */
492 spin_unlock(cidlock);
493 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
494 if (!npsidid)
495 return -ENOMEM;
496
497 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
498 if (!npsidid->sidstr) {
499 kfree(npsidid);
500 return -ENOMEM;
501 }
502
503 spin_lock(cidlock);
504 psidid = id_rb_search(cidtree, psid);
505 if (psidid) { /* node happened to get inserted meanwhile */
506 ++psidid->refcount;
507 spin_unlock(cidlock);
508 kfree(npsidid->sidstr);
509 kfree(npsidid);
510 } else {
511 psidid = npsidid;
512 id_rb_insert(cidtree, psid, &psidid,
513 sidtype == SIDOWNER ? "os:" : "gs:");
514 ++psidid->refcount;
515 spin_unlock(cidlock);
516 }
517 } else {
518 ++psidid->refcount;
519 spin_unlock(cidlock);
520 }
521
522 /*
523 * If we are here, it is safe to access psidid and its fields
524 * since a reference was taken earlier while holding the spinlock.
525 * A reference on the node is put without holding the spinlock
526 * and it is OK to do so in this case, shrinker will not erase
527 * this node until all references are put and we do not access
528 * any fields of the node after a reference is put .
529 */
530 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
531 cid = psidid->id;
532 psidid->time = jiffies; /* update ts for accessing */
533 goto sid_to_id_out;
534 }
535
536 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
537 goto sid_to_id_out;
538
539 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
540 saved_cred = override_creds(root_cred);
541 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
542 if (IS_ERR(idkey))
543 cFYI(1, "%s: Can't map SID to an id", __func__);
544 else {
545 cid = *(unsigned long *)idkey->payload.value;
546 psidid->id = cid;
547 set_bit(SID_ID_MAPPED, &psidid->state);
548 key_put(idkey);
549 kfree(psidid->sidstr);
550 }
551 revert_creds(saved_cred);
552 psidid->time = jiffies; /* update ts for accessing */
553 clear_bit(SID_ID_PENDING, &psidid->state);
554 wake_up_bit(&psidid->state, SID_ID_PENDING);
555 } else {
556 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
557 sidid_pending_wait, TASK_INTERRUPTIBLE);
558 if (rc) {
559 cFYI(1, "%s: sidid_pending_wait interrupted %d",
560 __func__, rc);
561 --psidid->refcount; /* decremented without spinlock */
562 return rc;
563 }
564 if (test_bit(SID_ID_MAPPED, &psidid->state))
565 cid = psidid->id;
566 }
567
568sid_to_id_out:
569 --psidid->refcount; /* decremented without spinlock */
570 if (sidtype == SIDOWNER)
571 fattr->cf_uid = cid;
572 else
573 fattr->cf_gid = cid;
574
575 return 0;
576}
577
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500578int
579init_cifs_idmap(void)
580{
581 struct cred *cred;
582 struct key *keyring;
583 int ret;
584
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400585 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500586
587 /* create an override credential set with a special thread keyring in
588 * which requests are cached
589 *
590 * this is used to prevent malicious redirections from being installed
591 * with add_key().
592 */
593 cred = prepare_kernel_cred(NULL);
594 if (!cred)
595 return -ENOMEM;
596
597 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
598 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
599 KEY_USR_VIEW | KEY_USR_READ,
600 KEY_ALLOC_NOT_IN_QUOTA);
601 if (IS_ERR(keyring)) {
602 ret = PTR_ERR(keyring);
603 goto failed_put_cred;
604 }
605
606 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
607 if (ret < 0)
608 goto failed_put_key;
609
610 ret = register_key_type(&cifs_idmap_key_type);
611 if (ret < 0)
612 goto failed_put_key;
613
614 /* instruct request_key() to use this special keyring as a cache for
615 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000616 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500617 cred->thread_keyring = keyring;
618 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
619 root_cred = cred;
620
621 spin_lock_init(&siduidlock);
622 uidtree = RB_ROOT;
623 spin_lock_init(&sidgidlock);
624 gidtree = RB_ROOT;
625
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500626 spin_lock_init(&uidsidlock);
627 siduidtree = RB_ROOT;
628 spin_lock_init(&gidsidlock);
629 sidgidtree = RB_ROOT;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500630 register_shrinker(&cifs_shrinker);
631
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400632 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500633 return 0;
634
635failed_put_key:
636 key_put(keyring);
637failed_put_cred:
638 put_cred(cred);
639 return ret;
640}
641
642void
643exit_cifs_idmap(void)
644{
645 key_revoke(root_cred->thread_keyring);
646 unregister_key_type(&cifs_idmap_key_type);
647 put_cred(root_cred);
648 unregister_shrinker(&cifs_shrinker);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400649 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500650}
651
652void
653cifs_destroy_idmaptrees(void)
654{
655 struct rb_root *root;
656 struct rb_node *node;
657
658 root = &uidtree;
659 spin_lock(&siduidlock);
660 while ((node = rb_first(root)))
661 rb_erase(node, root);
662 spin_unlock(&siduidlock);
663
664 root = &gidtree;
665 spin_lock(&sidgidlock);
666 while ((node = rb_first(root)))
667 rb_erase(node, root);
668 spin_unlock(&sidgidlock);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500669
670 root = &siduidtree;
671 spin_lock(&uidsidlock);
672 while ((node = rb_first(root)))
673 rb_erase(node, root);
674 spin_unlock(&uidsidlock);
675
676 root = &sidgidtree;
677 spin_lock(&gidsidlock);
678 while ((node = rb_first(root)))
679 rb_erase(node, root);
680 spin_unlock(&gidsidlock);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500681}
Steve French297647c2007-10-12 04:11:59 +0000682
Steve French97837582007-12-31 07:47:21 +0000683/* copy ntsd, owner sid, and group sid from a security descriptor to another */
684static void copy_sec_desc(const struct cifs_ntsd *pntsd,
685 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
686{
Steve French97837582007-12-31 07:47:21 +0000687 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
688 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
689
690 /* copy security descriptor control portion */
691 pnntsd->revision = pntsd->revision;
692 pnntsd->type = pntsd->type;
693 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
694 pnntsd->sacloffset = 0;
695 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
696 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
697
698 /* copy owner sid */
699 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
700 le32_to_cpu(pntsd->osidoffset));
701 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400702 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000703
704 /* copy group sid */
705 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
706 le32_to_cpu(pntsd->gsidoffset));
707 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
708 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400709 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000710
711 return;
712}
713
714
Steve French630f3f0c2007-10-25 21:17:17 +0000715/*
716 change posix mode to reflect permissions
717 pmode is the existing mode (we only want to overwrite part of this
718 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
719*/
Al Viro9b5e6852007-12-05 08:24:38 +0000720static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000721 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000722{
Al Viro9b5e6852007-12-05 08:24:38 +0000723 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000724 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000725 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000726 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000727 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000728 for the operation you are trying to perform for your user */
729
730 /* For deny ACEs we change the mask so that subsequent allow access
731 control entries do not turn on the bits we are denying */
732 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000733 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000734 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000735
Al Viro9b5e6852007-12-05 08:24:38 +0000736 if ((flags & GENERIC_WRITE) ||
737 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000738 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000739 if ((flags & GENERIC_READ) ||
740 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000741 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000742 if ((flags & GENERIC_EXECUTE) ||
743 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000744 *pbits_to_set &= ~S_IXUGO;
745 return;
746 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000747 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000748 return;
749 }
750 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000751
Al Viro9b5e6852007-12-05 08:24:38 +0000752 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000753 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000755 return;
756 }
Al Viro9b5e6852007-12-05 08:24:38 +0000757 if ((flags & GENERIC_WRITE) ||
758 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000759 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000760 if ((flags & GENERIC_READ) ||
761 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000762 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000763 if ((flags & GENERIC_EXECUTE) ||
764 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000765 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000766
Joe Perchesb6b38f72010-04-21 03:50:45 +0000767 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000768 return;
769}
770
Steve Frenchce06c9f2007-11-08 21:12:01 +0000771/*
772 Generate access flags to reflect permissions mode is the existing mode.
773 This function is called for every ACE in the DACL whose SID matches
774 with either owner or group or everyone.
775*/
776
777static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
778 __u32 *pace_flags)
779{
780 /* reset access mask */
781 *pace_flags = 0x0;
782
783 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
784 mode &= bits_to_use;
785
786 /* check for R/W/X UGO since we do not know whose flags
787 is this but we have cleared all the bits sans RWX for
788 either user or group or other as per bits_to_use */
789 if (mode & S_IRUGO)
790 *pace_flags |= SET_FILE_READ_RIGHTS;
791 if (mode & S_IWUGO)
792 *pace_flags |= SET_FILE_WRITE_RIGHTS;
793 if (mode & S_IXUGO)
794 *pace_flags |= SET_FILE_EXEC_RIGHTS;
795
Joe Perchesb6b38f72010-04-21 03:50:45 +0000796 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000797 return;
798}
799
Al Viro2b210ad2008-03-29 03:09:18 +0000800static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000801 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
802{
803 int i;
804 __u16 size = 0;
805 __u32 access_req = 0;
806
807 pntace->type = ACCESS_ALLOWED;
808 pntace->flags = 0x0;
809 mode_to_access_flags(nmode, bits, &access_req);
810 if (!access_req)
811 access_req = SET_MINIMUM_RIGHTS;
812 pntace->access_req = cpu_to_le32(access_req);
813
814 pntace->sid.revision = psid->revision;
815 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500816 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000817 pntace->sid.authority[i] = psid->authority[i];
818 for (i = 0; i < psid->num_subauth; i++)
819 pntace->sid.sub_auth[i] = psid->sub_auth[i];
820
821 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
822 pntace->size = cpu_to_le16(size);
823
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000824 return size;
Steve French97837582007-12-31 07:47:21 +0000825}
826
Steve French297647c2007-10-12 04:11:59 +0000827
Steve French953f8682007-10-31 04:54:42 +0000828#ifdef CONFIG_CIFS_DEBUG2
829static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000830{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000831 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000832
833 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000834
Steve French44093ca2007-10-23 21:22:55 +0000835 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000836 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000837 return;
838 }
839
840 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000841 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000842 return;
Steve French44093ca2007-10-23 21:22:55 +0000843 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000844
Steve French44093ca2007-10-23 21:22:55 +0000845 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000846 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000847 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000848 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000849 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000850 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000851 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000852 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
853 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000854 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000855
Steve Frenchd12fd122007-10-03 19:43:19 +0000856 /* BB add length check to make sure that we do not have huge
857 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000858 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000859
Steve Frenchd12fd122007-10-03 19:43:19 +0000860 return;
861}
Steve French953f8682007-10-31 04:54:42 +0000862#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000863
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000864
Steve Frencha750e772007-10-17 22:50:39 +0000865static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000866 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400867 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000868{
869 int i;
870 int num_aces = 0;
871 int acl_size;
872 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000873 struct cifs_ace **ppace;
874
875 /* BB need to add parm so we can store the SID BB */
876
Steve French2b834572007-11-25 10:01:00 +0000877 if (!pdacl) {
878 /* no DACL in the security descriptor, set
879 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400880 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000881 return;
882 }
883
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000884 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000885 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000886 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000887 return;
888 }
889
Joe Perchesb6b38f72010-04-21 03:50:45 +0000890 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000891 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000892 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000893
Steve French7505e052007-11-01 18:03:01 +0000894 /* reset rwx permissions for user/group/other.
895 Also, if num_aces is 0 i.e. DACL has no ACEs,
896 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400897 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000898
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000899 acl_base = (char *)pdacl;
900 acl_size = sizeof(struct cifs_acl);
901
Steve Frenchadbc0352007-10-17 02:12:46 +0000902 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500903 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000904 umode_t user_mask = S_IRWXU;
905 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600906 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000907
Dan Carpenter72501702012-01-11 10:46:27 +0300908 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
909 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000910 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
911 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300912 if (!ppace) {
913 cERROR(1, "DACL memory allocation error");
914 return;
915 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000916
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000917 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000918 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000919#ifdef CONFIG_CIFS_DEBUG2
920 dump_ace(ppace[i], end_of_acl);
921#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500922 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000923 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000924 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400925 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000926 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500927 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000928 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000929 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400930 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000931 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500932 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000933 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000934 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400935 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000936 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500937 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600938 access_flags_to_mode(ppace[i]->access_req,
939 ppace[i]->type,
940 &fattr->cf_mode,
941 &other_mask);
942
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000943
Steve French44093ca2007-10-23 21:22:55 +0000944/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000945 (void *)ppace[i],
946 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000947
Steve French44093ca2007-10-23 21:22:55 +0000948 acl_base = (char *)ppace[i];
949 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000950 }
951
952 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000953 }
954
955 return;
956}
957
Steve Frenchbcb02032007-09-25 16:17:24 +0000958
Steve French97837582007-12-31 07:47:21 +0000959static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
960 struct cifs_sid *pgrpsid, __u64 nmode)
961{
Al Viro2b210ad2008-03-29 03:09:18 +0000962 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000963 struct cifs_acl *pnndacl;
964
965 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
966
967 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
968 pownersid, nmode, S_IRWXU);
969 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
970 pgrpsid, nmode, S_IRWXG);
971 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
972 &sid_everyone, nmode, S_IRWXO);
973
974 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000975 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000976
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000977 return 0;
Steve French97837582007-12-31 07:47:21 +0000978}
979
980
Steve Frenchbcb02032007-09-25 16:17:24 +0000981static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
982{
983 /* BB need to add parm so we can store the SID BB */
984
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000985 /* validate that we do not go past end of ACL - sid must be at least 8
986 bytes long (assuming no sub-auths - e.g. the null SID */
987 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000988 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000989 return -EINVAL;
990 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000991
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000992#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500993 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000994 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000995 cFYI(1, "SID revision %d num_auth %d",
996 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000997
Steve Frenchaf6f4612007-10-16 18:40:37 +0000998 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000999 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
1000 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001001 }
1002
Steve Frenchd12fd122007-10-03 19:43:19 +00001003 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001004 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001005 cFYI(1, "RID 0x%x",
1006 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001007 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001008#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001009
Steve Frenchbcb02032007-09-25 16:17:24 +00001010 return 0;
1011}
1012
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001013
Steve Frenchbcb02032007-09-25 16:17:24 +00001014/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001015static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
1016 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +00001017{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001018 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001019 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1020 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001021 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001022 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001023
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001024 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001025 return -EIO;
1026
Steve Frenchbcb02032007-09-25 16:17:24 +00001027 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001028 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001029 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001030 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001031 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001032 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001033 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +00001034 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +00001035 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1036 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001037 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001038/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001039 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001040 if (rc) {
1041 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001042 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001043 }
1044 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1045 if (rc) {
1046 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
1047 return rc;
1048 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001049
1050 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001051 if (rc) {
1052 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001053 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001054 }
1055 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1056 if (rc) {
1057 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
1058 return rc;
1059 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001060
Steve French7505e052007-11-01 18:03:01 +00001061 if (dacloffset)
1062 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001063 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +00001064 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001065 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001066
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001067 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001068}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001069
Steve French97837582007-12-31 07:47:21 +00001070/* Convert permission bits from mode to equivalent CIFS ACL */
1071static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001072 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001073{
1074 int rc = 0;
1075 __u32 dacloffset;
1076 __u32 ndacloffset;
1077 __u32 sidsoffset;
1078 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001079 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001080 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1081 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1082
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001083 if (nmode != NO_CHANGE_64) { /* chmod */
1084 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001085 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001086 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001087 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001088 dacloffset = le32_to_cpu(pntsd->dacloffset);
1089 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1090 ndacloffset = sizeof(struct cifs_ntsd);
1091 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1092 ndacl_ptr->revision = dacl_ptr->revision;
1093 ndacl_ptr->size = 0;
1094 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001095
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001096 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1097 nmode);
1098 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1099 /* copy sec desc control portion & owner and group sids */
1100 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1101 *aclflag = CIFS_ACL_DACL;
1102 } else {
1103 memcpy(pnntsd, pntsd, secdesclen);
1104 if (uid != NO_CHANGE_32) { /* chown */
1105 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1106 le32_to_cpu(pnntsd->osidoffset));
1107 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1108 GFP_KERNEL);
1109 if (!nowner_sid_ptr)
1110 return -ENOMEM;
1111 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1112 if (rc) {
1113 cFYI(1, "%s: Mapping error %d for owner id %d",
1114 __func__, rc, uid);
1115 kfree(nowner_sid_ptr);
1116 return rc;
1117 }
Jeff Layton36960e42012-11-03 09:37:28 -04001118 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001119 kfree(nowner_sid_ptr);
1120 *aclflag = CIFS_ACL_OWNER;
1121 }
1122 if (gid != NO_CHANGE_32) { /* chgrp */
1123 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1124 le32_to_cpu(pnntsd->gsidoffset));
1125 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1126 GFP_KERNEL);
1127 if (!ngroup_sid_ptr)
1128 return -ENOMEM;
1129 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
1130 if (rc) {
1131 cFYI(1, "%s: Mapping error %d for group id %d",
1132 __func__, rc, gid);
1133 kfree(ngroup_sid_ptr);
1134 return rc;
1135 }
Jeff Layton36960e42012-11-03 09:37:28 -04001136 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001137 kfree(ngroup_sid_ptr);
1138 *aclflag = CIFS_ACL_GROUP;
1139 }
1140 }
Steve French97837582007-12-31 07:47:21 +00001141
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001142 return rc;
Steve French97837582007-12-31 07:47:21 +00001143}
1144
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001145static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1146 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001147{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001148 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001149 unsigned int xid;
1150 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001151 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1152
1153 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001154 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001155
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001156 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001157 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001158 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001159
Jeff Layton7ffec372010-09-29 19:51:11 -04001160 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001161
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001162 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1163 if (rc)
1164 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001165 return pntsd;
1166}
1167
1168static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1169 const char *path, u32 *pacllen)
1170{
1171 struct cifs_ntsd *pntsd = NULL;
1172 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001173 unsigned int xid;
1174 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001175 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001176 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001177 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001178
Jeff Layton7ffec372010-09-29 19:51:11 -04001179 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001180 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001181
1182 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001183 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001184
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001185 if (backup_cred(cifs_sb))
1186 create_options |= CREATE_OPEN_BACKUP_INTENT;
1187
1188 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
1189 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1190 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001191 if (!rc) {
1192 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1193 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001194 }
1195
Jeff Layton7ffec372010-09-29 19:51:11 -04001196 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001197 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001198
1199 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1200 if (rc)
1201 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001202 return pntsd;
1203}
1204
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001205/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001206struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001207 struct inode *inode, const char *path,
1208 u32 *pacllen)
1209{
1210 struct cifs_ntsd *pntsd = NULL;
1211 struct cifsFileInfo *open_file = NULL;
1212
1213 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001214 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001215 if (!open_file)
1216 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1217
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001218 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001219 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001220 return pntsd;
1221}
1222
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001223 /* Set an ACL on the server */
1224int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1225 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001226{
1227 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001228 unsigned int xid;
1229 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +00001230 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001231 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001232 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001233 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001234
Jeff Layton7ffec372010-09-29 19:51:11 -04001235 if (IS_ERR(tlink))
1236 return PTR_ERR(tlink);
1237
1238 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001239 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001240
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001241 if (backup_cred(cifs_sb))
1242 create_options |= CREATE_OPEN_BACKUP_INTENT;
1243
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001244 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1245 access_flags = WRITE_OWNER;
1246 else
1247 access_flags = WRITE_DAC;
1248
1249 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1250 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1251 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001252 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001253 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001254 goto out;
Steve French97837582007-12-31 07:47:21 +00001255 }
1256
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001257 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001258 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001259
Jeff Layton7ffec372010-09-29 19:51:11 -04001260 CIFSSMBClose(xid, tcon, fid);
1261out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001262 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001263 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001264 return rc;
1265}
Steve French97837582007-12-31 07:47:21 +00001266
Steve French7505e052007-11-01 18:03:01 +00001267/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001268int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001269cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1270 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001271{
1272 struct cifs_ntsd *pntsd = NULL;
1273 u32 acllen = 0;
1274 int rc = 0;
1275
Joe Perchesb6b38f72010-04-21 03:50:45 +00001276 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001277
1278 if (pfid)
1279 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1280 else
1281 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001282
1283 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001284 if (IS_ERR(pntsd)) {
1285 rc = PTR_ERR(pntsd);
1286 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1287 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001288 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001289 kfree(pntsd);
1290 if (rc)
1291 cERROR(1, "parse sec desc failed rc = %d", rc);
1292 }
Steve French7505e052007-11-01 18:03:01 +00001293
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001294 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001295}
Steve French953f8682007-10-31 04:54:42 +00001296
Steve French7505e052007-11-01 18:03:01 +00001297/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001298int
1299id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1300 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001301{
1302 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001303 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001304 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001305 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1306 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001307
Joe Perchesb6b38f72010-04-21 03:50:45 +00001308 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001309
1310 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001311 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001312 if (IS_ERR(pntsd)) {
1313 rc = PTR_ERR(pntsd);
1314 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001315 goto out;
Steve French97837582007-12-31 07:47:21 +00001316 }
1317
Jeff Laytonc78cd832012-11-25 08:00:35 -05001318 /*
1319 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1320 * as chmod disables ACEs and set the security descriptor. Allocate
1321 * memory for the smb header, set security descriptor request security
1322 * descriptor parameters, and secuirty descriptor itself
1323 */
1324 secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
1325 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1326 if (!pnntsd) {
1327 cERROR(1, "Unable to allocate security descriptor");
1328 kfree(pntsd);
1329 return -ENOMEM;
1330 }
1331
1332 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1333 &aclflag);
1334
1335 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1336
1337 if (!rc) {
1338 /* Set the security descriptor */
1339 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1340 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1341 }
1342
1343 kfree(pnntsd);
1344 kfree(pntsd);
1345out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001346 return rc;
Steve French953f8682007-10-31 04:54:42 +00001347}