blob: 9adcdb5a10013477627ec493b730b30d84d9c953 [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;
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500202 unsigned int saval;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500203 char *strptr;
204
205 strptr = sidstr;
206
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500207 sprintf(strptr, "S-%hhu", sidptr->revision);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500208 strptr = sidstr + strlen(sidstr);
209
Jeff Layton852e2292012-11-25 08:00:36 -0500210 for (i = 0; i < NUM_AUTHS; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500211 if (sidptr->authority[i]) {
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500212 sprintf(strptr, "-%hhu", sidptr->authority[i]);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500213 strptr = sidstr + strlen(sidstr);
214 }
215 }
216
217 for (i = 0; i < sidptr->num_subauth; ++i) {
218 saval = le32_to_cpu(sidptr->sub_auth[i]);
Jeff Laytonee13b2b2012-11-25 08:00:38 -0500219 sprintf(strptr, "-%u", saval);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500220 strptr = sidstr + strlen(sidstr);
221 }
222}
223
Jeff Layton436bb432012-11-25 08:00:36 -0500224/*
225 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
226 * the same returns zero, if they do not match returns non-zero.
227 */
228static int
229compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
230{
231 int i;
232 int num_subauth, num_sat, num_saw;
233
234 if ((!ctsid) || (!cwsid))
235 return 1;
236
237 /* compare the revision */
238 if (ctsid->revision != cwsid->revision) {
239 if (ctsid->revision > cwsid->revision)
240 return 1;
241 else
242 return -1;
243 }
244
245 /* compare all of the six auth values */
246 for (i = 0; i < NUM_AUTHS; ++i) {
247 if (ctsid->authority[i] != cwsid->authority[i]) {
248 if (ctsid->authority[i] > cwsid->authority[i])
249 return 1;
250 else
251 return -1;
252 }
253 }
254
255 /* compare all of the subauth values if any */
256 num_sat = ctsid->num_subauth;
257 num_saw = cwsid->num_subauth;
258 num_subauth = num_sat < num_saw ? num_sat : num_saw;
259 if (num_subauth) {
260 for (i = 0; i < num_subauth; ++i) {
261 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
262 if (le32_to_cpu(ctsid->sub_auth[i]) >
263 le32_to_cpu(cwsid->sub_auth[i]))
264 return 1;
265 else
266 return -1;
267 }
268 }
269 }
270
271 return 0; /* sids compare/match */
272}
273
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500274static void
Jeff Layton36960e42012-11-03 09:37:28 -0400275cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
276{
Jeff Layton36f87ee2012-11-25 08:00:37 -0500277 int i;
278
279 dst->revision = src->revision;
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500280 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500281 for (i = 0; i < NUM_AUTHS; ++i)
282 dst->authority[i] = src->authority[i];
283 for (i = 0; i < dst->num_subauth; ++i)
284 dst->sub_auth[i] = src->sub_auth[i];
Jeff Layton36960e42012-11-03 09:37:28 -0400285}
286
287static void
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500288id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
289 struct cifs_sid_id **psidid, char *typestr)
290{
291 int rc;
292 char *strptr;
293 struct rb_node *node = root->rb_node;
294 struct rb_node *parent = NULL;
295 struct rb_node **linkto = &(root->rb_node);
296 struct cifs_sid_id *lsidid;
297
298 while (node) {
299 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
300 parent = node;
301 rc = compare_sids(sidptr, &((lsidid)->sid));
302 if (rc > 0) {
303 linkto = &(node->rb_left);
304 node = node->rb_left;
305 } else if (rc < 0) {
306 linkto = &(node->rb_right);
307 node = node->rb_right;
308 }
309 }
310
Jeff Layton36960e42012-11-03 09:37:28 -0400311 cifs_copy_sid(&(*psidid)->sid, sidptr);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500312 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
313 (*psidid)->refcount = 0;
314
315 sprintf((*psidid)->sidstr, "%s", typestr);
316 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
317 sid_to_str(&(*psidid)->sid, strptr);
318
319 clear_bit(SID_ID_PENDING, &(*psidid)->state);
320 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
321
322 rb_link_node(&(*psidid)->rbnode, parent, linkto);
323 rb_insert_color(&(*psidid)->rbnode, root);
324}
325
326static struct cifs_sid_id *
327id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
328{
329 int rc;
330 struct rb_node *node = root->rb_node;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500331 struct cifs_sid_id *lsidid;
332
333 while (node) {
334 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500335 rc = compare_sids(sidptr, &((lsidid)->sid));
336 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500337 node = node->rb_left;
338 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500339 node = node->rb_right;
340 } else /* node found */
341 return lsidid;
342 }
343
344 return NULL;
345}
346
347static int
348sidid_pending_wait(void *unused)
349{
350 schedule();
351 return signal_pending(current) ? -ERESTARTSYS : 0;
352}
353
354static int
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500355id_to_sid(unsigned long cid, uint sidtype, struct cifs_sid *ssid)
356{
357 int rc = 0;
358 struct key *sidkey;
359 const struct cred *saved_cred;
360 struct cifs_sid *lsid;
361 struct cifs_sid_id *psidid, *npsidid;
362 struct rb_root *cidtree;
363 spinlock_t *cidlock;
364
365 if (sidtype == SIDOWNER) {
366 cidlock = &siduidlock;
367 cidtree = &uidtree;
368 } else if (sidtype == SIDGROUP) {
369 cidlock = &sidgidlock;
370 cidtree = &gidtree;
371 } else
372 return -EINVAL;
373
374 spin_lock(cidlock);
375 psidid = sid_rb_search(cidtree, cid);
376
377 if (!psidid) { /* node does not exist, allocate one & attempt adding */
378 spin_unlock(cidlock);
379 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
380 if (!npsidid)
381 return -ENOMEM;
382
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500383 npsidid->sidstr = kmalloc(SID_STRING_MAX, GFP_KERNEL);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500384 if (!npsidid->sidstr) {
385 kfree(npsidid);
386 return -ENOMEM;
387 }
388
389 spin_lock(cidlock);
390 psidid = sid_rb_search(cidtree, cid);
391 if (psidid) { /* node happened to get inserted meanwhile */
392 ++psidid->refcount;
393 spin_unlock(cidlock);
394 kfree(npsidid->sidstr);
395 kfree(npsidid);
396 } else {
397 psidid = npsidid;
398 sid_rb_insert(cidtree, cid, &psidid,
399 sidtype == SIDOWNER ? "oi:" : "gi:");
400 ++psidid->refcount;
401 spin_unlock(cidlock);
402 }
403 } else {
404 ++psidid->refcount;
405 spin_unlock(cidlock);
406 }
407
408 /*
409 * If we are here, it is safe to access psidid and its fields
410 * since a reference was taken earlier while holding the spinlock.
411 * A reference on the node is put without holding the spinlock
412 * and it is OK to do so in this case, shrinker will not erase
413 * this node until all references are put and we do not access
414 * any fields of the node after a reference is put .
415 */
416 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
Jeff Layton36960e42012-11-03 09:37:28 -0400417 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500418 psidid->time = jiffies; /* update ts for accessing */
419 goto id_sid_out;
420 }
421
422 if (time_after(psidid->time + SID_MAP_RETRY, jiffies)) {
423 rc = -EINVAL;
424 goto id_sid_out;
425 }
426
427 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
428 saved_cred = override_creds(root_cred);
429 sidkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
430 if (IS_ERR(sidkey)) {
431 rc = -EINVAL;
432 cFYI(1, "%s: Can't map and id to a SID", __func__);
Jeff Layton36f87ee2012-11-25 08:00:37 -0500433 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
Jeff Layton36960e42012-11-03 09:37:28 -0400434 rc = -EIO;
435 cFYI(1, "%s: Downcall contained malformed key "
436 "(datalen=%hu)", __func__, sidkey->datalen);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500437 } else {
438 lsid = (struct cifs_sid *)sidkey->payload.data;
Jeff Layton36960e42012-11-03 09:37:28 -0400439 cifs_copy_sid(&psidid->sid, lsid);
440 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500441 set_bit(SID_ID_MAPPED, &psidid->state);
442 key_put(sidkey);
443 kfree(psidid->sidstr);
444 }
445 psidid->time = jiffies; /* update ts for accessing */
446 revert_creds(saved_cred);
447 clear_bit(SID_ID_PENDING, &psidid->state);
448 wake_up_bit(&psidid->state, SID_ID_PENDING);
449 } else {
450 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
451 sidid_pending_wait, TASK_INTERRUPTIBLE);
452 if (rc) {
453 cFYI(1, "%s: sidid_pending_wait interrupted %d",
454 __func__, rc);
455 --psidid->refcount;
456 return rc;
457 }
458 if (test_bit(SID_ID_MAPPED, &psidid->state))
Jeff Layton36960e42012-11-03 09:37:28 -0400459 cifs_copy_sid(ssid, &psidid->sid);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500460 else
461 rc = -EINVAL;
462 }
463id_sid_out:
464 --psidid->refcount;
465 return rc;
466}
467
468static int
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500469sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
470 struct cifs_fattr *fattr, uint sidtype)
471{
472 int rc;
473 unsigned long cid;
474 struct key *idkey;
475 const struct cred *saved_cred;
476 struct cifs_sid_id *psidid, *npsidid;
477 struct rb_root *cidtree;
478 spinlock_t *cidlock;
479
480 if (sidtype == SIDOWNER) {
481 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
482 cidlock = &siduidlock;
483 cidtree = &uidtree;
484 } else if (sidtype == SIDGROUP) {
485 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
486 cidlock = &sidgidlock;
487 cidtree = &gidtree;
488 } else
489 return -ENOENT;
490
491 spin_lock(cidlock);
492 psidid = id_rb_search(cidtree, psid);
493
494 if (!psidid) { /* node does not exist, allocate one & attempt adding */
495 spin_unlock(cidlock);
496 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
497 if (!npsidid)
498 return -ENOMEM;
499
Jeff Layton30c9d6c2012-11-25 08:00:37 -0500500 npsidid->sidstr = kmalloc(SID_STRING_MAX, GFP_KERNEL);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500501 if (!npsidid->sidstr) {
502 kfree(npsidid);
503 return -ENOMEM;
504 }
505
506 spin_lock(cidlock);
507 psidid = id_rb_search(cidtree, psid);
508 if (psidid) { /* node happened to get inserted meanwhile */
509 ++psidid->refcount;
510 spin_unlock(cidlock);
511 kfree(npsidid->sidstr);
512 kfree(npsidid);
513 } else {
514 psidid = npsidid;
515 id_rb_insert(cidtree, psid, &psidid,
516 sidtype == SIDOWNER ? "os:" : "gs:");
517 ++psidid->refcount;
518 spin_unlock(cidlock);
519 }
520 } else {
521 ++psidid->refcount;
522 spin_unlock(cidlock);
523 }
524
525 /*
526 * If we are here, it is safe to access psidid and its fields
527 * since a reference was taken earlier while holding the spinlock.
528 * A reference on the node is put without holding the spinlock
529 * and it is OK to do so in this case, shrinker will not erase
530 * this node until all references are put and we do not access
531 * any fields of the node after a reference is put .
532 */
533 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
534 cid = psidid->id;
535 psidid->time = jiffies; /* update ts for accessing */
536 goto sid_to_id_out;
537 }
538
539 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
540 goto sid_to_id_out;
541
542 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
543 saved_cred = override_creds(root_cred);
544 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
545 if (IS_ERR(idkey))
546 cFYI(1, "%s: Can't map SID to an id", __func__);
547 else {
548 cid = *(unsigned long *)idkey->payload.value;
549 psidid->id = cid;
550 set_bit(SID_ID_MAPPED, &psidid->state);
551 key_put(idkey);
552 kfree(psidid->sidstr);
553 }
554 revert_creds(saved_cred);
555 psidid->time = jiffies; /* update ts for accessing */
556 clear_bit(SID_ID_PENDING, &psidid->state);
557 wake_up_bit(&psidid->state, SID_ID_PENDING);
558 } else {
559 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
560 sidid_pending_wait, TASK_INTERRUPTIBLE);
561 if (rc) {
562 cFYI(1, "%s: sidid_pending_wait interrupted %d",
563 __func__, rc);
564 --psidid->refcount; /* decremented without spinlock */
565 return rc;
566 }
567 if (test_bit(SID_ID_MAPPED, &psidid->state))
568 cid = psidid->id;
569 }
570
571sid_to_id_out:
572 --psidid->refcount; /* decremented without spinlock */
573 if (sidtype == SIDOWNER)
574 fattr->cf_uid = cid;
575 else
576 fattr->cf_gid = cid;
577
578 return 0;
579}
580
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500581int
582init_cifs_idmap(void)
583{
584 struct cred *cred;
585 struct key *keyring;
586 int ret;
587
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400588 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500589
590 /* create an override credential set with a special thread keyring in
591 * which requests are cached
592 *
593 * this is used to prevent malicious redirections from being installed
594 * with add_key().
595 */
596 cred = prepare_kernel_cred(NULL);
597 if (!cred)
598 return -ENOMEM;
599
600 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
601 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
602 KEY_USR_VIEW | KEY_USR_READ,
603 KEY_ALLOC_NOT_IN_QUOTA);
604 if (IS_ERR(keyring)) {
605 ret = PTR_ERR(keyring);
606 goto failed_put_cred;
607 }
608
609 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
610 if (ret < 0)
611 goto failed_put_key;
612
613 ret = register_key_type(&cifs_idmap_key_type);
614 if (ret < 0)
615 goto failed_put_key;
616
617 /* instruct request_key() to use this special keyring as a cache for
618 * the results it looks up */
David Howells700920e2012-01-18 15:31:45 +0000619 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500620 cred->thread_keyring = keyring;
621 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
622 root_cred = cred;
623
624 spin_lock_init(&siduidlock);
625 uidtree = RB_ROOT;
626 spin_lock_init(&sidgidlock);
627 gidtree = RB_ROOT;
628
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500629 spin_lock_init(&uidsidlock);
630 siduidtree = RB_ROOT;
631 spin_lock_init(&gidsidlock);
632 sidgidtree = RB_ROOT;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500633 register_shrinker(&cifs_shrinker);
634
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400635 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500636 return 0;
637
638failed_put_key:
639 key_put(keyring);
640failed_put_cred:
641 put_cred(cred);
642 return ret;
643}
644
645void
646exit_cifs_idmap(void)
647{
648 key_revoke(root_cred->thread_keyring);
649 unregister_key_type(&cifs_idmap_key_type);
650 put_cred(root_cred);
651 unregister_shrinker(&cifs_shrinker);
Jeff Laytonac3aa2f2012-07-23 13:14:28 -0400652 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500653}
654
655void
656cifs_destroy_idmaptrees(void)
657{
658 struct rb_root *root;
659 struct rb_node *node;
660
661 root = &uidtree;
662 spin_lock(&siduidlock);
663 while ((node = rb_first(root)))
664 rb_erase(node, root);
665 spin_unlock(&siduidlock);
666
667 root = &gidtree;
668 spin_lock(&sidgidlock);
669 while ((node = rb_first(root)))
670 rb_erase(node, root);
671 spin_unlock(&sidgidlock);
Shirish Pargaonkar21fed0d2011-08-09 14:30:48 -0500672
673 root = &siduidtree;
674 spin_lock(&uidsidlock);
675 while ((node = rb_first(root)))
676 rb_erase(node, root);
677 spin_unlock(&uidsidlock);
678
679 root = &sidgidtree;
680 spin_lock(&gidsidlock);
681 while ((node = rb_first(root)))
682 rb_erase(node, root);
683 spin_unlock(&gidsidlock);
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500684}
Steve French297647c2007-10-12 04:11:59 +0000685
Steve French97837582007-12-31 07:47:21 +0000686/* copy ntsd, owner sid, and group sid from a security descriptor to another */
687static void copy_sec_desc(const struct cifs_ntsd *pntsd,
688 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
689{
Steve French97837582007-12-31 07:47:21 +0000690 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
691 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
692
693 /* copy security descriptor control portion */
694 pnntsd->revision = pntsd->revision;
695 pnntsd->type = pntsd->type;
696 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
697 pnntsd->sacloffset = 0;
698 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
699 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
700
701 /* copy owner sid */
702 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
703 le32_to_cpu(pntsd->osidoffset));
704 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
Jeff Layton36960e42012-11-03 09:37:28 -0400705 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000706
707 /* copy group sid */
708 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
709 le32_to_cpu(pntsd->gsidoffset));
710 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
711 sizeof(struct cifs_sid));
Jeff Layton36960e42012-11-03 09:37:28 -0400712 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
Steve French97837582007-12-31 07:47:21 +0000713
714 return;
715}
716
717
Steve French630f3f0c2007-10-25 21:17:17 +0000718/*
719 change posix mode to reflect permissions
720 pmode is the existing mode (we only want to overwrite part of this
721 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
722*/
Al Viro9b5e6852007-12-05 08:24:38 +0000723static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000724 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000725{
Al Viro9b5e6852007-12-05 08:24:38 +0000726 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000727 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000728 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000729 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000730 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000731 for the operation you are trying to perform for your user */
732
733 /* For deny ACEs we change the mask so that subsequent allow access
734 control entries do not turn on the bits we are denying */
735 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000736 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000737 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000738
Al Viro9b5e6852007-12-05 08:24:38 +0000739 if ((flags & GENERIC_WRITE) ||
740 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000741 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000742 if ((flags & GENERIC_READ) ||
743 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000744 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000745 if ((flags & GENERIC_EXECUTE) ||
746 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000747 *pbits_to_set &= ~S_IXUGO;
748 return;
749 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000750 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000751 return;
752 }
753 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000754
Al Viro9b5e6852007-12-05 08:24:38 +0000755 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000756 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000757 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000758 return;
759 }
Al Viro9b5e6852007-12-05 08:24:38 +0000760 if ((flags & GENERIC_WRITE) ||
761 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000762 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000763 if ((flags & GENERIC_READ) ||
764 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000765 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000766 if ((flags & GENERIC_EXECUTE) ||
767 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000768 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000769
Joe Perchesb6b38f72010-04-21 03:50:45 +0000770 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000771 return;
772}
773
Steve Frenchce06c9f2007-11-08 21:12:01 +0000774/*
775 Generate access flags to reflect permissions mode is the existing mode.
776 This function is called for every ACE in the DACL whose SID matches
777 with either owner or group or everyone.
778*/
779
780static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
781 __u32 *pace_flags)
782{
783 /* reset access mask */
784 *pace_flags = 0x0;
785
786 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
787 mode &= bits_to_use;
788
789 /* check for R/W/X UGO since we do not know whose flags
790 is this but we have cleared all the bits sans RWX for
791 either user or group or other as per bits_to_use */
792 if (mode & S_IRUGO)
793 *pace_flags |= SET_FILE_READ_RIGHTS;
794 if (mode & S_IWUGO)
795 *pace_flags |= SET_FILE_WRITE_RIGHTS;
796 if (mode & S_IXUGO)
797 *pace_flags |= SET_FILE_EXEC_RIGHTS;
798
Joe Perchesb6b38f72010-04-21 03:50:45 +0000799 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000800 return;
801}
802
Al Viro2b210ad2008-03-29 03:09:18 +0000803static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000804 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
805{
806 int i;
807 __u16 size = 0;
808 __u32 access_req = 0;
809
810 pntace->type = ACCESS_ALLOWED;
811 pntace->flags = 0x0;
812 mode_to_access_flags(nmode, bits, &access_req);
813 if (!access_req)
814 access_req = SET_MINIMUM_RIGHTS;
815 pntace->access_req = cpu_to_le32(access_req);
816
817 pntace->sid.revision = psid->revision;
818 pntace->sid.num_subauth = psid->num_subauth;
Jeff Layton852e2292012-11-25 08:00:36 -0500819 for (i = 0; i < NUM_AUTHS; i++)
Steve French97837582007-12-31 07:47:21 +0000820 pntace->sid.authority[i] = psid->authority[i];
821 for (i = 0; i < psid->num_subauth; i++)
822 pntace->sid.sub_auth[i] = psid->sub_auth[i];
823
824 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
825 pntace->size = cpu_to_le16(size);
826
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000827 return size;
Steve French97837582007-12-31 07:47:21 +0000828}
829
Steve French297647c2007-10-12 04:11:59 +0000830
Steve French953f8682007-10-31 04:54:42 +0000831#ifdef CONFIG_CIFS_DEBUG2
832static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000833{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000834 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000835
836 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000837
Steve French44093ca2007-10-23 21:22:55 +0000838 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000839 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000840 return;
841 }
842
843 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000844 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000845 return;
Steve French44093ca2007-10-23 21:22:55 +0000846 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000847
Steve French44093ca2007-10-23 21:22:55 +0000848 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000849 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000850 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000851 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000852 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000853 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000854 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000855 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
856 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000857 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000858
Steve Frenchd12fd122007-10-03 19:43:19 +0000859 /* BB add length check to make sure that we do not have huge
860 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000861 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000862
Steve Frenchd12fd122007-10-03 19:43:19 +0000863 return;
864}
Steve French953f8682007-10-31 04:54:42 +0000865#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000866
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000867
Steve Frencha750e772007-10-17 22:50:39 +0000868static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000869 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400870 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000871{
872 int i;
873 int num_aces = 0;
874 int acl_size;
875 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000876 struct cifs_ace **ppace;
877
878 /* BB need to add parm so we can store the SID BB */
879
Steve French2b834572007-11-25 10:01:00 +0000880 if (!pdacl) {
881 /* no DACL in the security descriptor, set
882 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400883 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000884 return;
885 }
886
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000887 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000888 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000889 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000890 return;
891 }
892
Joe Perchesb6b38f72010-04-21 03:50:45 +0000893 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000894 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000895 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000896
Steve French7505e052007-11-01 18:03:01 +0000897 /* reset rwx permissions for user/group/other.
898 Also, if num_aces is 0 i.e. DACL has no ACEs,
899 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400900 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000901
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000902 acl_base = (char *)pdacl;
903 acl_size = sizeof(struct cifs_acl);
904
Steve Frenchadbc0352007-10-17 02:12:46 +0000905 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -0500906 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000907 umode_t user_mask = S_IRWXU;
908 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600909 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000910
Dan Carpenter72501702012-01-11 10:46:27 +0300911 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
912 return;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000913 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
914 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300915 if (!ppace) {
916 cERROR(1, "DACL memory allocation error");
917 return;
918 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000919
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000920 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000921 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000922#ifdef CONFIG_CIFS_DEBUG2
923 dump_ace(ppace[i], end_of_acl);
924#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500925 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000926 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000927 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400928 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000929 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500930 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000931 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000932 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400933 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000934 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500935 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000936 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000937 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400938 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000939 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500940 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600941 access_flags_to_mode(ppace[i]->access_req,
942 ppace[i]->type,
943 &fattr->cf_mode,
944 &other_mask);
945
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000946
Steve French44093ca2007-10-23 21:22:55 +0000947/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000948 (void *)ppace[i],
949 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000950
Steve French44093ca2007-10-23 21:22:55 +0000951 acl_base = (char *)ppace[i];
952 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000953 }
954
955 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000956 }
957
958 return;
959}
960
Steve Frenchbcb02032007-09-25 16:17:24 +0000961
Steve French97837582007-12-31 07:47:21 +0000962static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
963 struct cifs_sid *pgrpsid, __u64 nmode)
964{
Al Viro2b210ad2008-03-29 03:09:18 +0000965 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000966 struct cifs_acl *pnndacl;
967
968 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
969
970 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
971 pownersid, nmode, S_IRWXU);
972 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
973 pgrpsid, nmode, S_IRWXG);
974 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
975 &sid_everyone, nmode, S_IRWXO);
976
977 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000978 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000979
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000980 return 0;
Steve French97837582007-12-31 07:47:21 +0000981}
982
983
Steve Frenchbcb02032007-09-25 16:17:24 +0000984static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
985{
986 /* BB need to add parm so we can store the SID BB */
987
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000988 /* validate that we do not go past end of ACL - sid must be at least 8
989 bytes long (assuming no sub-auths - e.g. the null SID */
990 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000991 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000992 return -EINVAL;
993 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000994
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000995#ifdef CONFIG_CIFS_DEBUG2
Jeff Laytonfc03d8a2012-11-25 08:00:35 -0500996 if (psid->num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000997 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000998 cFYI(1, "SID revision %d num_auth %d",
999 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001000
Steve Frenchaf6f4612007-10-16 18:40:37 +00001001 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001002 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
1003 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001004 }
1005
Steve Frenchd12fd122007-10-03 19:43:19 +00001006 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001007 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001008 cFYI(1, "RID 0x%x",
1009 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001010 }
Jeff Laytonfc03d8a2012-11-25 08:00:35 -05001011#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001012
Steve Frenchbcb02032007-09-25 16:17:24 +00001013 return 0;
1014}
1015
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001016
Steve Frenchbcb02032007-09-25 16:17:24 +00001017/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001018static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
1019 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +00001020{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001021 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +00001022 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
1023 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +00001024 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +00001025 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +00001026
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001027 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001028 return -EIO;
1029
Steve Frenchbcb02032007-09-25 16:17:24 +00001030 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001031 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +00001032 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +00001033 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +00001034 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +00001035 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001036 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +00001037 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +00001038 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
1039 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +00001040 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001041/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +00001042 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001043 if (rc) {
1044 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001045 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001046 }
1047 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
1048 if (rc) {
1049 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
1050 return rc;
1051 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001052
1053 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001054 if (rc) {
1055 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +00001056 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001057 }
1058 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
1059 if (rc) {
1060 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
1061 return rc;
1062 }
Steve Frenchbcb02032007-09-25 16:17:24 +00001063
Steve French7505e052007-11-01 18:03:01 +00001064 if (dacloffset)
1065 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001066 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +00001067 else
Joe Perchesb6b38f72010-04-21 03:50:45 +00001068 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +00001069
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001070 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +00001071}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001072
Steve French97837582007-12-31 07:47:21 +00001073/* Convert permission bits from mode to equivalent CIFS ACL */
1074static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001075 __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
Steve French97837582007-12-31 07:47:21 +00001076{
1077 int rc = 0;
1078 __u32 dacloffset;
1079 __u32 ndacloffset;
1080 __u32 sidsoffset;
1081 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001082 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
Steve French97837582007-12-31 07:47:21 +00001083 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
1084 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
1085
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001086 if (nmode != NO_CHANGE_64) { /* chmod */
1087 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001088 le32_to_cpu(pntsd->osidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001089 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve French97837582007-12-31 07:47:21 +00001090 le32_to_cpu(pntsd->gsidoffset));
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001091 dacloffset = le32_to_cpu(pntsd->dacloffset);
1092 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
1093 ndacloffset = sizeof(struct cifs_ntsd);
1094 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
1095 ndacl_ptr->revision = dacl_ptr->revision;
1096 ndacl_ptr->size = 0;
1097 ndacl_ptr->num_aces = 0;
Steve French97837582007-12-31 07:47:21 +00001098
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001099 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
1100 nmode);
1101 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
1102 /* copy sec desc control portion & owner and group sids */
1103 copy_sec_desc(pntsd, pnntsd, sidsoffset);
1104 *aclflag = CIFS_ACL_DACL;
1105 } else {
1106 memcpy(pnntsd, pntsd, secdesclen);
1107 if (uid != NO_CHANGE_32) { /* chown */
1108 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1109 le32_to_cpu(pnntsd->osidoffset));
1110 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1111 GFP_KERNEL);
1112 if (!nowner_sid_ptr)
1113 return -ENOMEM;
1114 rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
1115 if (rc) {
1116 cFYI(1, "%s: Mapping error %d for owner id %d",
1117 __func__, rc, uid);
1118 kfree(nowner_sid_ptr);
1119 return rc;
1120 }
Jeff Layton36960e42012-11-03 09:37:28 -04001121 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001122 kfree(nowner_sid_ptr);
1123 *aclflag = CIFS_ACL_OWNER;
1124 }
1125 if (gid != NO_CHANGE_32) { /* chgrp */
1126 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
1127 le32_to_cpu(pnntsd->gsidoffset));
1128 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
1129 GFP_KERNEL);
1130 if (!ngroup_sid_ptr)
1131 return -ENOMEM;
1132 rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
1133 if (rc) {
1134 cFYI(1, "%s: Mapping error %d for group id %d",
1135 __func__, rc, gid);
1136 kfree(ngroup_sid_ptr);
1137 return rc;
1138 }
Jeff Layton36960e42012-11-03 09:37:28 -04001139 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001140 kfree(ngroup_sid_ptr);
1141 *aclflag = CIFS_ACL_GROUP;
1142 }
1143 }
Steve French97837582007-12-31 07:47:21 +00001144
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001145 return rc;
Steve French97837582007-12-31 07:47:21 +00001146}
1147
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001148static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
1149 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001150{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001151 struct cifs_ntsd *pntsd = NULL;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001152 unsigned int xid;
1153 int rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001154 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1155
1156 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001157 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001158
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001159 xid = get_xid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001160 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001161 free_xid(xid);
Steve French8b1327f2008-03-14 22:37:16 +00001162
Jeff Layton7ffec372010-09-29 19:51:11 -04001163 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001164
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001165 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1166 if (rc)
1167 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001168 return pntsd;
1169}
1170
1171static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1172 const char *path, u32 *pacllen)
1173{
1174 struct cifs_ntsd *pntsd = NULL;
1175 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001176 unsigned int xid;
1177 int rc, create_options = 0;
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001178 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001179 struct cifs_tcon *tcon;
Jeff Layton7ffec372010-09-29 19:51:11 -04001180 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001181
Jeff Layton7ffec372010-09-29 19:51:11 -04001182 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001183 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001184
1185 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001186 xid = get_xid();
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001187
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001188 if (backup_cred(cifs_sb))
1189 create_options |= CREATE_OPEN_BACKUP_INTENT;
1190
1191 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
1192 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1193 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001194 if (!rc) {
1195 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1196 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001197 }
1198
Jeff Layton7ffec372010-09-29 19:51:11 -04001199 cifs_put_tlink(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001200 free_xid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001201
1202 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1203 if (rc)
1204 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001205 return pntsd;
1206}
1207
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001208/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001209struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001210 struct inode *inode, const char *path,
1211 u32 *pacllen)
1212{
1213 struct cifs_ntsd *pntsd = NULL;
1214 struct cifsFileInfo *open_file = NULL;
1215
1216 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001217 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001218 if (!open_file)
1219 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1220
Pavel Shilovsky4b4de762012-09-18 16:20:26 -07001221 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001222 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001223 return pntsd;
1224}
1225
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001226 /* Set an ACL on the server */
1227int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1228 struct inode *inode, const char *path, int aclflag)
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001229{
1230 int oplock = 0;
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001231 unsigned int xid;
1232 int rc, access_flags, create_options = 0;
Steve French97837582007-12-31 07:47:21 +00001233 __u16 fid;
Steve French96daf2b2011-05-27 04:34:02 +00001234 struct cifs_tcon *tcon;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001235 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
Jeff Layton7ffec372010-09-29 19:51:11 -04001236 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001237
Jeff Layton7ffec372010-09-29 19:51:11 -04001238 if (IS_ERR(tlink))
1239 return PTR_ERR(tlink);
1240
1241 tcon = tlink_tcon(tlink);
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001242 xid = get_xid();
Steve French97837582007-12-31 07:47:21 +00001243
Shirish Pargaonkar3d3ea8e2011-09-26 09:56:44 -05001244 if (backup_cred(cifs_sb))
1245 create_options |= CREATE_OPEN_BACKUP_INTENT;
1246
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001247 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1248 access_flags = WRITE_OWNER;
1249 else
1250 access_flags = WRITE_DAC;
1251
1252 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
1253 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
1254 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001255 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001256 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001257 goto out;
Steve French97837582007-12-31 07:47:21 +00001258 }
1259
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001260 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001261 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001262
Jeff Layton7ffec372010-09-29 19:51:11 -04001263 CIFSSMBClose(xid, tcon, fid);
1264out:
Pavel Shilovsky6d5786a2012-06-20 11:21:16 +04001265 free_xid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001266 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001267 return rc;
1268}
Steve French97837582007-12-31 07:47:21 +00001269
Steve French7505e052007-11-01 18:03:01 +00001270/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001271int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001272cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1273 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001274{
1275 struct cifs_ntsd *pntsd = NULL;
1276 u32 acllen = 0;
1277 int rc = 0;
1278
Joe Perchesb6b38f72010-04-21 03:50:45 +00001279 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001280
1281 if (pfid)
1282 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1283 else
1284 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001285
1286 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001287 if (IS_ERR(pntsd)) {
1288 rc = PTR_ERR(pntsd);
1289 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1290 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001291 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001292 kfree(pntsd);
1293 if (rc)
1294 cERROR(1, "parse sec desc failed rc = %d", rc);
1295 }
Steve French7505e052007-11-01 18:03:01 +00001296
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001297 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001298}
Steve French953f8682007-10-31 04:54:42 +00001299
Steve French7505e052007-11-01 18:03:01 +00001300/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001301int
1302id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1303 uid_t uid, gid_t gid)
Steve French953f8682007-10-31 04:54:42 +00001304{
1305 int rc = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05001306 int aclflag = CIFS_ACL_DACL; /* default flag to set */
Steve Frenchcce246e2008-04-09 20:55:31 +00001307 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001308 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1309 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001310
Joe Perchesb6b38f72010-04-21 03:50:45 +00001311 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001312
1313 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001314 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001315 if (IS_ERR(pntsd)) {
1316 rc = PTR_ERR(pntsd);
1317 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
Jeff Laytonc78cd832012-11-25 08:00:35 -05001318 goto out;
Steve French97837582007-12-31 07:47:21 +00001319 }
1320
Jeff Laytonc78cd832012-11-25 08:00:35 -05001321 /*
1322 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1323 * as chmod disables ACEs and set the security descriptor. Allocate
1324 * memory for the smb header, set security descriptor request security
1325 * descriptor parameters, and secuirty descriptor itself
1326 */
1327 secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
1328 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1329 if (!pnntsd) {
1330 cERROR(1, "Unable to allocate security descriptor");
1331 kfree(pntsd);
1332 return -ENOMEM;
1333 }
1334
1335 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1336 &aclflag);
1337
1338 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1339
1340 if (!rc) {
1341 /* Set the security descriptor */
1342 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1343 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1344 }
1345
1346 kfree(pnntsd);
1347 kfree(pntsd);
1348out:
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001349 return rc;
Steve French953f8682007-10-31 04:54:42 +00001350}