ARM: mcpm: provide an interface to set the SMP ops at run time
[linux-2.6.git] / fs / cifs / cifsacl.c
blobf1e3f25fe00412a584a70883a5cf6f661741d821
1 /*
2 * fs/cifs/cifsacl.c
4 * Copyright (C) International Business Machines Corp., 2007,2008
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * Contains the routines for mapping CIFS/NTFS ACLs
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.
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.
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
24 #include <linux/fs.h>
25 #include <linux/slab.h>
26 #include <linux/string.h>
27 #include <linux/keyctl.h>
28 #include <linux/key-type.h>
29 #include <keys/user-type.h>
30 #include "cifspdu.h"
31 #include "cifsglob.h"
32 #include "cifsacl.h"
33 #include "cifsproto.h"
34 #include "cifs_debug.h"
36 /* security id for everyone/world system group */
37 static const struct cifs_sid sid_everyone = {
38 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
39 /* security id for Authenticated Users system group */
40 static const struct cifs_sid sid_authusers = {
41 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
42 /* group users */
43 static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
45 static const struct cred *root_cred;
47 static int
48 cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
50 char *payload;
53 * If the payload is less than or equal to the size of a pointer, then
54 * an allocation here is wasteful. Just copy the data directly to the
55 * payload.value union member instead.
57 * With this however, you must check the datalen before trying to
58 * dereference payload.data!
60 if (prep->datalen <= sizeof(key->payload)) {
61 key->payload.value = 0;
62 memcpy(&key->payload.value, prep->data, prep->datalen);
63 key->datalen = prep->datalen;
64 return 0;
66 payload = kmalloc(prep->datalen, GFP_KERNEL);
67 if (!payload)
68 return -ENOMEM;
70 memcpy(payload, prep->data, prep->datalen);
71 key->payload.data = payload;
72 key->datalen = prep->datalen;
73 return 0;
76 static inline void
77 cifs_idmap_key_destroy(struct key *key)
79 if (key->datalen > sizeof(key->payload))
80 kfree(key->payload.data);
83 static struct key_type cifs_idmap_key_type = {
84 .name = "cifs.idmap",
85 .instantiate = cifs_idmap_key_instantiate,
86 .destroy = cifs_idmap_key_destroy,
87 .describe = user_describe,
88 .match = user_match,
91 static char *
92 sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
94 int i, len;
95 unsigned int saval;
96 char *sidstr, *strptr;
97 unsigned long long id_auth_val;
99 /* 3 bytes for prefix */
100 sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
101 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
102 GFP_KERNEL);
103 if (!sidstr)
104 return sidstr;
106 strptr = sidstr;
107 len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
108 sidptr->revision);
109 strptr += len;
111 /* The authority field is a single 48-bit number */
112 id_auth_val = (unsigned long long)sidptr->authority[5];
113 id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
114 id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
115 id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
116 id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
117 id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
120 * MS-DTYP states that if the authority is >= 2^32, then it should be
121 * expressed as a hex value.
123 if (id_auth_val <= UINT_MAX)
124 len = sprintf(strptr, "-%llu", id_auth_val);
125 else
126 len = sprintf(strptr, "-0x%llx", id_auth_val);
128 strptr += len;
130 for (i = 0; i < sidptr->num_subauth; ++i) {
131 saval = le32_to_cpu(sidptr->sub_auth[i]);
132 len = sprintf(strptr, "-%u", saval);
133 strptr += len;
136 return sidstr;
140 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
141 * the same returns zero, if they do not match returns non-zero.
143 static int
144 compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
146 int i;
147 int num_subauth, num_sat, num_saw;
149 if ((!ctsid) || (!cwsid))
150 return 1;
152 /* compare the revision */
153 if (ctsid->revision != cwsid->revision) {
154 if (ctsid->revision > cwsid->revision)
155 return 1;
156 else
157 return -1;
160 /* compare all of the six auth values */
161 for (i = 0; i < NUM_AUTHS; ++i) {
162 if (ctsid->authority[i] != cwsid->authority[i]) {
163 if (ctsid->authority[i] > cwsid->authority[i])
164 return 1;
165 else
166 return -1;
170 /* compare all of the subauth values if any */
171 num_sat = ctsid->num_subauth;
172 num_saw = cwsid->num_subauth;
173 num_subauth = num_sat < num_saw ? num_sat : num_saw;
174 if (num_subauth) {
175 for (i = 0; i < num_subauth; ++i) {
176 if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
177 if (le32_to_cpu(ctsid->sub_auth[i]) >
178 le32_to_cpu(cwsid->sub_auth[i]))
179 return 1;
180 else
181 return -1;
186 return 0; /* sids compare/match */
189 static void
190 cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
192 int i;
194 dst->revision = src->revision;
195 dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
196 for (i = 0; i < NUM_AUTHS; ++i)
197 dst->authority[i] = src->authority[i];
198 for (i = 0; i < dst->num_subauth; ++i)
199 dst->sub_auth[i] = src->sub_auth[i];
202 static int
203 id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
205 int rc;
206 struct key *sidkey;
207 struct cifs_sid *ksid;
208 unsigned int ksid_size;
209 char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
210 const struct cred *saved_cred;
212 rc = snprintf(desc, sizeof(desc), "%ci:%u",
213 sidtype == SIDOWNER ? 'o' : 'g', cid);
214 if (rc >= sizeof(desc))
215 return -EINVAL;
217 rc = 0;
218 saved_cred = override_creds(root_cred);
219 sidkey = request_key(&cifs_idmap_key_type, desc, "");
220 if (IS_ERR(sidkey)) {
221 rc = -EINVAL;
222 cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
223 sidtype == SIDOWNER ? 'u' : 'g', cid);
224 goto out_revert_creds;
225 } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
226 rc = -EIO;
227 cFYI(1, "%s: Downcall contained malformed key "
228 "(datalen=%hu)", __func__, sidkey->datalen);
229 goto invalidate_key;
233 * A sid is usually too large to be embedded in payload.value, but if
234 * there are no subauthorities and the host has 8-byte pointers, then
235 * it could be.
237 ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
238 (struct cifs_sid *)&sidkey->payload.value :
239 (struct cifs_sid *)sidkey->payload.data;
241 ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
242 if (ksid_size > sidkey->datalen) {
243 rc = -EIO;
244 cFYI(1, "%s: Downcall contained malformed key (datalen=%hu, "
245 "ksid_size=%u)", __func__, sidkey->datalen, ksid_size);
246 goto invalidate_key;
249 cifs_copy_sid(ssid, ksid);
250 out_key_put:
251 key_put(sidkey);
252 out_revert_creds:
253 revert_creds(saved_cred);
254 return rc;
256 invalidate_key:
257 key_invalidate(sidkey);
258 goto out_key_put;
261 static int
262 sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
263 struct cifs_fattr *fattr, uint sidtype)
265 int rc;
266 struct key *sidkey;
267 char *sidstr;
268 const struct cred *saved_cred;
269 kuid_t fuid = cifs_sb->mnt_uid;
270 kgid_t fgid = cifs_sb->mnt_gid;
273 * If we have too many subauthorities, then something is really wrong.
274 * Just return an error.
276 if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
277 cFYI(1, "%s: %u subauthorities is too many!", __func__,
278 psid->num_subauth);
279 return -EIO;
282 sidstr = sid_to_key_str(psid, sidtype);
283 if (!sidstr)
284 return -ENOMEM;
286 saved_cred = override_creds(root_cred);
287 sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
288 if (IS_ERR(sidkey)) {
289 rc = -EINVAL;
290 cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
291 sidtype == SIDOWNER ? 'u' : 'g');
292 goto out_revert_creds;
296 * FIXME: Here we assume that uid_t and gid_t are same size. It's
297 * probably a safe assumption but might be better to check based on
298 * sidtype.
300 BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
301 if (sidkey->datalen != sizeof(uid_t)) {
302 rc = -EIO;
303 cFYI(1, "%s: Downcall contained malformed key "
304 "(datalen=%hu)", __func__, sidkey->datalen);
305 key_invalidate(sidkey);
306 goto out_key_put;
309 if (sidtype == SIDOWNER) {
310 kuid_t uid;
311 uid_t id;
312 memcpy(&id, &sidkey->payload.value, sizeof(uid_t));
313 uid = make_kuid(&init_user_ns, id);
314 if (uid_valid(uid))
315 fuid = uid;
316 } else {
317 kgid_t gid;
318 gid_t id;
319 memcpy(&id, &sidkey->payload.value, sizeof(gid_t));
320 gid = make_kgid(&init_user_ns, id);
321 if (gid_valid(gid))
322 fgid = gid;
325 out_key_put:
326 key_put(sidkey);
327 out_revert_creds:
328 revert_creds(saved_cred);
329 kfree(sidstr);
332 * Note that we return 0 here unconditionally. If the mapping
333 * fails then we just fall back to using the mnt_uid/mnt_gid.
335 if (sidtype == SIDOWNER)
336 fattr->cf_uid = fuid;
337 else
338 fattr->cf_gid = fgid;
339 return 0;
343 init_cifs_idmap(void)
345 struct cred *cred;
346 struct key *keyring;
347 int ret;
349 cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
351 /* create an override credential set with a special thread keyring in
352 * which requests are cached
354 * this is used to prevent malicious redirections from being installed
355 * with add_key().
357 cred = prepare_kernel_cred(NULL);
358 if (!cred)
359 return -ENOMEM;
361 keyring = keyring_alloc(".cifs_idmap",
362 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
363 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
364 KEY_USR_VIEW | KEY_USR_READ,
365 KEY_ALLOC_NOT_IN_QUOTA, NULL);
366 if (IS_ERR(keyring)) {
367 ret = PTR_ERR(keyring);
368 goto failed_put_cred;
371 ret = register_key_type(&cifs_idmap_key_type);
372 if (ret < 0)
373 goto failed_put_key;
375 /* instruct request_key() to use this special keyring as a cache for
376 * the results it looks up */
377 set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
378 cred->thread_keyring = keyring;
379 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
380 root_cred = cred;
382 cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
383 return 0;
385 failed_put_key:
386 key_put(keyring);
387 failed_put_cred:
388 put_cred(cred);
389 return ret;
392 void
393 exit_cifs_idmap(void)
395 key_revoke(root_cred->thread_keyring);
396 unregister_key_type(&cifs_idmap_key_type);
397 put_cred(root_cred);
398 cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
401 /* copy ntsd, owner sid, and group sid from a security descriptor to another */
402 static void copy_sec_desc(const struct cifs_ntsd *pntsd,
403 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
405 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
406 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
408 /* copy security descriptor control portion */
409 pnntsd->revision = pntsd->revision;
410 pnntsd->type = pntsd->type;
411 pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
412 pnntsd->sacloffset = 0;
413 pnntsd->osidoffset = cpu_to_le32(sidsoffset);
414 pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
416 /* copy owner sid */
417 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
418 le32_to_cpu(pntsd->osidoffset));
419 nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
420 cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
422 /* copy group sid */
423 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
424 le32_to_cpu(pntsd->gsidoffset));
425 ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
426 sizeof(struct cifs_sid));
427 cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
429 return;
434 change posix mode to reflect permissions
435 pmode is the existing mode (we only want to overwrite part of this
436 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
438 static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
439 umode_t *pbits_to_set)
441 __u32 flags = le32_to_cpu(ace_flags);
442 /* the order of ACEs is important. The canonical order is to begin with
443 DENY entries followed by ALLOW, otherwise an allow entry could be
444 encountered first, making the subsequent deny entry like "dead code"
445 which would be superflous since Windows stops when a match is made
446 for the operation you are trying to perform for your user */
448 /* For deny ACEs we change the mask so that subsequent allow access
449 control entries do not turn on the bits we are denying */
450 if (type == ACCESS_DENIED) {
451 if (flags & GENERIC_ALL)
452 *pbits_to_set &= ~S_IRWXUGO;
454 if ((flags & GENERIC_WRITE) ||
455 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
456 *pbits_to_set &= ~S_IWUGO;
457 if ((flags & GENERIC_READ) ||
458 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
459 *pbits_to_set &= ~S_IRUGO;
460 if ((flags & GENERIC_EXECUTE) ||
461 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
462 *pbits_to_set &= ~S_IXUGO;
463 return;
464 } else if (type != ACCESS_ALLOWED) {
465 cERROR(1, "unknown access control type %d", type);
466 return;
468 /* else ACCESS_ALLOWED type */
470 if (flags & GENERIC_ALL) {
471 *pmode |= (S_IRWXUGO & (*pbits_to_set));
472 cFYI(DBG2, "all perms");
473 return;
475 if ((flags & GENERIC_WRITE) ||
476 ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
477 *pmode |= (S_IWUGO & (*pbits_to_set));
478 if ((flags & GENERIC_READ) ||
479 ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
480 *pmode |= (S_IRUGO & (*pbits_to_set));
481 if ((flags & GENERIC_EXECUTE) ||
482 ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
483 *pmode |= (S_IXUGO & (*pbits_to_set));
485 cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
486 return;
490 Generate access flags to reflect permissions mode is the existing mode.
491 This function is called for every ACE in the DACL whose SID matches
492 with either owner or group or everyone.
495 static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
496 __u32 *pace_flags)
498 /* reset access mask */
499 *pace_flags = 0x0;
501 /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
502 mode &= bits_to_use;
504 /* check for R/W/X UGO since we do not know whose flags
505 is this but we have cleared all the bits sans RWX for
506 either user or group or other as per bits_to_use */
507 if (mode & S_IRUGO)
508 *pace_flags |= SET_FILE_READ_RIGHTS;
509 if (mode & S_IWUGO)
510 *pace_flags |= SET_FILE_WRITE_RIGHTS;
511 if (mode & S_IXUGO)
512 *pace_flags |= SET_FILE_EXEC_RIGHTS;
514 cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
515 return;
518 static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
519 const struct cifs_sid *psid, __u64 nmode, umode_t bits)
521 int i;
522 __u16 size = 0;
523 __u32 access_req = 0;
525 pntace->type = ACCESS_ALLOWED;
526 pntace->flags = 0x0;
527 mode_to_access_flags(nmode, bits, &access_req);
528 if (!access_req)
529 access_req = SET_MINIMUM_RIGHTS;
530 pntace->access_req = cpu_to_le32(access_req);
532 pntace->sid.revision = psid->revision;
533 pntace->sid.num_subauth = psid->num_subauth;
534 for (i = 0; i < NUM_AUTHS; i++)
535 pntace->sid.authority[i] = psid->authority[i];
536 for (i = 0; i < psid->num_subauth; i++)
537 pntace->sid.sub_auth[i] = psid->sub_auth[i];
539 size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
540 pntace->size = cpu_to_le16(size);
542 return size;
546 #ifdef CONFIG_CIFS_DEBUG2
547 static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
549 int num_subauth;
551 /* validate that we do not go past end of acl */
553 if (le16_to_cpu(pace->size) < 16) {
554 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
555 return;
558 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
559 cERROR(1, "ACL too small to parse ACE");
560 return;
563 num_subauth = pace->sid.num_subauth;
564 if (num_subauth) {
565 int i;
566 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
567 pace->sid.revision, pace->sid.num_subauth, pace->type,
568 pace->flags, le16_to_cpu(pace->size));
569 for (i = 0; i < num_subauth; ++i) {
570 cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
571 le32_to_cpu(pace->sid.sub_auth[i]));
574 /* BB add length check to make sure that we do not have huge
575 num auths and therefore go off the end */
578 return;
580 #endif
583 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
584 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
585 struct cifs_fattr *fattr)
587 int i;
588 int num_aces = 0;
589 int acl_size;
590 char *acl_base;
591 struct cifs_ace **ppace;
593 /* BB need to add parm so we can store the SID BB */
595 if (!pdacl) {
596 /* no DACL in the security descriptor, set
597 all the permissions for user/group/other */
598 fattr->cf_mode |= S_IRWXUGO;
599 return;
602 /* validate that we do not go past end of acl */
603 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
604 cERROR(1, "ACL too small to parse DACL");
605 return;
608 cFYI(DBG2, "DACL revision %d size %d num aces %d",
609 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
610 le32_to_cpu(pdacl->num_aces));
612 /* reset rwx permissions for user/group/other.
613 Also, if num_aces is 0 i.e. DACL has no ACEs,
614 user/group/other have no permissions */
615 fattr->cf_mode &= ~(S_IRWXUGO);
617 acl_base = (char *)pdacl;
618 acl_size = sizeof(struct cifs_acl);
620 num_aces = le32_to_cpu(pdacl->num_aces);
621 if (num_aces > 0) {
622 umode_t user_mask = S_IRWXU;
623 umode_t group_mask = S_IRWXG;
624 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
626 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
627 return;
628 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
629 GFP_KERNEL);
630 if (!ppace) {
631 cERROR(1, "DACL memory allocation error");
632 return;
635 for (i = 0; i < num_aces; ++i) {
636 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
637 #ifdef CONFIG_CIFS_DEBUG2
638 dump_ace(ppace[i], end_of_acl);
639 #endif
640 if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
641 access_flags_to_mode(ppace[i]->access_req,
642 ppace[i]->type,
643 &fattr->cf_mode,
644 &user_mask);
645 if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
646 access_flags_to_mode(ppace[i]->access_req,
647 ppace[i]->type,
648 &fattr->cf_mode,
649 &group_mask);
650 if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
651 access_flags_to_mode(ppace[i]->access_req,
652 ppace[i]->type,
653 &fattr->cf_mode,
654 &other_mask);
655 if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
656 access_flags_to_mode(ppace[i]->access_req,
657 ppace[i]->type,
658 &fattr->cf_mode,
659 &other_mask);
662 /* memcpy((void *)(&(cifscred->aces[i])),
663 (void *)ppace[i],
664 sizeof(struct cifs_ace)); */
666 acl_base = (char *)ppace[i];
667 acl_size = le16_to_cpu(ppace[i]->size);
670 kfree(ppace);
673 return;
677 static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
678 struct cifs_sid *pgrpsid, __u64 nmode)
680 u16 size = 0;
681 struct cifs_acl *pnndacl;
683 pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
685 size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
686 pownersid, nmode, S_IRWXU);
687 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
688 pgrpsid, nmode, S_IRWXG);
689 size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
690 &sid_everyone, nmode, S_IRWXO);
692 pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
693 pndacl->num_aces = cpu_to_le32(3);
695 return 0;
699 static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
701 /* BB need to add parm so we can store the SID BB */
703 /* validate that we do not go past end of ACL - sid must be at least 8
704 bytes long (assuming no sub-auths - e.g. the null SID */
705 if (end_of_acl < (char *)psid + 8) {
706 cERROR(1, "ACL too small to parse SID %p", psid);
707 return -EINVAL;
710 #ifdef CONFIG_CIFS_DEBUG2
711 if (psid->num_subauth) {
712 int i;
713 cFYI(1, "SID revision %d num_auth %d",
714 psid->revision, psid->num_subauth);
716 for (i = 0; i < psid->num_subauth; i++) {
717 cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
718 le32_to_cpu(psid->sub_auth[i]));
721 /* BB add length check to make sure that we do not have huge
722 num auths and therefore go off the end */
723 cFYI(1, "RID 0x%x",
724 le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
726 #endif
728 return 0;
732 /* Convert CIFS ACL to POSIX form */
733 static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
734 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
736 int rc = 0;
737 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
738 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
739 char *end_of_acl = ((char *)pntsd) + acl_len;
740 __u32 dacloffset;
742 if (pntsd == NULL)
743 return -EIO;
745 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
746 le32_to_cpu(pntsd->osidoffset));
747 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
748 le32_to_cpu(pntsd->gsidoffset));
749 dacloffset = le32_to_cpu(pntsd->dacloffset);
750 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
751 cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
752 "sacloffset 0x%x dacloffset 0x%x",
753 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
754 le32_to_cpu(pntsd->gsidoffset),
755 le32_to_cpu(pntsd->sacloffset), dacloffset);
756 /* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
757 rc = parse_sid(owner_sid_ptr, end_of_acl);
758 if (rc) {
759 cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
760 return rc;
762 rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
763 if (rc) {
764 cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
765 return rc;
768 rc = parse_sid(group_sid_ptr, end_of_acl);
769 if (rc) {
770 cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
771 return rc;
773 rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
774 if (rc) {
775 cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
776 return rc;
779 if (dacloffset)
780 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
781 group_sid_ptr, fattr);
782 else
783 cFYI(1, "no ACL"); /* BB grant all or default perms? */
785 return rc;
788 /* Convert permission bits from mode to equivalent CIFS ACL */
789 static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
790 __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
792 int rc = 0;
793 __u32 dacloffset;
794 __u32 ndacloffset;
795 __u32 sidsoffset;
796 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
797 struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
798 struct cifs_acl *dacl_ptr = NULL; /* no need for SACL ptr */
799 struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
801 if (nmode != NO_CHANGE_64) { /* chmod */
802 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
803 le32_to_cpu(pntsd->osidoffset));
804 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
805 le32_to_cpu(pntsd->gsidoffset));
806 dacloffset = le32_to_cpu(pntsd->dacloffset);
807 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
808 ndacloffset = sizeof(struct cifs_ntsd);
809 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
810 ndacl_ptr->revision = dacl_ptr->revision;
811 ndacl_ptr->size = 0;
812 ndacl_ptr->num_aces = 0;
814 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
815 nmode);
816 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
817 /* copy sec desc control portion & owner and group sids */
818 copy_sec_desc(pntsd, pnntsd, sidsoffset);
819 *aclflag = CIFS_ACL_DACL;
820 } else {
821 memcpy(pnntsd, pntsd, secdesclen);
822 if (uid_valid(uid)) { /* chown */
823 uid_t id;
824 owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
825 le32_to_cpu(pnntsd->osidoffset));
826 nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
827 GFP_KERNEL);
828 if (!nowner_sid_ptr)
829 return -ENOMEM;
830 id = from_kuid(&init_user_ns, uid);
831 rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
832 if (rc) {
833 cFYI(1, "%s: Mapping error %d for owner id %d",
834 __func__, rc, id);
835 kfree(nowner_sid_ptr);
836 return rc;
838 cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
839 kfree(nowner_sid_ptr);
840 *aclflag = CIFS_ACL_OWNER;
842 if (gid_valid(gid)) { /* chgrp */
843 gid_t id;
844 group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
845 le32_to_cpu(pnntsd->gsidoffset));
846 ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
847 GFP_KERNEL);
848 if (!ngroup_sid_ptr)
849 return -ENOMEM;
850 id = from_kgid(&init_user_ns, gid);
851 rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
852 if (rc) {
853 cFYI(1, "%s: Mapping error %d for group id %d",
854 __func__, rc, id);
855 kfree(ngroup_sid_ptr);
856 return rc;
858 cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
859 kfree(ngroup_sid_ptr);
860 *aclflag = CIFS_ACL_GROUP;
864 return rc;
867 static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
868 __u16 fid, u32 *pacllen)
870 struct cifs_ntsd *pntsd = NULL;
871 unsigned int xid;
872 int rc;
873 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
875 if (IS_ERR(tlink))
876 return ERR_CAST(tlink);
878 xid = get_xid();
879 rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
880 free_xid(xid);
882 cifs_put_tlink(tlink);
884 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
885 if (rc)
886 return ERR_PTR(rc);
887 return pntsd;
890 static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
891 const char *path, u32 *pacllen)
893 struct cifs_ntsd *pntsd = NULL;
894 int oplock = 0;
895 unsigned int xid;
896 int rc, create_options = 0;
897 __u16 fid;
898 struct cifs_tcon *tcon;
899 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
901 if (IS_ERR(tlink))
902 return ERR_CAST(tlink);
904 tcon = tlink_tcon(tlink);
905 xid = get_xid();
907 if (backup_cred(cifs_sb))
908 create_options |= CREATE_OPEN_BACKUP_INTENT;
910 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
911 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
912 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
913 if (!rc) {
914 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
915 CIFSSMBClose(xid, tcon, fid);
918 cifs_put_tlink(tlink);
919 free_xid(xid);
921 cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
922 if (rc)
923 return ERR_PTR(rc);
924 return pntsd;
927 /* Retrieve an ACL from the server */
928 struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
929 struct inode *inode, const char *path,
930 u32 *pacllen)
932 struct cifs_ntsd *pntsd = NULL;
933 struct cifsFileInfo *open_file = NULL;
935 if (inode)
936 open_file = find_readable_file(CIFS_I(inode), true);
937 if (!open_file)
938 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
940 pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
941 cifsFileInfo_put(open_file);
942 return pntsd;
945 /* Set an ACL on the server */
946 int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
947 struct inode *inode, const char *path, int aclflag)
949 int oplock = 0;
950 unsigned int xid;
951 int rc, access_flags, create_options = 0;
952 __u16 fid;
953 struct cifs_tcon *tcon;
954 struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
955 struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
957 if (IS_ERR(tlink))
958 return PTR_ERR(tlink);
960 tcon = tlink_tcon(tlink);
961 xid = get_xid();
963 if (backup_cred(cifs_sb))
964 create_options |= CREATE_OPEN_BACKUP_INTENT;
966 if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
967 access_flags = WRITE_OWNER;
968 else
969 access_flags = WRITE_DAC;
971 rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
972 create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
973 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
974 if (rc) {
975 cERROR(1, "Unable to open file to set ACL");
976 goto out;
979 rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
980 cFYI(DBG2, "SetCIFSACL rc = %d", rc);
982 CIFSSMBClose(xid, tcon, fid);
983 out:
984 free_xid(xid);
985 cifs_put_tlink(tlink);
986 return rc;
989 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
991 cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
992 struct inode *inode, const char *path, const __u16 *pfid)
994 struct cifs_ntsd *pntsd = NULL;
995 u32 acllen = 0;
996 int rc = 0;
998 cFYI(DBG2, "converting ACL to mode for %s", path);
1000 if (pfid)
1001 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
1002 else
1003 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
1005 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
1006 if (IS_ERR(pntsd)) {
1007 rc = PTR_ERR(pntsd);
1008 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1009 } else {
1010 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
1011 kfree(pntsd);
1012 if (rc)
1013 cERROR(1, "parse sec desc failed rc = %d", rc);
1016 return rc;
1019 /* Convert mode bits to an ACL so we can update the ACL on the server */
1021 id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1022 kuid_t uid, kgid_t gid)
1024 int rc = 0;
1025 int aclflag = CIFS_ACL_DACL; /* default flag to set */
1026 __u32 secdesclen = 0;
1027 struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1028 struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
1030 cFYI(DBG2, "set ACL from mode for %s", path);
1032 /* Get the security descriptor */
1033 pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
1034 if (IS_ERR(pntsd)) {
1035 rc = PTR_ERR(pntsd);
1036 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
1037 goto out;
1041 * Add three ACEs for owner, group, everyone getting rid of other ACEs
1042 * as chmod disables ACEs and set the security descriptor. Allocate
1043 * memory for the smb header, set security descriptor request security
1044 * descriptor parameters, and secuirty descriptor itself
1046 secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
1047 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1048 if (!pnntsd) {
1049 cERROR(1, "Unable to allocate security descriptor");
1050 kfree(pntsd);
1051 return -ENOMEM;
1054 rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1055 &aclflag);
1057 cFYI(DBG2, "build_sec_desc rc: %d", rc);
1059 if (!rc) {
1060 /* Set the security descriptor */
1061 rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
1062 cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1065 kfree(pnntsd);
1066 kfree(pntsd);
1067 out:
1068 return rc;