blob: 141a944c9dfdb4699c7c2620652921934fb1e3f9 [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{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500280 int i;
281
282 dst->revision = src->revision;
Jeff Layton36960e42012-11-03 09:37:28 -0400283 dst->num_subauth = min_t(u8, src->num_subauth, NUM_SUBAUTHS);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500284 for (i = 0; i < NUM_AUTHS; ++i)
285 dst->authority[i] = src->authority[i];
286 for (i = 0; i < dst->num_subauth; ++i)
287 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400288}
289
290static void
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500291id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
292 struct cifs_sid_id **psidid, char *typestr)
293{
294 int rc;
295 char *strptr;
296 struct rb_node *node = root->rb_node;
297 struct rb_node *parent = NULL;
298 struct rb_node **linkto = &(root->rb_node);
299 struct cifs_sid_id *lsidid;
300
301 while (node) {
302 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
303 parent = node;
304 rc = compare_sids(sidptr, &((lsidid)->sid));
305 if (rc > 0) {
306 linkto = &(node->rb_left);
307 node = node->rb_left;
308 } else if (rc < 0) {
309 linkto = &(node->rb_right);
310 node = node->rb_right;
311 }
312 }
313
Jeff Layton36960e42012-11-03 09:37:28 -0400314 cifs_copy_sid(&(*psidid)->sid, sidptr);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500315 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
316 (*psidid)->refcount = 0;
317
318 sprintf((*psidid)->sidstr, "%s", typestr);
319 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
320 sid_to_str(&(*psidid)->sid, strptr);
321
322 clear_bit(SID_ID_PENDING, &(*psidid)->state);
323 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
324
325 rb_link_node(&(*psidid)->rbnode, parent, linkto);
326 rb_insert_color(&(*psidid)->rbnode, root);
327}
328
329static struct cifs_sid_id *
330id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
331{
332 int rc;
333 struct rb_node *node = root->rb_node;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500334 struct cifs_sid_id *lsidid;
335
336 while (node) {
337 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500338 rc = compare_sids(sidptr, &((lsidid)->sid));
339 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500340 node = node->rb_left;
341 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500342 node = node->rb_right;
343 } else /* node found */
344 return lsidid;
345 }
346
347 return NULL;
348}
349
350static int
351sidid_pending_wait(void *unused)
352{
353 schedule();
354 return signal_pending(current) ? -ERESTARTSYS : 0;
355}
356
357static int
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500358id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
359{
360 int rc = 0;
361 struct key *sidkey;
362 const struct cred *saved_cred;
363 struct cifs_sid *lsid;
364 struct cifs_sid_id *psidid, *npsidid;
365 struct rb_root *cidtree;
366 spinlock_t *cidlock;
367
368 if (sidtype == SIDOWNER) {
369 cidlock = &siduidlock;
370 cidtree = &uidtree;
371 } else if (sidtype == SIDGROUP) {
372 cidlock = &sidgidlock;
373 cidtree = &gidtree;
374 } else
375 return -EINVAL;
376
377 spin_lock(cidlock);
378 psidid = sid_rb_search(cidtree, cid);
379
380 if (!psidid) { /* node does not exist, allocate one & attempt adding */
381 spin_unlock(cidlock);
382 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
383 if (!npsidid)
384 return -ENOMEM;
385
386 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
387 if (!npsidid->sidstr) {
388 kfree(npsidid);
389 return -ENOMEM;
390 }
391
392 spin_lock(cidlock);
393 psidid = sid_rb_search(cidtree, cid);
394 if (psidid) { /* node happened to get inserted meanwhile */
395 ++psidid->refcount;
396 spin_unlock(cidlock);
397 kfree(npsidid->sidstr);
398 kfree(npsidid);
399 } else {
400 psidid = npsidid;
401 sid_rb_insert(cidtree, cid, &psidid,
402 sidtype == SIDOWNER ? "oi:" : "gi:");
403 ++psidid->refcount;
404 spin_unlock(cidlock);
405 }
406 } else {
407 ++psidid->refcount;
408 spin_unlock(cidlock);
409 }
410
411 /*
412 * If we are here, it is safe to access psidid and its fields
413 * since a reference was taken earlier while holding the spinlock.
414 * A reference on the node is put without holding the spinlock
415 * and it is OK to do so in this case, shrinker will not erase
416 * this node until all references are put and we do not access
417 * any fields of the node after a reference is put .
418 */
419 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
Jeff Layton36960e42012-11-03 09:37:28 -0400420 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500421 psidid->time = jiffies; /* update ts for accessing */
422 goto id_sid_out;
423 }
424
425 if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
426 rc = -EINVAL;
427 goto id_sid_out;
428 }
429
430 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
431 saved_cred = override_creds(root_cred);
432 sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
433 if (IS_ERR(sidkey)) {
434 rc = -EINVAL;
435 cFYI(1, "%s: Can't map and id to a SID", __func__);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500436 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
Jeff Layton36960e42012-11-03 09:37:28 -0400437 rc = -EIO;
438 cFYI(1, "%s: Downcall contained malformed key "
439 "(datalen=%hu)", __func__, sidkey->datalen);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500440 } else {
441 lsid = (struct cifs_sid *)sidkey->payload.data;
Jeff Layton36960e42012-11-03 09:37:28 -0400442 cifs_copy_sid(&psidid->sid, lsid);
443 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500444 set_bit(SID_ID_MAPPED, &psidid->state);
445 key_put(sidkey);
446 kfree(psidid->sidstr);
447 }
448 psidid->time = jiffies; /* update ts for accessing */
449 revert_creds(saved_cred);
450 clear_bit(SID_ID_PENDING, &psidid->state);
451 wake_up_bit(&psidid->state, SID_ID_PENDING);
452 } else {
453 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
454 sidid_pending_wait, TASK_INTERRUPTIBLE);
455 if (rc) {
456 cFYI(1, "%s: sidid_pending_wait interrupted %d",
457 __func__, rc);
458 --psidid->refcount;
459 return rc;
460 }
461 if (test_bit(SID_ID_MAPPED, &psidid->state))
Jeff Layton36960e42012-11-03 09:37:28 -0400462 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500463 else
464 rc = -EINVAL;
465 }
466id_sid_out:
467 --psidid->refcount;
468 return rc;
469}
470
471static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500472sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
473 struct cifs_fattr *fattr, uint sidtype)
474{
475 int rc;
476 unsigned long cid;
477 struct key *idkey;
478 const struct cred *saved_cred;
479 struct cifs_sid_id *psidid, *npsidid;
480 struct rb_root *cidtree;
481 spinlock_t *cidlock;
482
483 if (sidtype == SIDOWNER) {
484 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
485 cidlock = &siduidlock;
486 cidtree = &uidtree;
487 } else if (sidtype == SIDGROUP) {
488 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
489 cidlock = &sidgidlock;
490 cidtree = &gidtree;
491 } else
492 return -ENOENT;
493
494 spin_lock(cidlock);
495 psidid = id_rb_search(cidtree, psid);
496
497 if (!psidid) { /* node does not exist, allocate one & attempt adding */
498 spin_unlock(cidlock);
499 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
500 if (!npsidid)
501 return -ENOMEM;
502
503 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
504 if (!npsidid->sidstr) {
505 kfree(npsidid);
506 return -ENOMEM;
507 }
508
509 spin_lock(cidlock);
510 psidid = id_rb_search(cidtree, psid);
511 if (psidid) { /* node happened to get inserted meanwhile */
512 ++psidid->refcount;
513 spin_unlock(cidlock);
514 kfree(npsidid->sidstr);
515 kfree(npsidid);
516 } else {
517 psidid = npsidid;
518 id_rb_insert(cidtree, psid, &psidid,
519 sidtype == SIDOWNER ? "os:" : "gs:");
520 ++psidid->refcount;
521 spin_unlock(cidlock);
522 }
523 } else {
524 ++psidid->refcount;
525 spin_unlock(cidlock);
526 }
527
528 /*
529 * If we are here, it is safe to access psidid and its fields
530 * since a reference was taken earlier while holding the spinlock.
531 * A reference on the node is put without holding the spinlock
532 * and it is OK to do so in this case, shrinker will not erase
533 * this node until all references are put and we do not access
534 * any fields of the node after a reference is put .
535 */
536 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
537 cid = psidid->id;
538 psidid->time = jiffies; /* update ts for accessing */
539 goto sid_to_id_out;
540 }
541
542 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
543 goto sid_to_id_out;
544
545 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
546 saved_cred = override_creds(root_cred);
547 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
548 if (IS_ERR(idkey))
549 cFYI(1, "%s: Can't map SID to an id", __func__);
550 else {
551 cid = *(unsigned long *)idkey->payload.value;
552 psidid->id = cid;
553 set_bit(SID_ID_MAPPED, &psidid->state);
554 key_put(idkey);
555 kfree(psidid->sidstr);
556 }
557 revert_creds(saved_cred);
558 psidid->time = jiffies; /* update ts for accessing */
559 clear_bit(SID_ID_PENDING, &psidid->state);
560 wake_up_bit(&psidid->state, SID_ID_PENDING);
561 } else {
562 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
563 sidid_pending_wait, TASK_INTERRUPTIBLE);
564 if (rc) {
565 cFYI(1, "%s: sidid_pending_wait interrupted %d",
566 __func__, rc);
567 --psidid->refcount; /* decremented without spinlock */
568 return rc;
569 }
570 if (test_bit(SID_ID_MAPPED, &psidid->state))
571 cid = psidid->id;
572 }
573
574sid_to_id_out:
575 --psidid->refcount; /* decremented without spinlock */
576 if (sidtype == SIDOWNER)
577 fattr->cf_uid = cid;
578 else
579 fattr->cf_gid = cid;
580
581 return 0;
582}
583
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500584int
585init_cifs_idmap(void)
586{
587 struct cred *cred;
588 struct key *keyring;
589 int ret;
590
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400591 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500592
593 /* create an override credential set with a special thread keyring in
594 * which requests are cached
595 *
596 * this is used to prevent malicious redirections from being installed
597 * with add_key().
598 */
599 cred = prepare_kernel_cred(NULL);
600 if (!cred)
601 return -ENOMEM;
602
603 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
604 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
605 KEY_USR_VIEW | KEY_USR_READ,
606 KEY_ALLOC_NOT_IN_QUOTA);
607 if (IS_ERR(keyring)) {
608 ret = PTR_ERR(keyring);
609 goto failed_put_cred;
610 }
611
612 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
613 if (ret < 0)
614 goto failed_put_key;
615
616 ret = register_key_type(&cifs_idmap_key_type);
617 if (ret < 0)
618 goto failed_put_key;
619
620 /* instruct request_key() to use this special keyring as a cache for
621 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000622 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500623 cred->thread_keyring = keyring;
624 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
625 root_cred = cred;
626
627 spin_lock_init(&siduidlock);
628 uidtree = RB_ROOT;
629 spin_lock_init(&sidgidlock);
630 gidtree = RB_ROOT;
631
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500632 spin_lock_init(&uidsidlock);
633 siduidtree = RB_ROOT;
634 spin_lock_init(&gidsidlock);
635 sidgidtree = RB_ROOT;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500636 register_shrinker(&cifs_shrinker);
637
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400638 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500639 return 0;
640
641failed_put_key:
642 key_put(keyring);
643failed_put_cred:
644 put_cred(cred);
645 return ret;
646}
647
648void
649exit_cifs_idmap(void)
650{
651 key_revoke(root_cred->thread_keyring);
652 unregister_key_type(&cifs_idmap_key_type);
653 put_cred(root_cred);
654 unregister_shrinker(&cifs_shrinker);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400655 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500656}
657
658void
659cifs_destroy_idmaptrees(void)
660{
661 struct rb_root *root;
662 struct rb_node *node;
663
664 root = &uidtree;
665 spin_lock(&siduidlock);
666 while ((node = rb_first(root)))
667 rb_erase(node, root);
668 spin_unlock(&siduidlock);
669
670 root = &gidtree;
671 spin_lock(&sidgidlock);
672 while ((node = rb_first(root)))
673 rb_erase(node, root);
674 spin_unlock(&sidgidlock);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500675
676 root = &siduidtree;
677 spin_lock(&uidsidlock);
678 while ((node = rb_first(root)))
679 rb_erase(node, root);
680 spin_unlock(&uidsidlock);
681
682 root = &sidgidtree;
683 spin_lock(&gidsidlock);
684 while ((node = rb_first(root)))
685 rb_erase(node, root);
686 spin_unlock(&gidsidlock);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500687}
Steve French297647c2007-10-12 04:11:59 +0000688
Steve French97837582007-12-31 07:47:21 +0000689/* copy ntsd, owner sid, and group sid from a security descriptor to another */
690static void copy_sec_desc(const struct cifs_ntsd *pntsd,
691 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
692{
Steve French97837582007-12-31 07:47:21 +0000693 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
694 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
695
696 /* copy security descriptor control portion */
697 pnntsd->revision = pntsd->revision;
698 pnntsd->type = pntsd->type;
699 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
700 pnntsd->sacloffset = 0;
701 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
702 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
703
704 /* copy owner sid */
705 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
706 le32_to_cpu(pntsd->osidoffset));
707 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400708 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000709
710 /* copy group sid */
711 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
712 le32_to_cpu(pntsd->gsidoffset));
713 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
714 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400715 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000716
717 return;
718}
719
720
Steve French630f3f0c2007-10-25 21:17:17 +0000721/*
722 change posix mode to reflect permissions
723 pmode is the existing mode (we only want to overwrite part of this
724 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
725*/
Al Viro9b5e6852007-12-05 08:24:38 +0000726static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000727 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000728{
Al Viro9b5e6852007-12-05 08:24:38 +0000729 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000730 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000731 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000732 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000733 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000734 for the operation you are trying to perform for your user */
735
736 /* For deny ACEs we change the mask so that subsequent allow access
737 control entries do not turn on the bits we are denying */
738 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000739 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000740 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000741
Al Viro9b5e6852007-12-05 08:24:38 +0000742 if ((flags & GENERIC_WRITE) ||
743 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000744 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000745 if ((flags & GENERIC_READ) ||
746 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000747 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000748 if ((flags & GENERIC_EXECUTE) ||
749 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000750 *pbits_to_set &= ~S_IXUGO;
751 return;
752 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000754 return;
755 }
756 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000757
Al Viro9b5e6852007-12-05 08:24:38 +0000758 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000759 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000760 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000761 return;
762 }
Al Viro9b5e6852007-12-05 08:24:38 +0000763 if ((flags & GENERIC_WRITE) ||
764 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000765 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000766 if ((flags & GENERIC_READ) ||
767 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000768 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000769 if ((flags & GENERIC_EXECUTE) ||
770 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000771 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000772
Joe Perchesb6b38f72010-04-21 03:50:45 +0000773 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000774 return;
775}
776
Steve Frenchce06c9f2007-11-08 21:12:01 +0000777/*
778 Generate access flags to reflect permissions mode is the existing mode.
779 This function is called for every ACE in the DACL whose SID matches
780 with either owner or group or everyone.
781*/
782
783static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
784 __u32 *pace_flags)
785{
786 /* reset access mask */
787 *pace_flags = 0x0;
788
789 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
790 mode &= bits_to_use;
791
792 /* check for R/W/X UGO since we do not know whose flags
793 is this but we have cleared all the bits sans RWX for
794 either user or group or other as per bits_to_use */
795 if (mode & S_IRUGO)
796 *pace_flags |= SET_FILE_READ_RIGHTS;
797 if (mode & S_IWUGO)
798 *pace_flags |= SET_FILE_WRITE_RIGHTS;
799 if (mode & S_IXUGO)
800 *pace_flags |= SET_FILE_EXEC_RIGHTS;
801
Joe Perchesb6b38f72010-04-21 03:50:45 +0000802 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000803 return;
804}
805
Al Viro2b210ad2008-03-29 03:09:18 +0000806static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000807 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
808{
809 int i;
810 __u16 size = 0;
811 __u32 access_req = 0;
812
813 pntace->type = ACCESS_ALLOWED;
814 pntace->flags = 0x0;
815 mode_to_access_flags(nmode, bits, &access_req);
816 if (!access_req)
817 access_req = SET_MINIMUM_RIGHTS;
818 pntace->access_req = cpu_to_le32(access_req);
819
820 pntace->sid.revision = psid->revision;
821 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500822 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000823 pntace->sid.authority[i] = psid->authority[i];
824 for (i = 0; i < psid->num_subauth; i++)
825 pntace->sid.sub_auth[i] = psid->sub_auth[i];
826
827 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
828 pntace->size = cpu_to_le16(size);
829
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000830 return size;
Steve French97837582007-12-31 07:47:21 +0000831}
832
Steve French297647c2007-10-12 04:11:59 +0000833
Steve French953f8682007-10-31 04:54:42 +0000834#ifdef CONFIG_CIFS_DEBUG2
835static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000836{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000837 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000838
839 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000840
Steve French44093ca2007-10-23 21:22:55 +0000841 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000842 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000843 return;
844 }
845
846 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000847 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000848 return;
Steve French44093ca2007-10-23 21:22:55 +0000849 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000850
Steve French44093ca2007-10-23 21:22:55 +0000851 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000852 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000853 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000854 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000855 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000856 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000857 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000858 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
859 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000860 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000861
Steve Frenchd12fd122007-10-03 19:43:19 +0000862 /* BB add length check to make sure that we do not have huge
863 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000864 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000865
Steve Frenchd12fd122007-10-03 19:43:19 +0000866 return;
867}
Steve French953f8682007-10-31 04:54:42 +0000868#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000869
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000870
Steve Frencha750e772007-10-17 22:50:39 +0000871static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000872 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400873 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000874{
875 int i;
876 int num_aces = 0;
877 int acl_size;
878 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000879 struct cifs_ace **ppace;
880
881 /* BB need to add parm so we can store the SID BB */
882
Steve French2b834572007-11-25 10:01:00 +0000883 if (!pdacl) {
884 /* no DACL in the security descriptor, set
885 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400886 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000887 return;
888 }
889
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000890 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000891 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000892 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000893 return;
894 }
895
Joe Perchesb6b38f72010-04-21 03:50:45 +0000896 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000897 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000898 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000899
Steve French7505e052007-11-01 18:03:01 +0000900 /* reset rwx permissions for user/group/other.
901 Also, if num_aces is 0 i.e. DACL has no ACEs,
902 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400903 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000904
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000905 acl_base = (char *)pdacl;
906 acl_size = sizeof(struct cifs_acl);
907
Steve Frenchadbc0352007-10-17 02:12:46 +0000908 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500909 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000910 umode_t user_mask = S_IRWXU;
911 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600912 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000913
Dan Carpenter72501702012-01-11 10:46:27 +0300914 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
915 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000916 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
917 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300918 if (!ppace) {
919 cERROR(1, "DACL memory allocation error");
920 return;
921 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000922
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000923 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000924 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000925#ifdef CONFIG_CIFS_DEBUG2
926 dump_ace(ppace[i], end_of_acl);
927#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500928 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000929 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000930 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400931 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000932 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500933 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000934 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000935 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400936 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000937 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500938 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000939 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000940 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400941 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000942 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500943 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600944 access_flags_to_mode(ppace[i]->access_req,
945 ppace[i]->type,
946 &fattr->cf_mode,
947 &other_mask);
948
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000949
Steve French44093ca2007-10-23 21:22:55 +0000950/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000951 (void *)ppace[i],
952 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000953
Steve French44093ca2007-10-23 21:22:55 +0000954 acl_base = (char *)ppace[i];
955 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000956 }
957
958 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000959 }
960
961 return;
962}
963
Steve Frenchbcb02032007-09-25 16:17:24 +0000964
Steve French97837582007-12-31 07:47:21 +0000965static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
966 struct cifs_sid *pgrpsid, __u64 nmode)
967{
Al Viro2b210ad2008-03-29 03:09:18 +0000968 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000969 struct cifs_acl *pnndacl;
970
971 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
972
973 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
974 pownersid, nmode, S_IRWXU);
975 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
976 pgrpsid, nmode, S_IRWXG);
977 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
978 &sid_everyone, nmode, S_IRWXO);
979
980 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000981 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000982
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000983 return 0;
Steve French97837582007-12-31 07:47:21 +0000984}
985
986
Steve Frenchbcb02032007-09-25 16:17:24 +0000987static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
988{
989 /* BB need to add parm so we can store the SID BB */
990
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000991 /* validate that we do not go past end of ACL - sid must be at least 8
992 bytes long (assuming no sub-auths - e.g. the null SID */
993 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000994 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000995 return -EINVAL;
996 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000997
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000998#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500999 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +00001000 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001001 cFYI(1, "SID revision %d num_auth %d",
1002 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001003
Steve Frenchaf6f4612007-10-16 18:40:37 +00001004 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001005 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
1006 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001007 }
1008
Steve Frenchd12fd122007-10-03 19:43:19 +00001009 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001010 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001011 cFYI(1, "RID 0x%x",
1012 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001013 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001014#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001015
Steve Frenchbcb02032007-09-25 16:17:24 +00001016 return 0;
1017}
1018
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001019
Steve Frenchbcb02032007-09-25 16:17:24 +00001020/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001021static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
1022 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +00001023{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001024 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001025 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1026 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001027 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001028 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001029
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001030 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001031 return -EIO;
1032
Steve Frenchbcb02032007-09-25 16:17:24 +00001033 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001034 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001035 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001036 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001037 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001038 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001039 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +00001040 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +00001041 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1042 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001043 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001044/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001045 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001046 if (rc) {
1047 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001048 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001049 }
1050 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1051 if (rc) {
1052 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
1053 return rc;
1054 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001055
1056 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001057 if (rc) {
1058 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001059 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001060 }
1061 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1062 if (rc) {
1063 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
1064 return rc;
1065 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001066
Steve French7505e052007-11-01 18:03:01 +00001067 if (dacloffset)
1068 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001069 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +00001070 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001071 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001072
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001073 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001074}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001075
Steve French97837582007-12-31 07:47:21 +00001076/* Convert permission bits from mode to equivalent CIFS ACL */
1077static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001078 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001079{
1080 int rc = 0;
1081 __u32 dacloffset;
1082 __u32 ndacloffset;
1083 __u32 sidsoffset;
1084 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001085 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001086 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1087 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1088
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001089 if (nmode != NO_CHANGE_64) { /* chmod */
1090 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001091 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001092 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001093 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001094 dacloffset = le32_to_cpu(pntsd->dacloffset);
1095 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1096 ndacloffset = sizeof(struct cifs_ntsd);
1097 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1098 ndacl_ptr->revision = dacl_ptr->revision;
1099 ndacl_ptr->size = 0;
1100 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001101
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001102 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1103 nmode);
1104 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1105 /* copy sec desc control portion & owner and group sids */
1106 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1107 *aclflag = CIFS_ACL_DACL;
1108 } else {
1109 memcpy(pnntsd, pntsd, secdesclen);
1110 if (uid != NO_CHANGE_32) { /* chown */
1111 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1112 le32_to_cpu(pnntsd->osidoffset));
1113 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1114 GFP_KERNEL);
1115 if (!nowner_sid_ptr)
1116 return -ENOMEM;
1117 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1118 if (rc) {
1119 cFYI(1, "%s: Mapping error %d for owner id %d",
1120 __func__, rc, uid);
1121 kfree(nowner_sid_ptr);
1122 return rc;
1123 }
Jeff Layton36960e42012-11-03 09:37:28 -04001124 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001125 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 }
Jeff Layton36960e42012-11-03 09:37:28 -04001142 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001143 kfree(ngroup_sid_ptr);
1144 *aclflag = CIFS_ACL_GROUP;
1145 }
1146 }
Steve French97837582007-12-31 07:47:21 +00001147
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001148 return rc;
Steve French97837582007-12-31 07:47:21 +00001149}
1150
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001151static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1152 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001153{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001154 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001155 unsigned int xid;
1156 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001157 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1158
1159 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001160 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001161
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001162 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001163 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001164 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001165
Jeff Layton7ffec372010-09-29 19:51:11 -04001166 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001167
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001168 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1169 if (rc)
1170 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001171 return pntsd;
1172}
1173
1174static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1175 const char *path, u32 *pacllen)
1176{
1177 struct cifs_ntsd *pntsd = NULL;
1178 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001179 unsigned int xid;
1180 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001181 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001182 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001183 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001184
Jeff Layton7ffec372010-09-29 19:51:11 -04001185 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001186 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001187
1188 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001189 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001190
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001191 if (backup_cred(cifs_sb))
1192 create_options |= CREATE_OPEN_BACKUP_INTENT;
1193
1194 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
1195 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1196 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001197 if (!rc) {
1198 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1199 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001200 }
1201
Jeff Layton7ffec372010-09-29 19:51:11 -04001202 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001203 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001204
1205 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1206 if (rc)
1207 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001208 return pntsd;
1209}
1210
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001211/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001212struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001213 struct inode *inode, const char *path,
1214 u32 *pacllen)
1215{
1216 struct cifs_ntsd *pntsd = NULL;
1217 struct cifsFileInfo *open_file = NULL;
1218
1219 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001220 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001221 if (!open_file)
1222 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1223
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001224 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001225 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001226 return pntsd;
1227}
1228
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001229 /* Set an ACL on the server */
1230int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1231 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001232{
1233 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001234 unsigned int xid;
1235 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +00001236 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001237 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001238 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001239 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001240
Jeff Layton7ffec372010-09-29 19:51:11 -04001241 if (IS_ERR(tlink))
1242 return PTR_ERR(tlink);
1243
1244 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001245 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001246
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001247 if (backup_cred(cifs_sb))
1248 create_options |= CREATE_OPEN_BACKUP_INTENT;
1249
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001250 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1251 access_flags = WRITE_OWNER;
1252 else
1253 access_flags = WRITE_DAC;
1254
1255 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1256 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1257 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001258 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001259 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001260 goto out;
Steve French97837582007-12-31 07:47:21 +00001261 }
1262
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001263 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001264 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001265
Jeff Layton7ffec372010-09-29 19:51:11 -04001266 CIFSSMBClose(xid, tcon, fid);
1267out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001268 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001269 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001270 return rc;
1271}
Steve French97837582007-12-31 07:47:21 +00001272
Steve French7505e052007-11-01 18:03:01 +00001273/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001274int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001275cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1276 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001277{
1278 struct cifs_ntsd *pntsd = NULL;
1279 u32 acllen = 0;
1280 int rc = 0;
1281
Joe Perchesb6b38f72010-04-21 03:50:45 +00001282 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001283
1284 if (pfid)
1285 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1286 else
1287 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001288
1289 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001290 if (IS_ERR(pntsd)) {
1291 rc = PTR_ERR(pntsd);
1292 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1293 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001294 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001295 kfree(pntsd);
1296 if (rc)
1297 cERROR(1, "parse sec desc failed rc = %d", rc);
1298 }
Steve French7505e052007-11-01 18:03:01 +00001299
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001300 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001301}
Steve French953f8682007-10-31 04:54:42 +00001302
Steve French7505e052007-11-01 18:03:01 +00001303/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001304int
1305id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1306 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001307{
1308 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001309 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001310 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001311 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1312 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001313
Joe Perchesb6b38f72010-04-21 03:50:45 +00001314 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001315
1316 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001317 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001318 if (IS_ERR(pntsd)) {
1319 rc = PTR_ERR(pntsd);
1320 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001321 goto out;
Steve French97837582007-12-31 07:47:21 +00001322 }
1323
Jeff Laytonc78cd832012-11-25 08:00:35 -05001324 /*
1325 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1326 * as chmod disables ACEs and set the security descriptor. Allocate
1327 * memory for the smb header, set security descriptor request security
1328 * descriptor parameters, and secuirty descriptor itself
1329 */
1330 secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
1331 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1332 if (!pnntsd) {
1333 cERROR(1, "Unable to allocate security descriptor");
1334 kfree(pntsd);
1335 return -ENOMEM;
1336 }
1337
1338 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1339 &aclflag);
1340
1341 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1342
1343 if (!rc) {
1344 /* Set the security descriptor */
1345 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1346 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1347 }
1348
1349 kfree(pnntsd);
1350 kfree(pntsd);
1351out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001352 return rc;
Steve French953f8682007-10-31 04:54:42 +00001353}