blob: bfb5ba5a271b73ea75605d2edc883ee71db04eba [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;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500214 struct cifs_sid_id *lsidid;
215
216 while (node) {
217 lsidid = rb_entry(node, struct cifs_sid_id, rbnode);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500218 rc = compare_sids(sidptr, &((lsidid)->sid));
219 if (rc > 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500220 node = node->rb_left;
221 } else if (rc < 0) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500222 node = node->rb_right;
223 } else /* node found */
224 return lsidid;
225 }
226
227 return NULL;
228}
229
230static int
231sidid_pending_wait(void *unused)
232{
233 schedule();
234 return signal_pending(current) ? -ERESTARTSYS : 0;
235}
236
237static int
238sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
239 struct cifs_fattr *fattr, uint sidtype)
240{
241 int rc;
242 unsigned long cid;
243 struct key *idkey;
244 const struct cred *saved_cred;
245 struct cifs_sid_id *psidid, *npsidid;
246 struct rb_root *cidtree;
247 spinlock_t *cidlock;
248
249 if (sidtype == SIDOWNER) {
250 cid = cifs_sb->mnt_uid; /* default uid, in case upcall fails */
251 cidlock = &siduidlock;
252 cidtree = &uidtree;
253 } else if (sidtype == SIDGROUP) {
254 cid = cifs_sb->mnt_gid; /* default gid, in case upcall fails */
255 cidlock = &sidgidlock;
256 cidtree = &gidtree;
257 } else
258 return -ENOENT;
259
260 spin_lock(cidlock);
261 psidid = id_rb_search(cidtree, psid);
262
263 if (!psidid) { /* node does not exist, allocate one & attempt adding */
264 spin_unlock(cidlock);
265 npsidid = kzalloc(sizeof(struct cifs_sid_id), GFP_KERNEL);
266 if (!npsidid)
267 return -ENOMEM;
268
269 npsidid->sidstr = kmalloc(SIDLEN, GFP_KERNEL);
270 if (!npsidid->sidstr) {
271 kfree(npsidid);
272 return -ENOMEM;
273 }
274
275 spin_lock(cidlock);
276 psidid = id_rb_search(cidtree, psid);
277 if (psidid) { /* node happened to get inserted meanwhile */
278 ++psidid->refcount;
279 spin_unlock(cidlock);
280 kfree(npsidid->sidstr);
281 kfree(npsidid);
282 } else {
283 psidid = npsidid;
284 id_rb_insert(cidtree, psid, &psidid,
285 sidtype == SIDOWNER ? "os:" : "gs:");
286 ++psidid->refcount;
287 spin_unlock(cidlock);
288 }
289 } else {
290 ++psidid->refcount;
291 spin_unlock(cidlock);
292 }
293
294 /*
295 * If we are here, it is safe to access psidid and its fields
296 * since a reference was taken earlier while holding the spinlock.
297 * A reference on the node is put without holding the spinlock
298 * and it is OK to do so in this case, shrinker will not erase
299 * this node until all references are put and we do not access
300 * any fields of the node after a reference is put .
301 */
302 if (test_bit(SID_ID_MAPPED, &psidid->state)) {
303 cid = psidid->id;
304 psidid->time = jiffies; /* update ts for accessing */
305 goto sid_to_id_out;
306 }
307
308 if (time_after(psidid->time + SID_MAP_RETRY, jiffies))
309 goto sid_to_id_out;
310
311 if (!test_and_set_bit(SID_ID_PENDING, &psidid->state)) {
312 saved_cred = override_creds(root_cred);
313 idkey = request_key(&cifs_idmap_key_type, psidid->sidstr, "");
314 if (IS_ERR(idkey))
315 cFYI(1, "%s: Can't map SID to an id", __func__);
316 else {
317 cid = *(unsigned long *)idkey->payload.value;
318 psidid->id = cid;
319 set_bit(SID_ID_MAPPED, &psidid->state);
320 key_put(idkey);
321 kfree(psidid->sidstr);
322 }
323 revert_creds(saved_cred);
324 psidid->time = jiffies; /* update ts for accessing */
325 clear_bit(SID_ID_PENDING, &psidid->state);
326 wake_up_bit(&psidid->state, SID_ID_PENDING);
327 } else {
328 rc = wait_on_bit(&psidid->state, SID_ID_PENDING,
329 sidid_pending_wait, TASK_INTERRUPTIBLE);
330 if (rc) {
331 cFYI(1, "%s: sidid_pending_wait interrupted %d",
332 __func__, rc);
333 --psidid->refcount; /* decremented without spinlock */
334 return rc;
335 }
336 if (test_bit(SID_ID_MAPPED, &psidid->state))
337 cid = psidid->id;
338 }
339
340sid_to_id_out:
341 --psidid->refcount; /* decremented without spinlock */
342 if (sidtype == SIDOWNER)
343 fattr->cf_uid = cid;
344 else
345 fattr->cf_gid = cid;
346
347 return 0;
348}
349
Shirish Pargaonkar4d79dba2011-04-27 23:34:35 -0500350int
351init_cifs_idmap(void)
352{
353 struct cred *cred;
354 struct key *keyring;
355 int ret;
356
357 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
358
359 /* create an override credential set with a special thread keyring in
360 * which requests are cached
361 *
362 * this is used to prevent malicious redirections from being installed
363 * with add_key().
364 */
365 cred = prepare_kernel_cred(NULL);
366 if (!cred)
367 return -ENOMEM;
368
369 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
370 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
371 KEY_USR_VIEW | KEY_USR_READ,
372 KEY_ALLOC_NOT_IN_QUOTA);
373 if (IS_ERR(keyring)) {
374 ret = PTR_ERR(keyring);
375 goto failed_put_cred;
376 }
377
378 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
379 if (ret < 0)
380 goto failed_put_key;
381
382 ret = register_key_type(&cifs_idmap_key_type);
383 if (ret < 0)
384 goto failed_put_key;
385
386 /* instruct request_key() to use this special keyring as a cache for
387 * the results it looks up */
388 cred->thread_keyring = keyring;
389 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
390 root_cred = cred;
391
392 spin_lock_init(&siduidlock);
393 uidtree = RB_ROOT;
394 spin_lock_init(&sidgidlock);
395 gidtree = RB_ROOT;
396
397 register_shrinker(&cifs_shrinker);
398
399 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
400 return 0;
401
402failed_put_key:
403 key_put(keyring);
404failed_put_cred:
405 put_cred(cred);
406 return ret;
407}
408
409void
410exit_cifs_idmap(void)
411{
412 key_revoke(root_cred->thread_keyring);
413 unregister_key_type(&cifs_idmap_key_type);
414 put_cred(root_cred);
415 unregister_shrinker(&cifs_shrinker);
416 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
417}
418
419void
420cifs_destroy_idmaptrees(void)
421{
422 struct rb_root *root;
423 struct rb_node *node;
424
425 root = &uidtree;
426 spin_lock(&siduidlock);
427 while ((node = rb_first(root)))
428 rb_erase(node, root);
429 spin_unlock(&siduidlock);
430
431 root = &gidtree;
432 spin_lock(&sidgidlock);
433 while ((node = rb_first(root)))
434 rb_erase(node, root);
435 spin_unlock(&sidgidlock);
436}
Steve French297647c2007-10-12 04:11:59 +0000437
438int match_sid(struct cifs_sid *ctsid)
439{
440 int i, j;
441 int num_subauth, num_sat, num_saw;
442 struct cifs_sid *cwsid;
443
444 if (!ctsid)
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000445 return -1;
Steve French297647c2007-10-12 04:11:59 +0000446
447 for (i = 0; i < NUM_WK_SIDS; ++i) {
448 cwsid = &(wksidarr[i].cifssid);
449
450 /* compare the revision */
451 if (ctsid->revision != cwsid->revision)
452 continue;
453
454 /* compare all of the six auth values */
455 for (j = 0; j < 6; ++j) {
456 if (ctsid->authority[j] != cwsid->authority[j])
457 break;
458 }
459 if (j < 6)
460 continue; /* all of the auth values did not match */
461
462 /* compare all of the subauth values if any */
Dave Kleikampce51ae12007-10-16 21:35:39 +0000463 num_sat = ctsid->num_subauth;
464 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000465 num_subauth = num_sat < num_saw ? num_sat : num_saw;
466 if (num_subauth) {
467 for (j = 0; j < num_subauth; ++j) {
468 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
469 break;
470 }
471 if (j < num_subauth)
472 continue; /* all sub_auth values do not match */
473 }
474
Joe Perchesb6b38f72010-04-21 03:50:45 +0000475 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000476 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000477 }
478
Joe Perchesb6b38f72010-04-21 03:50:45 +0000479 cFYI(1, "No matching sid");
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000480 return -1;
Steve French297647c2007-10-12 04:11:59 +0000481}
482
Steve Frencha750e772007-10-17 22:50:39 +0000483/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
484 the same returns 1, if they do not match returns 0 */
Steve French630f3f0c2007-10-25 21:17:17 +0000485int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
Steve French297647c2007-10-12 04:11:59 +0000486{
487 int i;
488 int num_subauth, num_sat, num_saw;
489
490 if ((!ctsid) || (!cwsid))
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500491 return 1;
Steve French297647c2007-10-12 04:11:59 +0000492
493 /* compare the revision */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500494 if (ctsid->revision != cwsid->revision) {
495 if (ctsid->revision > cwsid->revision)
496 return 1;
497 else
498 return -1;
499 }
Steve French297647c2007-10-12 04:11:59 +0000500
501 /* compare all of the six auth values */
502 for (i = 0; i < 6; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500503 if (ctsid->authority[i] != cwsid->authority[i]) {
504 if (ctsid->authority[i] > cwsid->authority[i])
505 return 1;
506 else
507 return -1;
508 }
Steve French297647c2007-10-12 04:11:59 +0000509 }
510
511 /* compare all of the subauth values if any */
Steve Frenchadbc0352007-10-17 02:12:46 +0000512 num_sat = ctsid->num_subauth;
Steve Frenchadddd492007-10-17 02:48:17 +0000513 num_saw = cwsid->num_subauth;
Steve French297647c2007-10-12 04:11:59 +0000514 num_subauth = num_sat < num_saw ? num_sat : num_saw;
515 if (num_subauth) {
516 for (i = 0; i < num_subauth; ++i) {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500517 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
518 if (ctsid->sub_auth[i] > cwsid->sub_auth[i])
519 return 1;
520 else
521 return -1;
522 }
Steve French297647c2007-10-12 04:11:59 +0000523 }
524 }
525
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500526 return 0; /* sids compare/match */
Steve French297647c2007-10-12 04:11:59 +0000527}
528
Steve French97837582007-12-31 07:47:21 +0000529
530/* copy ntsd, owner sid, and group sid from a security descriptor to another */
531static void copy_sec_desc(const struct cifs_ntsd *pntsd,
532 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
533{
534 int i;
535
536 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
537 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
538
539 /* copy security descriptor control portion */
540 pnntsd->revision = pntsd->revision;
541 pnntsd->type = pntsd->type;
542 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
543 pnntsd->sacloffset = 0;
544 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
545 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
546
547 /* copy owner sid */
548 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
549 le32_to_cpu(pntsd->osidoffset));
550 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
551
552 nowner_sid_ptr->revision = owner_sid_ptr->revision;
553 nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
554 for (i = 0; i < 6; i++)
555 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
556 for (i = 0; i < 5; i++)
557 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
558
559 /* copy group sid */
560 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
561 le32_to_cpu(pntsd->gsidoffset));
562 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
563 sizeof(struct cifs_sid));
564
565 ngroup_sid_ptr->revision = group_sid_ptr->revision;
566 ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
567 for (i = 0; i < 6; i++)
568 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
569 for (i = 0; i < 5; i++)
Shirish Pargaonkarb1910ad2008-07-24 14:53:20 +0000570 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
Steve French97837582007-12-31 07:47:21 +0000571
572 return;
573}
574
575
Steve French630f3f0c2007-10-25 21:17:17 +0000576/*
577 change posix mode to reflect permissions
578 pmode is the existing mode (we only want to overwrite part of this
579 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
580*/
Al Viro9b5e6852007-12-05 08:24:38 +0000581static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
Steve French15b03952007-11-08 17:57:40 +0000582 umode_t *pbits_to_set)
Steve French4879b442007-10-19 21:57:39 +0000583{
Al Viro9b5e6852007-12-05 08:24:38 +0000584 __u32 flags = le32_to_cpu(ace_flags);
Steve French15b03952007-11-08 17:57:40 +0000585 /* the order of ACEs is important. The canonical order is to begin with
Steve Frenchce06c9f2007-11-08 21:12:01 +0000586 DENY entries followed by ALLOW, otherwise an allow entry could be
Steve French15b03952007-11-08 17:57:40 +0000587 encountered first, making the subsequent deny entry like "dead code"
Steve Frenchce06c9f2007-11-08 21:12:01 +0000588 which would be superflous since Windows stops when a match is made
Steve French15b03952007-11-08 17:57:40 +0000589 for the operation you are trying to perform for your user */
590
591 /* For deny ACEs we change the mask so that subsequent allow access
592 control entries do not turn on the bits we are denying */
593 if (type == ACCESS_DENIED) {
Steve Frenchad7a2922008-02-07 23:25:02 +0000594 if (flags & GENERIC_ALL)
Steve French15b03952007-11-08 17:57:40 +0000595 *pbits_to_set &= ~S_IRWXUGO;
Steve Frenchad7a2922008-02-07 23:25:02 +0000596
Al Viro9b5e6852007-12-05 08:24:38 +0000597 if ((flags & GENERIC_WRITE) ||
598 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000599 *pbits_to_set &= ~S_IWUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000600 if ((flags & GENERIC_READ) ||
601 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000602 *pbits_to_set &= ~S_IRUGO;
Al Viro9b5e6852007-12-05 08:24:38 +0000603 if ((flags & GENERIC_EXECUTE) ||
604 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000605 *pbits_to_set &= ~S_IXUGO;
606 return;
607 } else if (type != ACCESS_ALLOWED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000608 cERROR(1, "unknown access control type %d", type);
Steve French15b03952007-11-08 17:57:40 +0000609 return;
610 }
611 /* else ACCESS_ALLOWED type */
Steve French44093ca2007-10-23 21:22:55 +0000612
Al Viro9b5e6852007-12-05 08:24:38 +0000613 if (flags & GENERIC_ALL) {
Steve French15b03952007-11-08 17:57:40 +0000614 *pmode |= (S_IRWXUGO & (*pbits_to_set));
Joe Perchesb6b38f72010-04-21 03:50:45 +0000615 cFYI(DBG2, "all perms");
Steve Frenchd61e5802007-10-26 04:32:43 +0000616 return;
617 }
Al Viro9b5e6852007-12-05 08:24:38 +0000618 if ((flags & GENERIC_WRITE) ||
619 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000620 *pmode |= (S_IWUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000621 if ((flags & GENERIC_READ) ||
622 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000623 *pmode |= (S_IRUGO & (*pbits_to_set));
Al Viro9b5e6852007-12-05 08:24:38 +0000624 if ((flags & GENERIC_EXECUTE) ||
625 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
Steve French15b03952007-11-08 17:57:40 +0000626 *pmode |= (S_IXUGO & (*pbits_to_set));
Steve Frenchd61e5802007-10-26 04:32:43 +0000627
Joe Perchesb6b38f72010-04-21 03:50:45 +0000628 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
Steve French630f3f0c2007-10-25 21:17:17 +0000629 return;
630}
631
Steve Frenchce06c9f2007-11-08 21:12:01 +0000632/*
633 Generate access flags to reflect permissions mode is the existing mode.
634 This function is called for every ACE in the DACL whose SID matches
635 with either owner or group or everyone.
636*/
637
638static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
639 __u32 *pace_flags)
640{
641 /* reset access mask */
642 *pace_flags = 0x0;
643
644 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
645 mode &= bits_to_use;
646
647 /* check for R/W/X UGO since we do not know whose flags
648 is this but we have cleared all the bits sans RWX for
649 either user or group or other as per bits_to_use */
650 if (mode & S_IRUGO)
651 *pace_flags |= SET_FILE_READ_RIGHTS;
652 if (mode & S_IWUGO)
653 *pace_flags |= SET_FILE_WRITE_RIGHTS;
654 if (mode & S_IXUGO)
655 *pace_flags |= SET_FILE_EXEC_RIGHTS;
656
Joe Perchesb6b38f72010-04-21 03:50:45 +0000657 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
Steve Frenchce06c9f2007-11-08 21:12:01 +0000658 return;
659}
660
Al Viro2b210ad2008-03-29 03:09:18 +0000661static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
Steve French97837582007-12-31 07:47:21 +0000662 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
663{
664 int i;
665 __u16 size = 0;
666 __u32 access_req = 0;
667
668 pntace->type = ACCESS_ALLOWED;
669 pntace->flags = 0x0;
670 mode_to_access_flags(nmode, bits, &access_req);
671 if (!access_req)
672 access_req = SET_MINIMUM_RIGHTS;
673 pntace->access_req = cpu_to_le32(access_req);
674
675 pntace->sid.revision = psid->revision;
676 pntace->sid.num_subauth = psid->num_subauth;
677 for (i = 0; i < 6; i++)
678 pntace->sid.authority[i] = psid->authority[i];
679 for (i = 0; i < psid->num_subauth; i++)
680 pntace->sid.sub_auth[i] = psid->sub_auth[i];
681
682 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
683 pntace->size = cpu_to_le16(size);
684
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000685 return size;
Steve French97837582007-12-31 07:47:21 +0000686}
687
Steve French297647c2007-10-12 04:11:59 +0000688
Steve French953f8682007-10-31 04:54:42 +0000689#ifdef CONFIG_CIFS_DEBUG2
690static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000691{
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000692 int num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000693
694 /* validate that we do not go past end of acl */
Steve French297647c2007-10-12 04:11:59 +0000695
Steve French44093ca2007-10-23 21:22:55 +0000696 if (le16_to_cpu(pace->size) < 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
Steve French44093ca2007-10-23 21:22:55 +0000698 return;
699 }
700
701 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cERROR(1, "ACL too small to parse ACE");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000703 return;
Steve French44093ca2007-10-23 21:22:55 +0000704 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000705
Steve French44093ca2007-10-23 21:22:55 +0000706 num_subauth = pace->sid.num_subauth;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000707 if (num_subauth) {
Steve French8f18c132007-10-12 18:54:12 +0000708 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000709 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
Steve French44093ca2007-10-23 21:22:55 +0000710 pace->sid.revision, pace->sid.num_subauth, pace->type,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000711 pace->flags, le16_to_cpu(pace->size));
Steve Frenchd12fd122007-10-03 19:43:19 +0000712 for (i = 0; i < num_subauth; ++i) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000713 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
714 le32_to_cpu(pace->sid.sub_auth[i]));
Steve Frenchd12fd122007-10-03 19:43:19 +0000715 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000716
Steve Frenchd12fd122007-10-03 19:43:19 +0000717 /* BB add length check to make sure that we do not have huge
718 num auths and therefore go off the end */
Steve Frenchd12fd122007-10-03 19:43:19 +0000719 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000720
Steve Frenchd12fd122007-10-03 19:43:19 +0000721 return;
722}
Steve French953f8682007-10-31 04:54:42 +0000723#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000724
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000725
Steve Frencha750e772007-10-17 22:50:39 +0000726static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
Steve Frenchd61e5802007-10-26 04:32:43 +0000727 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400728 struct cifs_fattr *fattr)
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000729{
730 int i;
731 int num_aces = 0;
732 int acl_size;
733 char *acl_base;
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000734 struct cifs_ace **ppace;
735
736 /* BB need to add parm so we can store the SID BB */
737
Steve French2b834572007-11-25 10:01:00 +0000738 if (!pdacl) {
739 /* no DACL in the security descriptor, set
740 all the permissions for user/group/other */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400741 fattr->cf_mode |= S_IRWXUGO;
Steve French2b834572007-11-25 10:01:00 +0000742 return;
743 }
744
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000745 /* validate that we do not go past end of acl */
Steve Frenchaf6f4612007-10-16 18:40:37 +0000746 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000747 cERROR(1, "ACL too small to parse DACL");
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000748 return;
749 }
750
Joe Perchesb6b38f72010-04-21 03:50:45 +0000751 cFYI(DBG2, "DACL revision %d size %d num aces %d",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000752 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000753 le32_to_cpu(pdacl->num_aces));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000754
Steve French7505e052007-11-01 18:03:01 +0000755 /* reset rwx permissions for user/group/other.
756 Also, if num_aces is 0 i.e. DACL has no ACEs,
757 user/group/other have no permissions */
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400758 fattr->cf_mode &= ~(S_IRWXUGO);
Steve French7505e052007-11-01 18:03:01 +0000759
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000760 acl_base = (char *)pdacl;
761 acl_size = sizeof(struct cifs_acl);
762
Steve Frenchadbc0352007-10-17 02:12:46 +0000763 num_aces = le32_to_cpu(pdacl->num_aces);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000764 if (num_aces > 0) {
Steve French15b03952007-11-08 17:57:40 +0000765 umode_t user_mask = S_IRWXU;
766 umode_t group_mask = S_IRWXG;
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600767 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
Steve French15b03952007-11-08 17:57:40 +0000768
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000769 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
770 GFP_KERNEL);
Stanislav Fomichev8132b652011-02-06 02:05:28 +0300771 if (!ppace) {
772 cERROR(1, "DACL memory allocation error");
773 return;
774 }
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000775
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000776 for (i = 0; i < num_aces; ++i) {
Steve French44093ca2007-10-23 21:22:55 +0000777 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
Steve French953f8682007-10-31 04:54:42 +0000778#ifdef CONFIG_CIFS_DEBUG2
779 dump_ace(ppace[i], end_of_acl);
780#endif
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500781 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000782 access_flags_to_mode(ppace[i]->access_req,
Steve French15b03952007-11-08 17:57:40 +0000783 ppace[i]->type,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400784 &fattr->cf_mode,
Steve French15b03952007-11-08 17:57:40 +0000785 &user_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500786 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 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 &group_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500791 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 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 &other_mask);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500796 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
Shirish Pargaonkar2fbc2f12010-12-06 14:56:46 -0600797 access_flags_to_mode(ppace[i]->access_req,
798 ppace[i]->type,
799 &fattr->cf_mode,
800 &other_mask);
801
Shirish Pargaonkare01b6402007-10-30 04:45:14 +0000802
Steve French44093ca2007-10-23 21:22:55 +0000803/* memcpy((void *)(&(cifscred->aces[i])),
Steve Frenchd12fd122007-10-03 19:43:19 +0000804 (void *)ppace[i],
805 sizeof(struct cifs_ace)); */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000806
Steve French44093ca2007-10-23 21:22:55 +0000807 acl_base = (char *)ppace[i];
808 acl_size = le16_to_cpu(ppace[i]->size);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000809 }
810
811 kfree(ppace);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000812 }
813
814 return;
815}
816
Steve Frenchbcb02032007-09-25 16:17:24 +0000817
Steve French97837582007-12-31 07:47:21 +0000818static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
819 struct cifs_sid *pgrpsid, __u64 nmode)
820{
Al Viro2b210ad2008-03-29 03:09:18 +0000821 u16 size = 0;
Steve French97837582007-12-31 07:47:21 +0000822 struct cifs_acl *pnndacl;
823
824 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
825
826 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
827 pownersid, nmode, S_IRWXU);
828 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
829 pgrpsid, nmode, S_IRWXG);
830 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
831 &sid_everyone, nmode, S_IRWXO);
832
833 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
Shirish Pargaonkard9f382e2008-02-12 20:46:26 +0000834 pndacl->num_aces = cpu_to_le32(3);
Steve French97837582007-12-31 07:47:21 +0000835
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000836 return 0;
Steve French97837582007-12-31 07:47:21 +0000837}
838
839
Steve Frenchbcb02032007-09-25 16:17:24 +0000840static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
841{
842 /* BB need to add parm so we can store the SID BB */
843
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000844 /* validate that we do not go past end of ACL - sid must be at least 8
845 bytes long (assuming no sub-auths - e.g. the null SID */
846 if (end_of_acl < (char *)psid + 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000847 cERROR(1, "ACL too small to parse SID %p", psid);
Steve Frenchbcb02032007-09-25 16:17:24 +0000848 return -EINVAL;
849 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000850
Steve Frenchaf6f4612007-10-16 18:40:37 +0000851 if (psid->num_subauth) {
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000852#ifdef CONFIG_CIFS_DEBUG2
Steve French8f18c132007-10-12 18:54:12 +0000853 int i;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000854 cFYI(1, "SID revision %d num_auth %d",
855 psid->revision, psid->num_subauth);
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000856
Steve Frenchaf6f4612007-10-16 18:40:37 +0000857 for (i = 0; i < psid->num_subauth; i++) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000858 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
859 le32_to_cpu(psid->sub_auth[i]));
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000860 }
861
Steve Frenchd12fd122007-10-03 19:43:19 +0000862 /* BB add length check to make sure that we do not have huge
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000863 num auths and therefore go off the end */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000864 cFYI(1, "RID 0x%x",
865 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
Steve Frenchbcb02032007-09-25 16:17:24 +0000866#endif
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000867 }
868
Steve Frenchbcb02032007-09-25 16:17:24 +0000869 return 0;
870}
871
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000872
Steve Frenchbcb02032007-09-25 16:17:24 +0000873/* Convert CIFS ACL to POSIX form */
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500874static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
875 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
Steve Frenchbcb02032007-09-25 16:17:24 +0000876{
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500877 int rc = 0;
Steve Frenchbcb02032007-09-25 16:17:24 +0000878 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
879 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
Steve Frenchbcb02032007-09-25 16:17:24 +0000880 char *end_of_acl = ((char *)pntsd) + acl_len;
Steve French7505e052007-11-01 18:03:01 +0000881 __u32 dacloffset;
Steve Frenchbcb02032007-09-25 16:17:24 +0000882
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400883 if (pntsd == NULL)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000884 return -EIO;
885
Steve Frenchbcb02032007-09-25 16:17:24 +0000886 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000887 le32_to_cpu(pntsd->osidoffset));
Steve Frenchbcb02032007-09-25 16:17:24 +0000888 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
Steve Frenchaf6f4612007-10-16 18:40:37 +0000889 le32_to_cpu(pntsd->gsidoffset));
Steve French7505e052007-11-01 18:03:01 +0000890 dacloffset = le32_to_cpu(pntsd->dacloffset);
Steve French63d25832007-11-05 21:46:10 +0000891 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000892 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
Steve Frenchbcb02032007-09-25 16:17:24 +0000893 "sacloffset 0x%x dacloffset 0x%x",
Steve Frenchaf6f4612007-10-16 18:40:37 +0000894 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
895 le32_to_cpu(pntsd->gsidoffset),
Joe Perchesb6b38f72010-04-21 03:50:45 +0000896 le32_to_cpu(pntsd->sacloffset), dacloffset);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000897/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000898 rc = parse_sid(owner_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500899 if (rc) {
900 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000901 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500902 }
903 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
904 if (rc) {
905 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
906 return rc;
907 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000908
909 rc = parse_sid(group_sid_ptr, end_of_acl);
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500910 if (rc) {
911 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
Steve Frenchbcb02032007-09-25 16:17:24 +0000912 return rc;
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500913 }
914 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
915 if (rc) {
916 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
917 return rc;
918 }
Steve Frenchbcb02032007-09-25 16:17:24 +0000919
Steve French7505e052007-11-01 18:03:01 +0000920 if (dacloffset)
921 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
Jeff Layton0b8f18e2009-07-09 01:46:37 -0400922 group_sid_ptr, fattr);
Steve French7505e052007-11-01 18:03:01 +0000923 else
Joe Perchesb6b38f72010-04-21 03:50:45 +0000924 cFYI(1, "no ACL"); /* BB grant all or default perms? */
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +0000925
Steve Frenchbcb02032007-09-25 16:17:24 +0000926/* cifscred->uid = owner_sid_ptr->rid;
927 cifscred->gid = group_sid_ptr->rid;
928 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000929 sizeof(struct cifs_sid));
Steve Frenchbcb02032007-09-25 16:17:24 +0000930 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
Steve French630f3f0c2007-10-25 21:17:17 +0000931 sizeof(struct cifs_sid)); */
Steve Frenchbcb02032007-09-25 16:17:24 +0000932
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -0500933 return rc;
Steve Frenchbcb02032007-09-25 16:17:24 +0000934}
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000935
936
Steve French97837582007-12-31 07:47:21 +0000937/* Convert permission bits from mode to equivalent CIFS ACL */
938static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
Steve Frenchcce246e2008-04-09 20:55:31 +0000939 struct inode *inode, __u64 nmode)
Steve French97837582007-12-31 07:47:21 +0000940{
941 int rc = 0;
942 __u32 dacloffset;
943 __u32 ndacloffset;
944 __u32 sidsoffset;
945 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
946 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
947 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
948
949 if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000950 return -EIO;
Steve French97837582007-12-31 07:47:21 +0000951
952 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
953 le32_to_cpu(pntsd->osidoffset));
954 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
955 le32_to_cpu(pntsd->gsidoffset));
956
957 dacloffset = le32_to_cpu(pntsd->dacloffset);
958 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
959
960 ndacloffset = sizeof(struct cifs_ntsd);
961 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
962 ndacl_ptr->revision = dacl_ptr->revision;
963 ndacl_ptr->size = 0;
964 ndacl_ptr->num_aces = 0;
965
966 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
967
968 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
969
970 /* copy security descriptor control portion and owner and group sid */
971 copy_sec_desc(pntsd, pnntsd, sidsoffset);
972
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000973 return rc;
Steve French97837582007-12-31 07:47:21 +0000974}
975
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400976static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
977 __u16 fid, u32 *pacllen)
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000978{
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000979 struct cifs_ntsd *pntsd = NULL;
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400980 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -0400981 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
982
983 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600984 return ERR_CAST(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000985
986 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -0400987 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400988 FreeXid(xid);
Steve French8b1327f2008-03-14 22:37:16 +0000989
Jeff Layton7ffec372010-09-29 19:51:11 -0400990 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +0000991
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -0600992 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
993 if (rc)
994 return ERR_PTR(rc);
Christoph Hellwig1bf40722009-05-27 09:37:33 -0400995 return pntsd;
996}
997
998static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
999 const char *path, u32 *pacllen)
1000{
1001 struct cifs_ntsd *pntsd = NULL;
1002 int oplock = 0;
1003 int xid, rc;
1004 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -04001005 struct cifsTconInfo *tcon;
1006 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001007
Jeff Layton7ffec372010-09-29 19:51:11 -04001008 if (IS_ERR(tlink))
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001009 return ERR_CAST(tlink);
Jeff Layton7ffec372010-09-29 19:51:11 -04001010
1011 tcon = tlink_tcon(tlink);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001012 xid = GetXid();
1013
Jeff Layton7ffec372010-09-29 19:51:11 -04001014 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001015 &fid, &oplock, NULL, cifs_sb->local_nls,
1016 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001017 if (!rc) {
1018 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
1019 CIFSSMBClose(xid, tcon, fid);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001020 }
1021
Jeff Layton7ffec372010-09-29 19:51:11 -04001022 cifs_put_tlink(tlink);
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001023 FreeXid(xid);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001024
1025 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
1026 if (rc)
1027 return ERR_PTR(rc);
Steve French7505e052007-11-01 18:03:01 +00001028 return pntsd;
1029}
1030
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001031/* Retrieve an ACL from the server */
Shirish Pargaonkarfbeba8b2010-11-27 11:37:54 -06001032struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001033 struct inode *inode, const char *path,
1034 u32 *pacllen)
1035{
1036 struct cifs_ntsd *pntsd = NULL;
1037 struct cifsFileInfo *open_file = NULL;
1038
1039 if (inode)
Jeff Layton6508d902010-09-29 19:51:11 -04001040 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001041 if (!open_file)
1042 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1043
1044 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001045 cifsFileInfo_put(open_file);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001046 return pntsd;
1047}
1048
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001049static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
1050 struct cifs_ntsd *pnntsd, u32 acllen)
Steve French97837582007-12-31 07:47:21 +00001051{
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001052 int xid, rc;
Jeff Layton7ffec372010-09-29 19:51:11 -04001053 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1054
1055 if (IS_ERR(tlink))
1056 return PTR_ERR(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001057
1058 xid = GetXid();
Jeff Layton7ffec372010-09-29 19:51:11 -04001059 rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001060 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001061 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001062
Joe Perchesb6b38f72010-04-21 03:50:45 +00001063 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001064 return rc;
1065}
1066
1067static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
1068 struct cifs_ntsd *pnntsd, u32 acllen)
1069{
1070 int oplock = 0;
1071 int xid, rc;
Steve French97837582007-12-31 07:47:21 +00001072 __u16 fid;
Jeff Layton7ffec372010-09-29 19:51:11 -04001073 struct cifsTconInfo *tcon;
1074 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
Steve French97837582007-12-31 07:47:21 +00001075
Jeff Layton7ffec372010-09-29 19:51:11 -04001076 if (IS_ERR(tlink))
1077 return PTR_ERR(tlink);
1078
1079 tcon = tlink_tcon(tlink);
Steve French97837582007-12-31 07:47:21 +00001080 xid = GetXid();
1081
Jeff Layton7ffec372010-09-29 19:51:11 -04001082 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001083 &fid, &oplock, NULL, cifs_sb->local_nls,
1084 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
1085 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001086 cERROR(1, "Unable to open file to set ACL");
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001087 goto out;
Steve French97837582007-12-31 07:47:21 +00001088 }
1089
Jeff Layton7ffec372010-09-29 19:51:11 -04001090 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001091 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
Steve French97837582007-12-31 07:47:21 +00001092
Jeff Layton7ffec372010-09-29 19:51:11 -04001093 CIFSSMBClose(xid, tcon, fid);
1094out:
Steve French97837582007-12-31 07:47:21 +00001095 FreeXid(xid);
Jeff Layton7ffec372010-09-29 19:51:11 -04001096 cifs_put_tlink(tlink);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001097 return rc;
1098}
Steve French97837582007-12-31 07:47:21 +00001099
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001100/* Set an ACL on the server */
Steve Frenchb73b9a42011-04-19 18:27:10 +00001101int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001102 struct inode *inode, const char *path)
1103{
1104 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1105 struct cifsFileInfo *open_file;
1106 int rc;
1107
Joe Perchesb6b38f72010-04-21 03:50:45 +00001108 cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001109
Jeff Layton6508d902010-09-29 19:51:11 -04001110 open_file = find_readable_file(CIFS_I(inode), true);
Christoph Hellwigb96d31a2009-05-27 09:37:33 -04001111 if (!open_file)
1112 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
1113
1114 rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
Dave Kleikamp6ab409b2009-08-31 11:07:12 -04001115 cifsFileInfo_put(open_file);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001116 return rc;
Steve French97837582007-12-31 07:47:21 +00001117}
1118
Steve French7505e052007-11-01 18:03:01 +00001119/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001120int
Jeff Layton0b8f18e2009-07-09 01:46:37 -04001121cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1122 struct inode *inode, const char *path, const __u16 *pfid)
Steve French7505e052007-11-01 18:03:01 +00001123{
1124 struct cifs_ntsd *pntsd = NULL;
1125 u32 acllen = 0;
1126 int rc = 0;
1127
Joe Perchesb6b38f72010-04-21 03:50:45 +00001128 cFYI(DBG2, "converting ACL to mode for %s", path);
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001129
1130 if (pfid)
1131 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1132 else
1133 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
Steve French7505e052007-11-01 18:03:01 +00001134
1135 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001136 if (IS_ERR(pntsd)) {
1137 rc = PTR_ERR(pntsd);
1138 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1139 } else {
Shirish Pargaonkar9409ae52011-04-22 12:09:36 -05001140 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001141 kfree(pntsd);
1142 if (rc)
1143 cERROR(1, "parse sec desc failed rc = %d", rc);
1144 }
Steve French7505e052007-11-01 18:03:01 +00001145
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001146 return rc;
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00001147}
Steve French953f8682007-10-31 04:54:42 +00001148
Steve French7505e052007-11-01 18:03:01 +00001149/* Convert mode bits to an ACL so we can update the ACL on the server */
Shirish Pargaonkar78415d22010-11-27 11:37:26 -06001150int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
Steve French953f8682007-10-31 04:54:42 +00001151{
1152 int rc = 0;
Steve Frenchcce246e2008-04-09 20:55:31 +00001153 __u32 secdesclen = 0;
Steve French97837582007-12-31 07:47:21 +00001154 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1155 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
Steve French953f8682007-10-31 04:54:42 +00001156
Joe Perchesb6b38f72010-04-21 03:50:45 +00001157 cFYI(DBG2, "set ACL from mode for %s", path);
Steve French953f8682007-10-31 04:54:42 +00001158
1159 /* Get the security descriptor */
Christoph Hellwig1bf40722009-05-27 09:37:33 -04001160 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
Steve French953f8682007-10-31 04:54:42 +00001161
Steve French97837582007-12-31 07:47:21 +00001162 /* Add three ACEs for owner, group, everyone getting rid of
1163 other ACEs as chmod disables ACEs and set the security descriptor */
Steve French953f8682007-10-31 04:54:42 +00001164
Shirish Pargaonkar987b21d2010-11-10 07:50:35 -06001165 if (IS_ERR(pntsd)) {
1166 rc = PTR_ERR(pntsd);
1167 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1168 } else {
Steve French97837582007-12-31 07:47:21 +00001169 /* allocate memory for the smb header,
1170 set security descriptor request security descriptor
1171 parameters, and secuirty descriptor itself */
Steve French953f8682007-10-31 04:54:42 +00001172
Steve Frenchcce246e2008-04-09 20:55:31 +00001173 secdesclen = secdesclen < DEFSECDESCLEN ?
1174 DEFSECDESCLEN : secdesclen;
1175 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
Steve French97837582007-12-31 07:47:21 +00001176 if (!pnntsd) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001177 cERROR(1, "Unable to allocate security descriptor");
Steve French97837582007-12-31 07:47:21 +00001178 kfree(pntsd);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001179 return -ENOMEM;
Steve French97837582007-12-31 07:47:21 +00001180 }
Steve French7505e052007-11-01 18:03:01 +00001181
Steve Frenchcce246e2008-04-09 20:55:31 +00001182 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
Steve French97837582007-12-31 07:47:21 +00001183
Joe Perchesb6b38f72010-04-21 03:50:45 +00001184 cFYI(DBG2, "build_sec_desc rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001185
1186 if (!rc) {
1187 /* Set the security descriptor */
Steve Frenchcce246e2008-04-09 20:55:31 +00001188 rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
Joe Perchesb6b38f72010-04-21 03:50:45 +00001189 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
Steve French97837582007-12-31 07:47:21 +00001190 }
1191
1192 kfree(pnntsd);
1193 kfree(pntsd);
1194 }
1195
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +00001196 return rc;
Steve French953f8682007-10-31 04:54:42 +00001197}