~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/cifs/cifsacl.c

Version: ~ [ linux-5.7 ] ~ [ linux-5.6.15 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.43 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.125 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.182 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.225 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.225 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.84 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *   fs/cifs/cifsacl.c
  3  *
  4  *   Copyright (C) International Business Machines  Corp., 2007,2008
  5  *   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 
 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"
 35 
 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}, {cpu_to_le32(11)} };
 42 /* group users */
 43 static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
 44 
 45 /* S-1-22-1 Unmapped Unix users */
 46 static const struct cifs_sid sid_unix_users = {1, 1, {0, 0, 0, 0, 0, 22},
 47                 {cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
 48 
 49 /* S-1-22-2 Unmapped Unix groups */
 50 static const struct cifs_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22},
 51                 {cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
 52 
 53 /*
 54  * See http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
 55  */
 56 
 57 /* S-1-5-88 MS NFS and Apple style UID/GID/mode */
 58 
 59 /* S-1-5-88-1 Unix uid */
 60 static const struct cifs_sid sid_unix_NFS_users = { 1, 2, {0, 0, 0, 0, 0, 5},
 61         {cpu_to_le32(88),
 62          cpu_to_le32(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
 63 
 64 /* S-1-5-88-2 Unix gid */
 65 static const struct cifs_sid sid_unix_NFS_groups = { 1, 2, {0, 0, 0, 0, 0, 5},
 66         {cpu_to_le32(88),
 67          cpu_to_le32(2), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
 68 
 69 /* S-1-5-88-3 Unix mode */
 70 static const struct cifs_sid sid_unix_NFS_mode = { 1, 2, {0, 0, 0, 0, 0, 5},
 71         {cpu_to_le32(88),
 72          cpu_to_le32(3), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} };
 73 
 74 static const struct cred *root_cred;
 75 
 76 static int
 77 cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
 78 {
 79         char *payload;
 80 
 81         /*
 82          * If the payload is less than or equal to the size of a pointer, then
 83          * an allocation here is wasteful. Just copy the data directly to the
 84          * payload.value union member instead.
 85          *
 86          * With this however, you must check the datalen before trying to
 87          * dereference payload.data!
 88          */
 89         if (prep->datalen <= sizeof(key->payload)) {
 90                 key->payload.data[0] = NULL;
 91                 memcpy(&key->payload, prep->data, prep->datalen);
 92         } else {
 93                 payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
 94                 if (!payload)
 95                         return -ENOMEM;
 96                 key->payload.data[0] = payload;
 97         }
 98 
 99         key->datalen = prep->datalen;
100         return 0;
101 }
102 
103 static inline void
104 cifs_idmap_key_destroy(struct key *key)
105 {
106         if (key->datalen > sizeof(key->payload))
107                 kfree(key->payload.data[0]);
108 }
109 
110 static struct key_type cifs_idmap_key_type = {
111         .name        = "cifs.idmap",
112         .instantiate = cifs_idmap_key_instantiate,
113         .destroy     = cifs_idmap_key_destroy,
114         .describe    = user_describe,
115 };
116 
117 static char *
118 sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
119 {
120         int i, len;
121         unsigned int saval;
122         char *sidstr, *strptr;
123         unsigned long long id_auth_val;
124 
125         /* 3 bytes for prefix */
126         sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
127                          (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
128                          GFP_KERNEL);
129         if (!sidstr)
130                 return sidstr;
131 
132         strptr = sidstr;
133         len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
134                         sidptr->revision);
135         strptr += len;
136 
137         /* The authority field is a single 48-bit number */
138         id_auth_val = (unsigned long long)sidptr->authority[5];
139         id_auth_val |= (unsigned long long)sidptr->authority[4] << 8;
140         id_auth_val |= (unsigned long long)sidptr->authority[3] << 16;
141         id_auth_val |= (unsigned long long)sidptr->authority[2] << 24;
142         id_auth_val |= (unsigned long long)sidptr->authority[1] << 32;
143         id_auth_val |= (unsigned long long)sidptr->authority[0] << 48;
144 
145         /*
146          * MS-DTYP states that if the authority is >= 2^32, then it should be
147          * expressed as a hex value.
148          */
149         if (id_auth_val <= UINT_MAX)
150                 len = sprintf(strptr, "-%llu", id_auth_val);
151         else
152                 len = sprintf(strptr, "-0x%llx", id_auth_val);
153 
154         strptr += len;
155 
156         for (i = 0; i < sidptr->num_subauth; ++i) {
157                 saval = le32_to_cpu(sidptr->sub_auth[i]);
158                 len = sprintf(strptr, "-%u", saval);
159                 strptr += len;
160         }
161 
162         return sidstr;
163 }
164 
165 /*
166  * if the two SIDs (roughly equivalent to a UUID for a user or group) are
167  * the same returns zero, if they do not match returns non-zero.
168  */
169 static int
170 compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
171 {
172         int i;
173         int num_subauth, num_sat, num_saw;
174 
175         if ((!ctsid) || (!cwsid))
176                 return 1;
177 
178         /* compare the revision */
179         if (ctsid->revision != cwsid->revision) {
180                 if (ctsid->revision > cwsid->revision)
181                         return 1;
182                 else
183                         return -1;
184         }
185 
186         /* compare all of the six auth values */
187         for (i = 0; i < NUM_AUTHS; ++i) {
188                 if (ctsid->authority[i] != cwsid->authority[i]) {
189                         if (ctsid->authority[i] > cwsid->authority[i])
190                                 return 1;
191                         else
192                                 return -1;
193                 }
194         }
195 
196         /* compare all of the subauth values if any */
197         num_sat = ctsid->num_subauth;
198         num_saw = cwsid->num_subauth;
199         num_subauth = num_sat < num_saw ? num_sat : num_saw;
200         if (num_subauth) {
201                 for (i = 0; i < num_subauth; ++i) {
202                         if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
203                                 if (le32_to_cpu(ctsid->sub_auth[i]) >
204                                         le32_to_cpu(cwsid->sub_auth[i]))
205                                         return 1;
206                                 else
207                                         return -1;
208                         }
209                 }
210         }
211 
212         return 0; /* sids compare/match */
213 }
214 
215 static bool
216 is_well_known_sid(const struct cifs_sid *psid, uint32_t *puid, bool is_group)
217 {
218         int i;
219         int num_subauth;
220         const struct cifs_sid *pwell_known_sid;
221 
222         if (!psid || (puid == NULL))
223                 return false;
224 
225         num_subauth = psid->num_subauth;
226 
227         /* check if Mac (or Windows NFS) vs. Samba format for Unix owner SID */
228         if (num_subauth == 2) {
229                 if (is_group)
230                         pwell_known_sid = &sid_unix_groups;
231                 else
232                         pwell_known_sid = &sid_unix_users;
233         } else if (num_subauth == 3) {
234                 if (is_group)
235                         pwell_known_sid = &sid_unix_NFS_groups;
236                 else
237                         pwell_known_sid = &sid_unix_NFS_users;
238         } else
239                 return false;
240 
241         /* compare the revision */
242         if (psid->revision != pwell_known_sid->revision)
243                 return false;
244 
245         /* compare all of the six auth values */
246         for (i = 0; i < NUM_AUTHS; ++i) {
247                 if (psid->authority[i] != pwell_known_sid->authority[i]) {
248                         cifs_dbg(FYI, "auth %d did not match\n", i);
249                         return false;
250                 }
251         }
252 
253         if (num_subauth == 2) {
254                 if (psid->sub_auth[0] != pwell_known_sid->sub_auth[0])
255                         return false;
256 
257                 *puid = le32_to_cpu(psid->sub_auth[1]);
258         } else /* 3 subauths, ie Windows/Mac style */ {
259                 *puid = le32_to_cpu(psid->sub_auth[0]);
260                 if ((psid->sub_auth[0] != pwell_known_sid->sub_auth[0]) ||
261                     (psid->sub_auth[1] != pwell_known_sid->sub_auth[1]))
262                         return false;
263 
264                 *puid = le32_to_cpu(psid->sub_auth[2]);
265         }
266 
267         cifs_dbg(FYI, "Unix UID %d returned from SID\n", *puid);
268         return true; /* well known sid found, uid returned */
269 }
270 
271 static void
272 cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
273 {
274         int i;
275 
276         dst->revision = src->revision;
277         dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
278         for (i = 0; i < NUM_AUTHS; ++i)
279                 dst->authority[i] = src->authority[i];
280         for (i = 0; i < dst->num_subauth; ++i)
281                 dst->sub_auth[i] = src->sub_auth[i];
282 }
283 
284 static int
285 id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
286 {
287         int rc;
288         struct key *sidkey;
289         struct cifs_sid *ksid;
290         unsigned int ksid_size;
291         char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
292         const struct cred *saved_cred;
293 
294         rc = snprintf(desc, sizeof(desc), "%ci:%u",
295                         sidtype == SIDOWNER ? 'o' : 'g', cid);
296         if (rc >= sizeof(desc))
297                 return -EINVAL;
298 
299         rc = 0;
300         saved_cred = override_creds(root_cred);
301         sidkey = request_key(&cifs_idmap_key_type, desc, "");
302         if (IS_ERR(sidkey)) {
303                 rc = -EINVAL;
304                 cifs_dbg(FYI, "%s: Can't map %cid %u to a SID\n",
305                          __func__, sidtype == SIDOWNER ? 'u' : 'g', cid);
306                 goto out_revert_creds;
307         } else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
308                 rc = -EIO;
309                 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
310                          __func__, sidkey->datalen);
311                 goto invalidate_key;
312         }
313 
314         /*
315          * A sid is usually too large to be embedded in payload.value, but if
316          * there are no subauthorities and the host has 8-byte pointers, then
317          * it could be.
318          */
319         ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
320                 (struct cifs_sid *)&sidkey->payload :
321                 (struct cifs_sid *)sidkey->payload.data[0];
322 
323         ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32));
324         if (ksid_size > sidkey->datalen) {
325                 rc = -EIO;
326                 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu, ksid_size=%u)\n",
327                          __func__, sidkey->datalen, ksid_size);
328                 goto invalidate_key;
329         }
330 
331         cifs_copy_sid(ssid, ksid);
332 out_key_put:
333         key_put(sidkey);
334 out_revert_creds:
335         revert_creds(saved_cred);
336         return rc;
337 
338 invalidate_key:
339         key_invalidate(sidkey);
340         goto out_key_put;
341 }
342 
343 static int
344 sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
345                 struct cifs_fattr *fattr, uint sidtype)
346 {
347         int rc;
348         struct key *sidkey;
349         char *sidstr;
350         const struct cred *saved_cred;
351         kuid_t fuid = cifs_sb->mnt_uid;
352         kgid_t fgid = cifs_sb->mnt_gid;
353 
354         /*
355          * If we have too many subauthorities, then something is really wrong.
356          * Just return an error.
357          */
358         if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
359                 cifs_dbg(FYI, "%s: %u subauthorities is too many!\n",
360                          __func__, psid->num_subauth);
361                 return -EIO;
362         }
363 
364         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL) {
365                 uint32_t unix_id;
366                 bool is_group;
367 
368                 if (sidtype != SIDOWNER)
369                         is_group = true;
370                 else
371                         is_group = false;
372 
373                 if (is_well_known_sid(psid, &unix_id, is_group) == false)
374                         goto try_upcall_to_get_id;
375 
376                 if (is_group) {
377                         kgid_t gid;
378                         gid_t id;
379 
380                         id = (gid_t)unix_id;
381                         gid = make_kgid(&init_user_ns, id);
382                         if (gid_valid(gid)) {
383                                 fgid = gid;
384                                 goto got_valid_id;
385                         }
386                 } else {
387                         kuid_t uid;
388                         uid_t id;
389 
390                         id = (uid_t)unix_id;
391                         uid = make_kuid(&init_user_ns, id);
392                         if (uid_valid(uid)) {
393                                 fuid = uid;
394                                 goto got_valid_id;
395                         }
396                 }
397                 /* If unable to find uid/gid easily from SID try via upcall */
398         }
399 
400 try_upcall_to_get_id:
401         sidstr = sid_to_key_str(psid, sidtype);
402         if (!sidstr)
403                 return -ENOMEM;
404 
405         saved_cred = override_creds(root_cred);
406         sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
407         if (IS_ERR(sidkey)) {
408                 rc = -EINVAL;
409                 cifs_dbg(FYI, "%s: Can't map SID %s to a %cid\n",
410                          __func__, sidstr, sidtype == SIDOWNER ? 'u' : 'g');
411                 goto out_revert_creds;
412         }
413 
414         /*
415          * FIXME: Here we assume that uid_t and gid_t are same size. It's
416          * probably a safe assumption but might be better to check based on
417          * sidtype.
418          */
419         BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t));
420         if (sidkey->datalen != sizeof(uid_t)) {
421                 rc = -EIO;
422                 cifs_dbg(FYI, "%s: Downcall contained malformed key (datalen=%hu)\n",
423                          __func__, sidkey->datalen);
424                 key_invalidate(sidkey);
425                 goto out_key_put;
426         }
427 
428         if (sidtype == SIDOWNER) {
429                 kuid_t uid;
430                 uid_t id;
431                 memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t));
432                 uid = make_kuid(&init_user_ns, id);
433                 if (uid_valid(uid))
434                         fuid = uid;
435         } else {
436                 kgid_t gid;
437                 gid_t id;
438                 memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t));
439                 gid = make_kgid(&init_user_ns, id);
440                 if (gid_valid(gid))
441                         fgid = gid;
442         }
443 
444 out_key_put:
445         key_put(sidkey);
446 out_revert_creds:
447         revert_creds(saved_cred);
448         kfree(sidstr);
449 
450         /*
451          * Note that we return 0 here unconditionally. If the mapping
452          * fails then we just fall back to using the mnt_uid/mnt_gid.
453          */
454 got_valid_id:
455         if (sidtype == SIDOWNER)
456                 fattr->cf_uid = fuid;
457         else
458                 fattr->cf_gid = fgid;
459         return 0;
460 }
461 
462 int
463 init_cifs_idmap(void)
464 {
465         struct cred *cred;
466         struct key *keyring;
467         int ret;
468 
469         cifs_dbg(FYI, "Registering the %s key type\n",
470                  cifs_idmap_key_type.name);
471 
472         /* create an override credential set with a special thread keyring in
473          * which requests are cached
474          *
475          * this is used to prevent malicious redirections from being installed
476          * with add_key().
477          */
478         cred = prepare_kernel_cred(NULL);
479         if (!cred)
480                 return -ENOMEM;
481 
482         keyring = keyring_alloc(".cifs_idmap",
483                                 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
484                                 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
485                                 KEY_USR_VIEW | KEY_USR_READ,
486                                 KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
487         if (IS_ERR(keyring)) {
488                 ret = PTR_ERR(keyring);
489                 goto failed_put_cred;
490         }
491 
492         ret = register_key_type(&cifs_idmap_key_type);
493         if (ret < 0)
494                 goto failed_put_key;
495 
496         /* instruct request_key() to use this special keyring as a cache for
497          * the results it looks up */
498         set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
499         cred->thread_keyring = keyring;
500         cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
501         root_cred = cred;
502 
503         cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring));
504         return 0;
505 
506 failed_put_key:
507         key_put(keyring);
508 failed_put_cred:
509         put_cred(cred);
510         return ret;
511 }
512 
513 void
514 exit_cifs_idmap(void)
515 {
516         key_revoke(root_cred->thread_keyring);
517         unregister_key_type(&cifs_idmap_key_type);
518         put_cred(root_cred);
519         cifs_dbg(FYI, "Unregistered %s key type\n", cifs_idmap_key_type.name);
520 }
521 
522 /* copy ntsd, owner sid, and group sid from a security descriptor to another */
523 static void copy_sec_desc(const struct cifs_ntsd *pntsd,
524                                 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
525 {
526         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
527         struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
528 
529         /* copy security descriptor control portion */
530         pnntsd->revision = pntsd->revision;
531         pnntsd->type = pntsd->type;
532         pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
533         pnntsd->sacloffset = 0;
534         pnntsd->osidoffset = cpu_to_le32(sidsoffset);
535         pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
536 
537         /* copy owner sid */
538         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
539                                 le32_to_cpu(pntsd->osidoffset));
540         nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
541         cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
542 
543         /* copy group sid */
544         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
545                                 le32_to_cpu(pntsd->gsidoffset));
546         ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
547                                         sizeof(struct cifs_sid));
548         cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
549 
550         return;
551 }
552 
553 
554 /*
555    change posix mode to reflect permissions
556    pmode is the existing mode (we only want to overwrite part of this
557    bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
558 */
559 static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
560                                  umode_t *pbits_to_set)
561 {
562         __u32 flags = le32_to_cpu(ace_flags);
563         /* the order of ACEs is important.  The canonical order is to begin with
564            DENY entries followed by ALLOW, otherwise an allow entry could be
565            encountered first, making the subsequent deny entry like "dead code"
566            which would be superflous since Windows stops when a match is made
567            for the operation you are trying to perform for your user */
568 
569         /* For deny ACEs we change the mask so that subsequent allow access
570            control entries do not turn on the bits we are denying */
571         if (type == ACCESS_DENIED) {
572                 if (flags & GENERIC_ALL)
573                         *pbits_to_set &= ~S_IRWXUGO;
574 
575                 if ((flags & GENERIC_WRITE) ||
576                         ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
577                         *pbits_to_set &= ~S_IWUGO;
578                 if ((flags & GENERIC_READ) ||
579                         ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
580                         *pbits_to_set &= ~S_IRUGO;
581                 if ((flags & GENERIC_EXECUTE) ||
582                         ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
583                         *pbits_to_set &= ~S_IXUGO;
584                 return;
585         } else if (type != ACCESS_ALLOWED) {
586                 cifs_dbg(VFS, "unknown access control type %d\n", type);
587                 return;
588         }
589         /* else ACCESS_ALLOWED type */
590 
591         if (flags & GENERIC_ALL) {
592                 *pmode |= (S_IRWXUGO & (*pbits_to_set));
593                 cifs_dbg(NOISY, "all perms\n");
594                 return;
595         }
596         if ((flags & GENERIC_WRITE) ||
597                         ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
598                 *pmode |= (S_IWUGO & (*pbits_to_set));
599         if ((flags & GENERIC_READ) ||
600                         ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
601                 *pmode |= (S_IRUGO & (*pbits_to_set));
602         if ((flags & GENERIC_EXECUTE) ||
603                         ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
604                 *pmode |= (S_IXUGO & (*pbits_to_set));
605 
606         cifs_dbg(NOISY, "access flags 0x%x mode now 0x%x\n", flags, *pmode);
607         return;
608 }
609 
610 /*
611    Generate access flags to reflect permissions mode is the existing mode.
612    This function is called for every ACE in the DACL whose SID matches
613    with either owner or group or everyone.
614 */
615 
616 static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
617                                 __u32 *pace_flags)
618 {
619         /* reset access mask */
620         *pace_flags = 0x0;
621 
622         /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
623         mode &= bits_to_use;
624 
625         /* check for R/W/X UGO since we do not know whose flags
626            is this but we have cleared all the bits sans RWX for
627            either user or group or other as per bits_to_use */
628         if (mode & S_IRUGO)
629                 *pace_flags |= SET_FILE_READ_RIGHTS;
630         if (mode & S_IWUGO)
631                 *pace_flags |= SET_FILE_WRITE_RIGHTS;
632         if (mode & S_IXUGO)
633                 *pace_flags |= SET_FILE_EXEC_RIGHTS;
634 
635         cifs_dbg(NOISY, "mode: 0x%x, access flags now 0x%x\n",
636                  mode, *pace_flags);
637         return;
638 }
639 
640 static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
641                         const struct cifs_sid *psid, __u64 nmode, umode_t bits)
642 {
643         int i;
644         __u16 size = 0;
645         __u32 access_req = 0;
646 
647         pntace->type = ACCESS_ALLOWED;
648         pntace->flags = 0x0;
649         mode_to_access_flags(nmode, bits, &access_req);
650         if (!access_req)
651                 access_req = SET_MINIMUM_RIGHTS;
652         pntace->access_req = cpu_to_le32(access_req);
653 
654         pntace->sid.revision = psid->revision;
655         pntace->sid.num_subauth = psid->num_subauth;
656         for (i = 0; i < NUM_AUTHS; i++)
657                 pntace->sid.authority[i] = psid->authority[i];
658         for (i = 0; i < psid->num_subauth; i++)
659                 pntace->sid.sub_auth[i] = psid->sub_auth[i];
660 
661         size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
662         pntace->size = cpu_to_le16(size);
663 
664         return size;
665 }
666 
667 
668 #ifdef CONFIG_CIFS_DEBUG2
669 static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
670 {
671         int num_subauth;
672 
673         /* validate that we do not go past end of acl */
674 
675         if (le16_to_cpu(pace->size) < 16) {
676                 cifs_dbg(VFS, "ACE too small %d\n", le16_to_cpu(pace->size));
677                 return;
678         }
679 
680         if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
681                 cifs_dbg(VFS, "ACL too small to parse ACE\n");
682                 return;
683         }
684 
685         num_subauth = pace->sid.num_subauth;
686         if (num_subauth) {
687                 int i;
688                 cifs_dbg(FYI, "ACE revision %d num_auth %d type %d flags %d size %d\n",
689                          pace->sid.revision, pace->sid.num_subauth, pace->type,
690                          pace->flags, le16_to_cpu(pace->size));
691                 for (i = 0; i < num_subauth; ++i) {
692                         cifs_dbg(FYI, "ACE sub_auth[%d]: 0x%x\n",
693                                  i, le32_to_cpu(pace->sid.sub_auth[i]));
694                 }
695 
696                 /* BB add length check to make sure that we do not have huge
697                         num auths and therefore go off the end */
698         }
699 
700         return;
701 }
702 #endif
703 
704 
705 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
706                        struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
707                        struct cifs_fattr *fattr)
708 {
709         int i;
710         int num_aces = 0;
711         int acl_size;
712         char *acl_base;
713         struct cifs_ace **ppace;
714 
715         /* BB need to add parm so we can store the SID BB */
716 
717         if (!pdacl) {
718                 /* no DACL in the security descriptor, set
719                    all the permissions for user/group/other */
720                 fattr->cf_mode |= S_IRWXUGO;
721                 return;
722         }
723 
724         /* validate that we do not go past end of acl */
725         if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
726                 cifs_dbg(VFS, "ACL too small to parse DACL\n");
727                 return;
728         }
729 
730         cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n",
731                  le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
732                  le32_to_cpu(pdacl->num_aces));
733 
734         /* reset rwx permissions for user/group/other.
735            Also, if num_aces is 0 i.e. DACL has no ACEs,
736            user/group/other have no permissions */
737         fattr->cf_mode &= ~(S_IRWXUGO);
738 
739         acl_base = (char *)pdacl;
740         acl_size = sizeof(struct cifs_acl);
741 
742         num_aces = le32_to_cpu(pdacl->num_aces);
743         if (num_aces > 0) {
744                 umode_t user_mask = S_IRWXU;
745                 umode_t group_mask = S_IRWXG;
746                 umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
747 
748                 if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
749                         return;
750                 ppace = kmalloc_array(num_aces, sizeof(struct cifs_ace *),
751                                       GFP_KERNEL);
752                 if (!ppace)
753                         return;
754 
755                 for (i = 0; i < num_aces; ++i) {
756                         ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
757 #ifdef CONFIG_CIFS_DEBUG2
758                         dump_ace(ppace[i], end_of_acl);
759 #endif
760                         if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
761                                 access_flags_to_mode(ppace[i]->access_req,
762                                                      ppace[i]->type,
763                                                      &fattr->cf_mode,
764                                                      &user_mask);
765                         if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
766                                 access_flags_to_mode(ppace[i]->access_req,
767                                                      ppace[i]->type,
768                                                      &fattr->cf_mode,
769                                                      &group_mask);
770                         if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
771                                 access_flags_to_mode(ppace[i]->access_req,
772                                                      ppace[i]->type,
773                                                      &fattr->cf_mode,
774                                                      &other_mask);
775                         if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
776                                 access_flags_to_mode(ppace[i]->access_req,
777                                                      ppace[i]->type,
778                                                      &fattr->cf_mode,
779                                                      &other_mask);
780 
781 
782 /*                      memcpy((void *)(&(cifscred->aces[i])),
783                                 (void *)ppace[i],
784                                 sizeof(struct cifs_ace)); */
785 
786                         acl_base = (char *)ppace[i];
787                         acl_size = le16_to_cpu(ppace[i]->size);
788                 }
789 
790                 kfree(ppace);
791         }
792 
793         return;
794 }
795 
796 
797 static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
798                         struct cifs_sid *pgrpsid, __u64 nmode)
799 {
800         u16 size = 0;
801         struct cifs_acl *pnndacl;
802 
803         pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
804 
805         size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
806                                         pownersid, nmode, S_IRWXU);
807         size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
808                                         pgrpsid, nmode, S_IRWXG);
809         size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
810                                          &sid_everyone, nmode, S_IRWXO);
811 
812         pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
813         pndacl->num_aces = cpu_to_le32(3);
814 
815         return 0;
816 }
817 
818 
819 static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
820 {
821         /* BB need to add parm so we can store the SID BB */
822 
823         /* validate that we do not go past end of ACL - sid must be at least 8
824            bytes long (assuming no sub-auths - e.g. the null SID */
825         if (end_of_acl < (char *)psid + 8) {
826                 cifs_dbg(VFS, "ACL too small to parse SID %p\n", psid);
827                 return -EINVAL;
828         }
829 
830 #ifdef CONFIG_CIFS_DEBUG2
831         if (psid->num_subauth) {
832                 int i;
833                 cifs_dbg(FYI, "SID revision %d num_auth %d\n",
834                          psid->revision, psid->num_subauth);
835 
836                 for (i = 0; i < psid->num_subauth; i++) {
837                         cifs_dbg(FYI, "SID sub_auth[%d]: 0x%x\n",
838                                  i, le32_to_cpu(psid->sub_auth[i]));
839                 }
840 
841                 /* BB add length check to make sure that we do not have huge
842                         num auths and therefore go off the end */
843                 cifs_dbg(FYI, "RID 0x%x\n",
844                          le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
845         }
846 #endif
847 
848         return 0;
849 }
850 
851 
852 /* Convert CIFS ACL to POSIX form */
853 static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
854                 struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
855 {
856         int rc = 0;
857         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
858         struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
859         char *end_of_acl = ((char *)pntsd) + acl_len;
860         __u32 dacloffset;
861 
862         if (pntsd == NULL)
863                 return -EIO;
864 
865         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
866                                 le32_to_cpu(pntsd->osidoffset));
867         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
868                                 le32_to_cpu(pntsd->gsidoffset));
869         dacloffset = le32_to_cpu(pntsd->dacloffset);
870         dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
871         cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
872                  pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
873                  le32_to_cpu(pntsd->gsidoffset),
874                  le32_to_cpu(pntsd->sacloffset), dacloffset);
875 /*      cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
876         rc = parse_sid(owner_sid_ptr, end_of_acl);
877         if (rc) {
878                 cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
879                 return rc;
880         }
881         rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
882         if (rc) {
883                 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
884                          __func__, rc);
885                 return rc;
886         }
887 
888         rc = parse_sid(group_sid_ptr, end_of_acl);
889         if (rc) {
890                 cifs_dbg(FYI, "%s: Error %d mapping Owner SID to gid\n",
891                          __func__, rc);
892                 return rc;
893         }
894         rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
895         if (rc) {
896                 cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
897                          __func__, rc);
898                 return rc;
899         }
900 
901         if (dacloffset)
902                 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
903                            group_sid_ptr, fattr);
904         else
905                 cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */
906 
907         return rc;
908 }
909 
910 /* Convert permission bits from mode to equivalent CIFS ACL */
911 static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
912         __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag)
913 {
914         int rc = 0;
915         __u32 dacloffset;
916         __u32 ndacloffset;
917         __u32 sidsoffset;
918         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
919         struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
920         struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
921         struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
922 
923         if (nmode != NO_CHANGE_64) { /* chmod */
924                 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
925                                 le32_to_cpu(pntsd->osidoffset));
926                 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
927                                 le32_to_cpu(pntsd->gsidoffset));
928                 dacloffset = le32_to_cpu(pntsd->dacloffset);
929                 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
930                 ndacloffset = sizeof(struct cifs_ntsd);
931                 ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
932                 ndacl_ptr->revision = dacl_ptr->revision;
933                 ndacl_ptr->size = 0;
934                 ndacl_ptr->num_aces = 0;
935 
936                 rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
937                                         nmode);
938                 sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
939                 /* copy sec desc control portion & owner and group sids */
940                 copy_sec_desc(pntsd, pnntsd, sidsoffset);
941                 *aclflag = CIFS_ACL_DACL;
942         } else {
943                 memcpy(pnntsd, pntsd, secdesclen);
944                 if (uid_valid(uid)) { /* chown */
945                         uid_t id;
946                         owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
947                                         le32_to_cpu(pnntsd->osidoffset));
948                         nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
949                                                                 GFP_KERNEL);
950                         if (!nowner_sid_ptr)
951                                 return -ENOMEM;
952                         id = from_kuid(&init_user_ns, uid);
953                         rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr);
954                         if (rc) {
955                                 cifs_dbg(FYI, "%s: Mapping error %d for owner id %d\n",
956                                          __func__, rc, id);
957                                 kfree(nowner_sid_ptr);
958                                 return rc;
959                         }
960                         cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
961                         kfree(nowner_sid_ptr);
962                         *aclflag = CIFS_ACL_OWNER;
963                 }
964                 if (gid_valid(gid)) { /* chgrp */
965                         gid_t id;
966                         group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
967                                         le32_to_cpu(pnntsd->gsidoffset));
968                         ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
969                                                                 GFP_KERNEL);
970                         if (!ngroup_sid_ptr)
971                                 return -ENOMEM;
972                         id = from_kgid(&init_user_ns, gid);
973                         rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr);
974                         if (rc) {
975                                 cifs_dbg(FYI, "%s: Mapping error %d for group id %d\n",
976                                          __func__, rc, id);
977                                 kfree(ngroup_sid_ptr);
978                                 return rc;
979                         }
980                         cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
981                         kfree(ngroup_sid_ptr);
982                         *aclflag = CIFS_ACL_GROUP;
983                 }
984         }
985 
986         return rc;
987 }
988 
989 struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
990                 const struct cifs_fid *cifsfid, u32 *pacllen)
991 {
992         struct cifs_ntsd *pntsd = NULL;
993         unsigned int xid;
994         int rc;
995         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
996 
997         if (IS_ERR(tlink))
998                 return ERR_CAST(tlink);
999 
1000         xid = get_xid();
1001         rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
1002                                 pacllen);
1003         free_xid(xid);
1004 
1005         cifs_put_tlink(tlink);
1006 
1007         cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
1008         if (rc)
1009                 return ERR_PTR(rc);
1010         return pntsd;
1011 }
1012 
1013 static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
1014                 const char *path, u32 *pacllen)
1015 {
1016         struct cifs_ntsd *pntsd = NULL;
1017         int oplock = 0;
1018         unsigned int xid;
1019         int rc, create_options = 0;
1020         struct cifs_tcon *tcon;
1021         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1022         struct cifs_fid fid;
1023         struct cifs_open_parms oparms;
1024 
1025         if (IS_ERR(tlink))
1026                 return ERR_CAST(tlink);
1027 
1028         tcon = tlink_tcon(tlink);
1029         xid = get_xid();
1030 
1031         if (backup_cred(cifs_sb))
1032                 create_options |= CREATE_OPEN_BACKUP_INTENT;
1033 
1034         oparms.tcon = tcon;
1035         oparms.cifs_sb = cifs_sb;
1036         oparms.desired_access = READ_CONTROL;
1037         oparms.create_options = create_options;
1038         oparms.disposition = FILE_OPEN;
1039         oparms.path = path;
1040         oparms.fid = &fid;
1041         oparms.reconnect = false;
1042 
1043         rc = CIFS_open(xid, &oparms, &oplock, NULL);
1044         if (!rc) {
1045                 rc = CIFSSMBGetCIFSACL(xid, tcon, fid.netfid, &pntsd, pacllen);
1046                 CIFSSMBClose(xid, tcon, fid.netfid);
1047         }
1048 
1049         cifs_put_tlink(tlink);
1050         free_xid(xid);
1051 
1052         cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
1053         if (rc)
1054                 return ERR_PTR(rc);
1055         return pntsd;
1056 }
1057 
1058 /* Retrieve an ACL from the server */
1059 struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
1060                                       struct inode *inode, const char *path,
1061                                       u32 *pacllen)
1062 {
1063         struct cifs_ntsd *pntsd = NULL;
1064         struct cifsFileInfo *open_file = NULL;
1065 
1066         if (inode)
1067                 open_file = find_readable_file(CIFS_I(inode), true);
1068         if (!open_file)
1069                 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
1070 
1071         pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
1072         cifsFileInfo_put(open_file);
1073         return pntsd;
1074 }
1075 
1076  /* Set an ACL on the server */
1077 int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
1078                         struct inode *inode, const char *path, int aclflag)
1079 {
1080         int oplock = 0;
1081         unsigned int xid;
1082         int rc, access_flags, create_options = 0;
1083         struct cifs_tcon *tcon;
1084         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1085         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1086         struct cifs_fid fid;
1087         struct cifs_open_parms oparms;
1088 
1089         if (IS_ERR(tlink))
1090                 return PTR_ERR(tlink);
1091 
1092         tcon = tlink_tcon(tlink);
1093         xid = get_xid();
1094 
1095         if (backup_cred(cifs_sb))
1096                 create_options |= CREATE_OPEN_BACKUP_INTENT;
1097 
1098         if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
1099                 access_flags = WRITE_OWNER;
1100         else
1101                 access_flags = WRITE_DAC;
1102 
1103         oparms.tcon = tcon;
1104         oparms.cifs_sb = cifs_sb;
1105         oparms.desired_access = access_flags;
1106         oparms.create_options = create_options;
1107         oparms.disposition = FILE_OPEN;
1108         oparms.path = path;
1109         oparms.fid = &fid;
1110         oparms.reconnect = false;
1111 
1112         rc = CIFS_open(xid, &oparms, &oplock, NULL);
1113         if (rc) {
1114                 cifs_dbg(VFS, "Unable to open file to set ACL\n");
1115                 goto out;
1116         }
1117 
1118         rc = CIFSSMBSetCIFSACL(xid, tcon, fid.netfid, pnntsd, acllen, aclflag);
1119         cifs_dbg(NOISY, "SetCIFSACL rc = %d\n", rc);
1120 
1121         CIFSSMBClose(xid, tcon, fid.netfid);
1122 out:
1123         free_xid(xid);
1124         cifs_put_tlink(tlink);
1125         return rc;
1126 }
1127 
1128 /* Translate the CIFS ACL (similar to NTFS ACL) for a file into mode bits */
1129 int
1130 cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
1131                   struct inode *inode, const char *path,
1132                   const struct cifs_fid *pfid)
1133 {
1134         struct cifs_ntsd *pntsd = NULL;
1135         u32 acllen = 0;
1136         int rc = 0;
1137         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1138         struct smb_version_operations *ops;
1139 
1140         cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);
1141 
1142         if (IS_ERR(tlink))
1143                 return PTR_ERR(tlink);
1144 
1145         ops = tlink_tcon(tlink)->ses->server->ops;
1146 
1147         if (pfid && (ops->get_acl_by_fid))
1148                 pntsd = ops->get_acl_by_fid(cifs_sb, pfid, &acllen);
1149         else if (ops->get_acl)
1150                 pntsd = ops->get_acl(cifs_sb, inode, path, &acllen);
1151         else {
1152                 cifs_put_tlink(tlink);
1153                 return -EOPNOTSUPP;
1154         }
1155         /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
1156         if (IS_ERR(pntsd)) {
1157                 rc = PTR_ERR(pntsd);
1158                 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
1159         } else {
1160                 rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
1161                 kfree(pntsd);
1162                 if (rc)
1163                         cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
1164         }
1165 
1166         cifs_put_tlink(tlink);
1167 
1168         return rc;
1169 }
1170 
1171 /* Convert mode bits to an ACL so we can update the ACL on the server */
1172 int
1173 id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
1174                         kuid_t uid, kgid_t gid)
1175 {
1176         int rc = 0;
1177         int aclflag = CIFS_ACL_DACL; /* default flag to set */
1178         __u32 secdesclen = 0;
1179         struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
1180         struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
1181         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
1182         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
1183         struct smb_version_operations *ops;
1184 
1185         if (IS_ERR(tlink))
1186                 return PTR_ERR(tlink);
1187 
1188         ops = tlink_tcon(tlink)->ses->server->ops;
1189 
1190         cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
1191 
1192         /* Get the security descriptor */
1193 
1194         if (ops->get_acl == NULL) {
1195                 cifs_put_tlink(tlink);
1196                 return -EOPNOTSUPP;
1197         }
1198 
1199         pntsd = ops->get_acl(cifs_sb, inode, path, &secdesclen);
1200         if (IS_ERR(pntsd)) {
1201                 rc = PTR_ERR(pntsd);
1202                 cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
1203                 cifs_put_tlink(tlink);
1204                 return rc;
1205         }
1206 
1207         /*
1208          * Add three ACEs for owner, group, everyone getting rid of other ACEs
1209          * as chmod disables ACEs and set the security descriptor. Allocate
1210          * memory for the smb header, set security descriptor request security
1211          * descriptor parameters, and secuirty descriptor itself
1212          */
1213         secdesclen = max_t(u32, secdesclen, DEFAULT_SEC_DESC_LEN);
1214         pnntsd = kmalloc(secdesclen, GFP_KERNEL);
1215         if (!pnntsd) {
1216                 kfree(pntsd);
1217                 cifs_put_tlink(tlink);
1218                 return -ENOMEM;
1219         }
1220 
1221         rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
1222                                 &aclflag);
1223 
1224         cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
1225 
1226         if (ops->set_acl == NULL)
1227                 rc = -EOPNOTSUPP;
1228 
1229         if (!rc) {
1230                 /* Set the security descriptor */
1231                 rc = ops->set_acl(pnntsd, secdesclen, inode, path, aclflag);
1232                 cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
1233         }
1234         cifs_put_tlink(tlink);
1235 
1236         kfree(pnntsd);
1237         kfree(pntsd);
1238         return rc;
1239 }
1240 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp