blob: a4aa0f0af5c3f157350ac71e744cfd55f02e25fe [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
Steve French297647c2007-10-12 04:11:59 +000036
Steve Frenchaf6f4612007-10-16 18:40:37 +000037static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
Steve French297647c2007-10-12 04:11:59 +000038 {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
39 {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
Jeff Layton536abdb2008-07-12 13:48:00 -070040 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
41 {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
42 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
43 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
44 {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
Steve French44093ca2007-10-23 21:22:55 +000045;
Steve French297647c2007-10-12 04:11:59 +000046
47
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060048/* security id for everyone/world system group */
Shirish Pargaonkare01b6402007-10-30 04:45:14 +000049static const struct cifs_sid sid_everyone = {
50 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -060051/* security id for Authenticated Users system group */
52static const struct cifs_sid sid_authusers = {
53 1, 1, {0, 0, 0, 0, 0, 5}, {11} };
Steve Frenchbcb02032007-09-25 16:17:24 +000054/* group users */
Steve Frenchad7a2922008-02-07 23:25:02 +000055static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000056
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050057const struct cred *root_cred;
58
59static void
60shrink_idmap_tree(struct rb_root *root, int nr_to_scan, int *nr_rem,
61 int *nr_del)
62{
63 struct rb_node *node;
64 struct rb_node *tmp;
65 struct cifs_sid_id *psidid;
66
67 node = rb_first(root);
68 while (node) {
69 tmp = node;
70 node = rb_next(tmp);
71 psidid = rb_entry(tmp, struct cifs_sid_id, rbnode);
72 if (nr_to_scan == 0 || *nr_del == nr_to_scan)
73 ++(*nr_rem);
74 else {
75 if (time_after(jiffies, psidid->time + SID_MAP_EXPIRE)
76 && psidid->refcount == 0) {
77 rb_erase(tmp, root);
78 ++(*nr_del);
79 } else
80 ++(*nr_rem);
81 }
82 }
83}
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -050084
85/*
86 * Run idmap cache shrinker.
87 */
88static int
89cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
90{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -050091 int nr_del = 0;
92 int nr_rem = 0;
93 struct rb_root *root;
94
95 root = &uidtree;
96 spin_lock(&siduidlock);
97 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
98 spin_unlock(&siduidlock);
99
100 root = &gidtree;
101 spin_lock(&sidgidlock);
102 shrink_idmap_tree(root, nr_to_scan, &nr_rem, &nr_del);
103 spin_unlock(&sidgidlock);
104
105 return nr_rem;
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500106}
107
108static struct shrinker cifs_shrinker = {
109 .shrink = cifs_idmap_shrinker,
110 .seeks = DEFAULT_SEEKS,
111};
112
113static int
114cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
115{
116 char *payload;
117
118 payload = kmalloc(datalen, GFP_KERNEL);
119 if (!payload)
120 return -ENOMEM;
121
122 memcpy(payload, data, datalen);
123 key->payload.data = payload;
124 return 0;
125}
126
127static inline void
128cifs_idmap_key_destroy(struct key *key)
129{
130 kfree(key->payload.data);
131}
132
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500133struct key_type cifs_idmap_key_type = {
134 .name = "cifs.cifs_idmap",
135 .instantiate = cifs_idmap_key_instantiate,
136 .destroy = cifs_idmap_key_destroy,
137 .describe = user_describe,
138 .match = user_match,
139};
140
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500141static void
142sid_to_str(struct cifs_sid *sidptr, char *sidstr)
143{
144 int i;
145 unsigned long saval;
146 char *strptr;
147
148 strptr = sidstr;
149
150 sprintf(strptr, "%s", "S");
151 strptr = sidstr + strlen(sidstr);
152
153 sprintf(strptr, "-%d", sidptr->revision);
154 strptr = sidstr + strlen(sidstr);
155
156 for (i = 0; i < 6; ++i) {
157 if (sidptr->authority[i]) {
158 sprintf(strptr, "-%d", sidptr->authority[i]);
159 strptr = sidstr + strlen(sidstr);
160 }
161 }
162
163 for (i = 0; i < sidptr->num_subauth; ++i) {
164 saval = le32_to_cpu(sidptr->sub_auth[i]);
165 sprintf(strptr, "-%ld", saval);
166 strptr = sidstr + strlen(sidstr);
167 }
168}
169
170static void
171id_rb_insert(struct rb_root *root, struct cifs_sid *sidptr,
172 struct cifs_sid_id **psidid, char *typestr)
173{
174 int rc;
175 char *strptr;
176 struct rb_node *node = root->rb_node;
177 struct rb_node *parent = NULL;
178 struct rb_node **linkto = &(root->rb_node);
179 struct cifs_sid_id *lsidid;
180
181 while (node) {
182 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
183 parent = node;
184 rc = compare_sids(sidptr, &((lsidid)->sid));
185 if (rc > 0) {
186 linkto = &(node->rb_left);
187 node = node->rb_left;
188 } else if (rc < 0) {
189 linkto = &(node->rb_right);
190 node = node->rb_right;
191 }
192 }
193
194 memcpy(&(*psidid)->sid, sidptr, sizeof(struct cifs_sid));
195 (*psidid)->time = jiffies - (SID_MAP_RETRY + 1);
196 (*psidid)->refcount = 0;
197
198 sprintf((*psidid)->sidstr, "%s", typestr);
199 strptr = (*psidid)->sidstr + strlen((*psidid)->sidstr);
200 sid_to_str(&(*psidid)->sid, strptr);
201
202 clear_bit(SID_ID_PENDING, &(*psidid)->state);
203 clear_bit(SID_ID_MAPPED, &(*psidid)->state);
204
205 rb_link_node(&(*psidid)->rbnode, parent, linkto);
206 rb_insert_color(&(*psidid)->rbnode, root);
207}
208
209static struct cifs_sid_id *
210id_rb_search(struct rb_root *root, struct cifs_sid *sidptr)
211{
212 int rc;
213 struct rb_node *node = root->rb_node;
214 struct rb_node *parent = NULL;
215 struct rb_node **linkto = &(root->rb_node);
216 struct cifs_sid_id *lsidid;
217
218 while (node) {
219 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
220 parent = node;
221 rc = compare_sids(sidptr, &((lsidid)->sid));
222 if (rc > 0) {
223 linkto = &(node->rb_left);
224 node = node->rb_left;
225 } else if (rc < 0) {
226 linkto = &(node->rb_right);
227 node = node->rb_right;
228 } else /* node found */
229 return lsidid;
230 }
231
232 return NULL;
233}
234
235static int
236sidid_pending_wait(void *unused)
237{
238 schedule();
239 return signal_pending(current) ? -ERESTARTSYS : 0;
240}
241
242static int
243sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
244 struct cifs_fattr *fattr, uint sidtype)
245{
246 int rc;
247 unsigned long cid;
248 struct key *idkey;
249 const struct cred *saved_cred;
250 struct cifs_sid_id *psidid, *npsidid;
251 struct rb_root *cidtree;
252 spinlock_t *cidlock;
253
254 if (sidtype == SIDOWNER) {
255 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
256 cidlock = &siduidlock;
257 cidtree = &uidtree;
258 } else if (sidtype == SIDGROUP) {
259 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
260 cidlock = &sidgidlock;
261 cidtree = &gidtree;
262 } else
263 return -ENOENT;
264
265 spin_lock(cidlock);
266 psidid = id_rb_search(cidtree, psid);
267
268 if (!psidid) { /* node does not exist, allocate one & attempt adding */
269 spin_unlock(cidlock);
270 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
271 if (!npsidid)
272 return -ENOMEM;
273
274 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
275 if (!npsidid->sidstr) {
276 kfree(npsidid);
277 return -ENOMEM;
278 }
279
280 spin_lock(cidlock);
281 psidid = id_rb_search(cidtree, psid);
282 if (psidid) { /* node happened to get inserted meanwhile */
283 ++psidid->refcount;
284 spin_unlock(cidlock);
285 kfree(npsidid->sidstr);
286 kfree(npsidid);
287 } else {
288 psidid = npsidid;
289 id_rb_insert(cidtree, psid, &psidid,
290 sidtype == SIDOWNER ? "os:" : "gs:");
291 ++psidid->refcount;
292 spin_unlock(cidlock);
293 }
294 } else {
295 ++psidid->refcount;
296 spin_unlock(cidlock);
297 }
298
299 /*
300 * If we are here, it is safe to access psidid and its fields
301 * since a reference was taken earlier while holding the spinlock.
302 * A reference on the node is put without holding the spinlock
303 * and it is OK to do so in this case, shrinker will not erase
304 * this node until all references are put and we do not access
305 * any fields of the node after a reference is put .
306 */
307 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
308 cid = psidid->id;
309 psidid->time = jiffies; /* update ts for accessing */
310 goto sid_to_id_out;
311 }
312
313 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
314 goto sid_to_id_out;
315
316 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
317 saved_cred = override_creds(root_cred);
318 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
319 if (IS_ERR(idkey))
320 cFYI(1, "%s: Can't map SID to an id", __func__);
321 else {
322 cid = *(unsigned long *)idkey->payload.value;
323 psidid->id = cid;
324 set_bit(SID_ID_MAPPED, &psidid->state);
325 key_put(idkey);
326 kfree(psidid->sidstr);
327 }
328 revert_creds(saved_cred);
329 psidid->time = jiffies; /* update ts for accessing */
330 clear_bit(SID_ID_PENDING, &psidid->state);
331 wake_up_bit(&psidid->state, SID_ID_PENDING);
332 } else {
333 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
334 sidid_pending_wait, TASK_INTERRUPTIBLE);
335 if (rc) {
336 cFYI(1, "%s: sidid_pending_wait interrupted %d",
337 __func__, rc);
338 --psidid->refcount; /* decremented without spinlock */
339 return rc;
340 }
341 if (test_bit(SID_ID_MAPPED, &psidid->state))
342 cid = psidid->id;
343 }
344
345sid_to_id_out:
346 --psidid->refcount; /* decremented without spinlock */
347 if (sidtype == SIDOWNER)
348 fattr->cf_uid = cid;
349 else
350 fattr->cf_gid = cid;
351
352 return 0;
353}
354
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500355int
356init_cifs_idmap(void)
357{
358 struct cred *cred;
359 struct key *keyring;
360 int ret;
361
362 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
363
364 /* create an override credential set with a special thread keyring in
365 * which requests are cached
366 *
367 * this is used to prevent malicious redirections from being installed
368 * with add_key().
369 */
370 cred = prepare_kernel_cred(NULL);
371 if (!cred)
372 return -ENOMEM;
373
374 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
375 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
376 KEY_USR_VIEW | KEY_USR_READ,
377 KEY_ALLOC_NOT_IN_QUOTA);
378 if (IS_ERR(keyring)) {
379 ret = PTR_ERR(keyring);
380 goto failed_put_cred;
381 }
382
383 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
384 if (ret < 0)
385 goto failed_put_key;
386
387 ret = register_key_type(&cifs_idmap_key_type);
388 if (ret < 0)
389 goto failed_put_key;
390
391 /* instruct request_key() to use this special keyring as a cache for
392 * the results it looks up */
393 cred->thread_keyring = keyring;
394 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
395 root_cred = cred;
396
397 spin_lock_init(&siduidlock);
398 uidtree = RB_ROOT;
399 spin_lock_init(&sidgidlock);
400 gidtree = RB_ROOT;
401
402 register_shrinker(&cifs_shrinker);
403
404 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
405 return 0;
406
407failed_put_key:
408 key_put(keyring);
409failed_put_cred:
410 put_cred(cred);
411 return ret;
412}
413
414void
415exit_cifs_idmap(void)
416{
417 key_revoke(root_cred->thread_keyring);
418 unregister_key_type(&cifs_idmap_key_type);
419 put_cred(root_cred);
420 unregister_shrinker(&cifs_shrinker);
421 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
422}
423
424void
425cifs_destroy_idmaptrees(void)
426{
427 struct rb_root *root;
428 struct rb_node *node;
429
430 root = &uidtree;
431 spin_lock(&siduidlock);
432 while ((node = rb_first(root)))
433 rb_erase(node, root);
434 spin_unlock(&siduidlock);
435
436 root = &gidtree;
437 spin_lock(&sidgidlock);
438 while ((node = rb_first(root)))
439 rb_erase(node, root);
440 spin_unlock(&sidgidlock);
441}
Steve French297647c2007-10-12 04:11:59 +0000442
443int match_sid(struct cifs_sid *ctsid)
444{
445 int i, j;
446 int num_subauth, num_sat, num_saw;
447 struct cifs_sid *cwsid;
448
449 if (!ctsid)
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000450 return -1;
Steve French297647c2007-10-12 04:11:59 +0000451
452 for (i = 0; i < NUM_WK_SIDS; ++i) {
453 cwsid = &(wksidarr[i].cifssid);
454
455 /* compare the revision */
456 if (ctsid->revision != cwsid->revision)
457 continue;
458
459 /* compare all of the six auth values */
460 for (j = 0; j < 6; ++j) {
461 if (ctsid->authority[j] != cwsid->authority[j])
462 break;
463 }
464 if (j < 6)
465 continue; /* all of the auth values did not match */
466
467 /* compare all of the subauth values if any */
Dave Kleikampce51ae12007-10-16 21:35:39 +0000468 num_sat = ctsid->num_subauth;
469 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000470 num_subauth = num_sat < num_saw ? num_sat : num_saw;
471 if (num_subauth) {
472 for (j = 0; j < num_subauth; ++j) {
473 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
474 break;
475 }
476 if (j < num_subauth)
477 continue; /* all sub_auth values do not match */
478 }
479
Joe Perchesb6b38f72010-04-21 03:50:45 +0000480 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000481 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000482 }
483
Joe Perchesb6b38f72010-04-21 03:50:45 +0000484 cFYI(1, "No matching sid");
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000485 return -1;
Steve French297647c2007-10-12 04:11:59 +0000486}
487
Steve Frencha750e772007-10-17 22:50:39 +0000488/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
489 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000490int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000491{
492 int i;
493 int num_subauth, num_sat, num_saw;
494
495 if ((!ctsid) || (!cwsid))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500496 return 1;
Steve French297647c2007-10-12 04:11:59 +0000497
498 /* compare the revision */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500499 if (ctsid->revision != cwsid->revision) {
500 if (ctsid->revision > cwsid->revision)
501 return 1;
502 else
503 return -1;
504 }
Steve French297647c2007-10-12 04:11:59 +0000505
506 /* compare all of the six auth values */
507 for (i = 0; i < 6; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500508 if (ctsid->authority[i] != cwsid->authority[i]) {
509 if (ctsid->authority[i] > cwsid->authority[i])
510 return 1;
511 else
512 return -1;
513 }
Steve French297647c2007-10-12 04:11:59 +0000514 }
515
516 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000517 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000518 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000519 num_subauth = num_sat < num_saw ? num_sat : num_saw;
520 if (num_subauth) {
521 for (i = 0; i < num_subauth; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500522 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
523 if (ctsid->sub_auth[i] > cwsid->sub_auth[i])
524 return 1;
525 else
526 return -1;
527 }
Steve French297647c2007-10-12 04:11:59 +0000528 }
529 }
530
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500531 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000532}
533
Steve French97837582007-12-31 07:47:21 +0000534
535/* copy ntsd, owner sid, and group sid from a security descriptor to another */
536static void copy_sec_desc(const struct cifs_ntsd *pntsd,
537 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
538{
539 int i;
540
541 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
542 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
543
544 /* copy security descriptor control portion */
545 pnntsd->revision = pntsd->revision;
546 pnntsd->type = pntsd->type;
547 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
548 pnntsd->sacloffset = 0;
549 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
550 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
551
552 /* copy owner sid */
553 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
554 le32_to_cpu(pntsd->osidoffset));
555 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
556
557 nowner_sid_ptr->revision = owner_sid_ptr->revision;
558 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
559 for (i = 0; i < 6; i++)
560 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
561 for (i = 0; i < 5; i++)
562 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
563
564 /* copy group sid */
565 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
566 le32_to_cpu(pntsd->gsidoffset));
567 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
568 sizeof(struct cifs_sid));
569
570 ngroup_sid_ptr->revision = group_sid_ptr->revision;
571 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
572 for (i = 0; i < 6; i++)
573 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
574 for (i = 0; i < 5; i++)
Shirish Pargaonkarb1910ad2008-07-24 14:53:20 +0000575 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
Steve French97837582007-12-31 07:47:21 +0000576
577 return;
578}
579
580
Steve French630f3f0c2007-10-25 21:17:17 +0000581/*
582 change posix mode to reflect permissions
583 pmode is the existing mode (we only want to overwrite part of this
584 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
585*/
Al Viro9b5e6852007-12-05 08:24:38 +0000586static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000587 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000588{
Al Viro9b5e6852007-12-05 08:24:38 +0000589 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000590 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000591 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000592 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000593 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000594 for the operation you are trying to perform for your user */
595
596 /* For deny ACEs we change the mask so that subsequent allow access
597 control entries do not turn on the bits we are denying */
598 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000599 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000600 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000601
Al Viro9b5e6852007-12-05 08:24:38 +0000602 if ((flags & GENERIC_WRITE) ||
603 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000604 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000605 if ((flags & GENERIC_READ) ||
606 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000607 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000608 if ((flags & GENERIC_EXECUTE) ||
609 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000610 *pbits_to_set &= ~S_IXUGO;
611 return;
612 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000613 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000614 return;
615 }
616 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000617
Al Viro9b5e6852007-12-05 08:24:38 +0000618 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000619 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000620 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000621 return;
622 }
Al Viro9b5e6852007-12-05 08:24:38 +0000623 if ((flags & GENERIC_WRITE) ||
624 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000625 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000626 if ((flags & GENERIC_READ) ||
627 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000628 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000629 if ((flags & GENERIC_EXECUTE) ||
630 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000631 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000632
Joe Perchesb6b38f72010-04-21 03:50:45 +0000633 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000634 return;
635}
636
Steve Frenchce06c9f2007-11-08 21:12:01 +0000637/*
638 Generate access flags to reflect permissions mode is the existing mode.
639 This function is called for every ACE in the DACL whose SID matches
640 with either owner or group or everyone.
641*/
642
643static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
644 __u32 *pace_flags)
645{
646 /* reset access mask */
647 *pace_flags = 0x0;
648
649 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
650 mode &= bits_to_use;
651
652 /* check for R/W/X UGO since we do not know whose flags
653 is this but we have cleared all the bits sans RWX for
654 either user or group or other as per bits_to_use */
655 if (mode & S_IRUGO)
656 *pace_flags |= SET_FILE_READ_RIGHTS;
657 if (mode & S_IWUGO)
658 *pace_flags |= SET_FILE_WRITE_RIGHTS;
659 if (mode & S_IXUGO)
660 *pace_flags |= SET_FILE_EXEC_RIGHTS;
661
Joe Perchesb6b38f72010-04-21 03:50:45 +0000662 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000663 return;
664}
665
Al Viro2b210ad2008-03-29 03:09:18 +0000666static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000667 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
668{
669 int i;
670 __u16 size = 0;
671 __u32 access_req = 0;
672
673 pntace->type = ACCESS_ALLOWED;
674 pntace->flags = 0x0;
675 mode_to_access_flags(nmode, bits, &access_req);
676 if (!access_req)
677 access_req = SET_MINIMUM_RIGHTS;
678 pntace->access_req = cpu_to_le32(access_req);
679
680 pntace->sid.revision = psid->revision;
681 pntace->sid.num_subauth = psid->num_subauth;
682 for (i = 0; i < 6; i++)
683 pntace->sid.authority[i] = psid->authority[i];
684 for (i = 0; i < psid->num_subauth; i++)
685 pntace->sid.sub_auth[i] = psid->sub_auth[i];
686
687 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
688 pntace->size = cpu_to_le16(size);
689
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000690 return size;
Steve French97837582007-12-31 07:47:21 +0000691}
692
Steve French297647c2007-10-12 04:11:59 +0000693
Steve French953f8682007-10-31 04:54:42 +0000694#ifdef CONFIG_CIFS_DEBUG2
695static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000696{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000697 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000698
699 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000700
Steve French44093ca2007-10-23 21:22:55 +0000701 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000703 return;
704 }
705
706 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000707 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000708 return;
Steve French44093ca2007-10-23 21:22:55 +0000709 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000710
Steve French44093ca2007-10-23 21:22:55 +0000711 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000712 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000713 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000714 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000715 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000716 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000717 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000718 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
719 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000720 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000721
Steve Frenchd12fd122007-10-03 19:43:19 +0000722 /* BB add length check to make sure that we do not have huge
723 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000724 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000725
Steve Frenchd12fd122007-10-03 19:43:19 +0000726 return;
727}
Steve French953f8682007-10-31 04:54:42 +0000728#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000729
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000730
Steve Frencha750e772007-10-17 22:50:39 +0000731static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000732 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400733 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000734{
735 int i;
736 int num_aces = 0;
737 int acl_size;
738 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000739 struct cifs_ace **ppace;
740
741 /* BB need to add parm so we can store the SID BB */
742
Steve French2b834572007-11-25 10:01:00 +0000743 if (!pdacl) {
744 /* no DACL in the security descriptor, set
745 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400746 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000747 return;
748 }
749
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000750 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000751 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000752 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000753 return;
754 }
755
Joe Perchesb6b38f72010-04-21 03:50:45 +0000756 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000757 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000758 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000759
Steve French7505e052007-11-01 18:03:01 +0000760 /* reset rwx permissions for user/group/other.
761 Also, if num_aces is 0 i.e. DACL has no ACEs,
762 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400763 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000764
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000765 acl_base = (char *)pdacl;
766 acl_size = sizeof(struct cifs_acl);
767
Steve Frenchadbc0352007-10-17 02:12:46 +0000768 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000769 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000770 umode_t user_mask = S_IRWXU;
771 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600772 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000773
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000774 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
775 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300776 if (!ppace) {
777 cERROR(1, "DACL memory allocation error");
778 return;
779 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000780
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000781 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000782 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000783#ifdef CONFIG_CIFS_DEBUG2
784 dump_ace(ppace[i], end_of_acl);
785#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500786 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000787 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000788 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400789 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000790 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500791 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000792 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000793 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400794 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000795 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500796 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000797 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000798 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400799 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000800 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500801 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600802 access_flags_to_mode(ppace[i]->access_req,
803 ppace[i]->type,
804 &fattr->cf_mode,
805 &other_mask);
806
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000807
Steve French44093ca2007-10-23 21:22:55 +0000808/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000809 (void *)ppace[i],
810 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000811
Steve French44093ca2007-10-23 21:22:55 +0000812 acl_base = (char *)ppace[i];
813 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000814 }
815
816 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000817 }
818
819 return;
820}
821
Steve Frenchbcb02032007-09-25 16:17:24 +0000822
Steve French97837582007-12-31 07:47:21 +0000823static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
824 struct cifs_sid *pgrpsid, __u64 nmode)
825{
Al Viro2b210ad2008-03-29 03:09:18 +0000826 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000827 struct cifs_acl *pnndacl;
828
829 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
830
831 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
832 pownersid, nmode, S_IRWXU);
833 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
834 pgrpsid, nmode, S_IRWXG);
835 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
836 &sid_everyone, nmode, S_IRWXO);
837
838 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000839 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000840
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000841 return 0;
Steve French97837582007-12-31 07:47:21 +0000842}
843
844
Steve Frenchbcb02032007-09-25 16:17:24 +0000845static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
846{
847 /* BB need to add parm so we can store the SID BB */
848
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000849 /* validate that we do not go past end of ACL - sid must be at least 8
850 bytes long (assuming no sub-auths - e.g. the null SID */
851 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000852 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000853 return -EINVAL;
854 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000855
Steve Frenchaf6f4612007-10-16 18:40:37 +0000856 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000857#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000858 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000859 cFYI(1, "SID revision %d num_auth %d",
860 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000861
Steve Frenchaf6f4612007-10-16 18:40:37 +0000862 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000863 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
864 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000865 }
866
Steve Frenchd12fd122007-10-03 19:43:19 +0000867 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000868 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000869 cFYI(1, "RID 0x%x",
870 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +0000871#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000872 }
873
Steve Frenchbcb02032007-09-25 16:17:24 +0000874 return 0;
875}
876
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000877
Steve Frenchbcb02032007-09-25 16:17:24 +0000878/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500879static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
880 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000881{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500882 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000883 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
884 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000885 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000886 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000887
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400888 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000889 return -EIO;
890
Steve Frenchbcb02032007-09-25 16:17:24 +0000891 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000892 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000893 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000894 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000895 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000896 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000897 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000898 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000899 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
900 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000901 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000902/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000903 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500904 if (rc) {
905 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000906 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500907 }
908 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
909 if (rc) {
910 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
911 return rc;
912 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000913
914 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500915 if (rc) {
916 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000917 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500918 }
919 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
920 if (rc) {
921 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
922 return rc;
923 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000924
Steve French7505e052007-11-01 18:03:01 +0000925 if (dacloffset)
926 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400927 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000928 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000929 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000930
Steve Frenchbcb02032007-09-25 16:17:24 +0000931/* cifscred->uid = owner_sid_ptr->rid;
932 cifscred->gid = group_sid_ptr->rid;
933 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000934 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000935 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000936 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000937
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500938 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000939}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000940
941
Steve French97837582007-12-31 07:47:21 +0000942/* Convert permission bits from mode to equivalent CIFS ACL */
943static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve Frenchcce246e2008-04-09 20:55:31 +0000944 struct inode *inode, __u64 nmode)
Steve French97837582007-12-31 07:47:21 +0000945{
946 int rc = 0;
947 __u32 dacloffset;
948 __u32 ndacloffset;
949 __u32 sidsoffset;
950 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
951 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
952 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
953
954 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000955 return -EIO;
Steve French97837582007-12-31 07:47:21 +0000956
957 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
958 le32_to_cpu(pntsd->osidoffset));
959 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
960 le32_to_cpu(pntsd->gsidoffset));
961
962 dacloffset = le32_to_cpu(pntsd->dacloffset);
963 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
964
965 ndacloffset = sizeof(struct cifs_ntsd);
966 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
967 ndacl_ptr->revision = dacl_ptr->revision;
968 ndacl_ptr->size = 0;
969 ndacl_ptr->num_aces = 0;
970
971 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
972
973 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
974
975 /* copy security descriptor control portion and owner and group sid */
976 copy_sec_desc(pntsd, pnntsd, sidsoffset);
977
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000978 return rc;
Steve French97837582007-12-31 07:47:21 +0000979}
980
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400981static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
982 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000983{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000984 struct cifs_ntsd *pntsd = NULL;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400985 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400986 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
987
988 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600989 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000990
991 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400992 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400993 FreeXid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000994
Jeff Layton7ffec372010-09-29 19:51:11 -0400995 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000996
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600997 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
998 if (rc)
999 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001000 return pntsd;
1001}
1002
1003static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1004 const char *path, u32 *pacllen)
1005{
1006 struct cifs_ntsd *pntsd = NULL;
1007 int oplock = 0;
1008 int xid, rc;
1009 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -04001010 struct cifsTconInfo *tcon;
1011 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001012
Jeff Layton7ffec372010-09-29 19:51:11 -04001013 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001014 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001015
1016 tcon = tlink_tcon(tlink);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001017 xid = GetXid();
1018
Jeff Layton7ffec372010-09-29 19:51:11 -04001019 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001020 &fid, &oplock, NULL, cifs_sb->local_nls,
1021 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001022 if (!rc) {
1023 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1024 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001025 }
1026
Jeff Layton7ffec372010-09-29 19:51:11 -04001027 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001028 FreeXid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001029
1030 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1031 if (rc)
1032 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001033 return pntsd;
1034}
1035
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001036/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001037struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001038 struct inode *inode, const char *path,
1039 u32 *pacllen)
1040{
1041 struct cifs_ntsd *pntsd = NULL;
1042 struct cifsFileInfo *open_file = NULL;
1043
1044 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001045 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001046 if (!open_file)
1047 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1048
1049 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001050 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001051 return pntsd;
1052}
1053
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001054static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
1055 struct cifs_ntsd *pnntsd, u32 acllen)
Steve French97837582007-12-31 07:47:21 +00001056{
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001057 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001058 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1059
1060 if (IS_ERR(tlink))
1061 return PTR_ERR(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001062
1063 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001064 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001065 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001066 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001067
Joe Perchesb6b38f72010-04-21 03:50:45 +00001068 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001069 return rc;
1070}
1071
1072static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
1073 struct cifs_ntsd *pnntsd, u32 acllen)
1074{
1075 int oplock = 0;
1076 int xid, rc;
Steve French97837582007-12-31 07:47:21 +00001077 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -04001078 struct cifsTconInfo *tcon;
1079 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001080
Jeff Layton7ffec372010-09-29 19:51:11 -04001081 if (IS_ERR(tlink))
1082 return PTR_ERR(tlink);
1083
1084 tcon = tlink_tcon(tlink);
Steve French97837582007-12-31 07:47:21 +00001085 xid = GetXid();
1086
Jeff Layton7ffec372010-09-29 19:51:11 -04001087 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001088 &fid, &oplock, NULL, cifs_sb->local_nls,
1089 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1090 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001091 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001092 goto out;
Steve French97837582007-12-31 07:47:21 +00001093 }
1094
Jeff Layton7ffec372010-09-29 19:51:11 -04001095 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001096 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001097
Jeff Layton7ffec372010-09-29 19:51:11 -04001098 CIFSSMBClose(xid, tcon, fid);
1099out:
Steve French97837582007-12-31 07:47:21 +00001100 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001101 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001102 return rc;
1103}
Steve French97837582007-12-31 07:47:21 +00001104
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001105/* Set an ACL on the server */
Steve Frenchb73b9a42011-04-19 18:27:10 +00001106int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001107 struct inode *inode, const char *path)
1108{
1109 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1110 struct cifsFileInfo *open_file;
1111 int rc;
1112
Joe Perchesb6b38f72010-04-21 03:50:45 +00001113 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001114
Jeff Layton6508d902010-09-29 19:51:11 -04001115 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001116 if (!open_file)
1117 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
1118
1119 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001120 cifsFileInfo_put(open_file);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001121 return rc;
Steve French97837582007-12-31 07:47:21 +00001122}
1123
Steve French7505e052007-11-01 18:03:01 +00001124/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001125int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001126cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1127 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001128{
1129 struct cifs_ntsd *pntsd = NULL;
1130 u32 acllen = 0;
1131 int rc = 0;
1132
Joe Perchesb6b38f72010-04-21 03:50:45 +00001133 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001134
1135 if (pfid)
1136 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1137 else
1138 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001139
1140 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001141 if (IS_ERR(pntsd)) {
1142 rc = PTR_ERR(pntsd);
1143 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1144 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001145 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001146 kfree(pntsd);
1147 if (rc)
1148 cERROR(1, "parse sec desc failed rc = %d", rc);
1149 }
Steve French7505e052007-11-01 18:03:01 +00001150
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001151 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001152}
Steve French953f8682007-10-31 04:54:42 +00001153
Steve French7505e052007-11-01 18:03:01 +00001154/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06001155int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
Steve French953f8682007-10-31 04:54:42 +00001156{
1157 int rc = 0;
Steve Frenchcce246e2008-04-09 20:55:31 +00001158 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001159 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1160 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001161
Joe Perchesb6b38f72010-04-21 03:50:45 +00001162 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001163
1164 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001165 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +00001166
Steve French97837582007-12-31 07:47:21 +00001167 /* Add three ACEs for owner, group, everyone getting rid of
1168 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +00001169
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001170 if (IS_ERR(pntsd)) {
1171 rc = PTR_ERR(pntsd);
1172 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1173 } else {
Steve French97837582007-12-31 07:47:21 +00001174 /* allocate memory for the smb header,
1175 set security descriptor request security descriptor
1176 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +00001177
Steve Frenchcce246e2008-04-09 20:55:31 +00001178 secdesclen = secdesclen < DEFSECDESCLEN ?
1179 DEFSECDESCLEN : secdesclen;
1180 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +00001181 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001182 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +00001183 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001184 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +00001185 }
Steve French7505e052007-11-01 18:03:01 +00001186
Steve Frenchcce246e2008-04-09 20:55:31 +00001187 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
Steve French97837582007-12-31 07:47:21 +00001188
Joe Perchesb6b38f72010-04-21 03:50:45 +00001189 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001190
1191 if (!rc) {
1192 /* Set the security descriptor */
Steve Frenchcce246e2008-04-09 20:55:31 +00001193 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001194 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001195 }
1196
1197 kfree(pnntsd);
1198 kfree(pntsd);
1199 }
1200
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001201 return rc;
Steve French953f8682007-10-31 04:54:42 +00001202}