a437ec391a015fb7c05725543d6c118eadefc466
[pandora-kernel.git] / fs / cifs / cifsacl.c
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 "cifspdu.h"
27 #include "cifsglob.h"
28 #include "cifsacl.h"
29 #include "cifsproto.h"
30 #include "cifs_debug.h"
31
32
33 static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
34         {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
35         {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
36         {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
37         {{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
38         {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
39         {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
40         {{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
41 ;
42
43
44 /* security id for everyone */
45 static const struct cifs_sid sid_everyone = {
46         1, 1, {0, 0, 0, 0, 0, 1}, {0} };
47 /* group users */
48 static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
49
50
51 int match_sid(struct cifs_sid *ctsid)
52 {
53         int i, j;
54         int num_subauth, num_sat, num_saw;
55         struct cifs_sid *cwsid;
56
57         if (!ctsid)
58                 return -1;
59
60         for (i = 0; i < NUM_WK_SIDS; ++i) {
61                 cwsid = &(wksidarr[i].cifssid);
62
63                 /* compare the revision */
64                 if (ctsid->revision != cwsid->revision)
65                         continue;
66
67                 /* compare all of the six auth values */
68                 for (j = 0; j < 6; ++j) {
69                         if (ctsid->authority[j] != cwsid->authority[j])
70                                 break;
71                 }
72                 if (j < 6)
73                         continue; /* all of the auth values did not match */
74
75                 /* compare all of the subauth values if any */
76                 num_sat = ctsid->num_subauth;
77                 num_saw = cwsid->num_subauth;
78                 num_subauth = num_sat < num_saw ? num_sat : num_saw;
79                 if (num_subauth) {
80                         for (j = 0; j < num_subauth; ++j) {
81                                 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
82                                         break;
83                         }
84                         if (j < num_subauth)
85                                 continue; /* all sub_auth values do not match */
86                 }
87
88                 cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
89                 return 0; /* sids compare/match */
90         }
91
92         cFYI(1, "No matching sid");
93         return -1;
94 }
95
96 /* if the two SIDs (roughly equivalent to a UUID for a user or group) are
97    the same returns 1, if they do not match returns 0 */
98 int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
99 {
100         int i;
101         int num_subauth, num_sat, num_saw;
102
103         if ((!ctsid) || (!cwsid))
104                 return 0;
105
106         /* compare the revision */
107         if (ctsid->revision != cwsid->revision)
108                 return 0;
109
110         /* compare all of the six auth values */
111         for (i = 0; i < 6; ++i) {
112                 if (ctsid->authority[i] != cwsid->authority[i])
113                         return 0;
114         }
115
116         /* compare all of the subauth values if any */
117         num_sat = ctsid->num_subauth;
118         num_saw = cwsid->num_subauth;
119         num_subauth = num_sat < num_saw ? num_sat : num_saw;
120         if (num_subauth) {
121                 for (i = 0; i < num_subauth; ++i) {
122                         if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
123                                 return 0;
124                 }
125         }
126
127         return 1; /* sids compare/match */
128 }
129
130
131 /* copy ntsd, owner sid, and group sid from a security descriptor to another */
132 static void copy_sec_desc(const struct cifs_ntsd *pntsd,
133                                 struct cifs_ntsd *pnntsd, __u32 sidsoffset)
134 {
135         int i;
136
137         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
138         struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
139
140         /* copy security descriptor control portion */
141         pnntsd->revision = pntsd->revision;
142         pnntsd->type = pntsd->type;
143         pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
144         pnntsd->sacloffset = 0;
145         pnntsd->osidoffset = cpu_to_le32(sidsoffset);
146         pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
147
148         /* copy owner sid */
149         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
150                                 le32_to_cpu(pntsd->osidoffset));
151         nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
152
153         nowner_sid_ptr->revision = owner_sid_ptr->revision;
154         nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
155         for (i = 0; i < 6; i++)
156                 nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
157         for (i = 0; i < 5; i++)
158                 nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
159
160         /* copy group sid */
161         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
162                                 le32_to_cpu(pntsd->gsidoffset));
163         ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
164                                         sizeof(struct cifs_sid));
165
166         ngroup_sid_ptr->revision = group_sid_ptr->revision;
167         ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
168         for (i = 0; i < 6; i++)
169                 ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
170         for (i = 0; i < 5; i++)
171                 ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
172
173         return;
174 }
175
176
177 /*
178    change posix mode to reflect permissions
179    pmode is the existing mode (we only want to overwrite part of this
180    bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
181 */
182 static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
183                                  umode_t *pbits_to_set)
184 {
185         __u32 flags = le32_to_cpu(ace_flags);
186         /* the order of ACEs is important.  The canonical order is to begin with
187            DENY entries followed by ALLOW, otherwise an allow entry could be
188            encountered first, making the subsequent deny entry like "dead code"
189            which would be superflous since Windows stops when a match is made
190            for the operation you are trying to perform for your user */
191
192         /* For deny ACEs we change the mask so that subsequent allow access
193            control entries do not turn on the bits we are denying */
194         if (type == ACCESS_DENIED) {
195                 if (flags & GENERIC_ALL)
196                         *pbits_to_set &= ~S_IRWXUGO;
197
198                 if ((flags & GENERIC_WRITE) ||
199                         ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
200                         *pbits_to_set &= ~S_IWUGO;
201                 if ((flags & GENERIC_READ) ||
202                         ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
203                         *pbits_to_set &= ~S_IRUGO;
204                 if ((flags & GENERIC_EXECUTE) ||
205                         ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
206                         *pbits_to_set &= ~S_IXUGO;
207                 return;
208         } else if (type != ACCESS_ALLOWED) {
209                 cERROR(1, "unknown access control type %d", type);
210                 return;
211         }
212         /* else ACCESS_ALLOWED type */
213
214         if (flags & GENERIC_ALL) {
215                 *pmode |= (S_IRWXUGO & (*pbits_to_set));
216                 cFYI(DBG2, "all perms");
217                 return;
218         }
219         if ((flags & GENERIC_WRITE) ||
220                         ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
221                 *pmode |= (S_IWUGO & (*pbits_to_set));
222         if ((flags & GENERIC_READ) ||
223                         ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
224                 *pmode |= (S_IRUGO & (*pbits_to_set));
225         if ((flags & GENERIC_EXECUTE) ||
226                         ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
227                 *pmode |= (S_IXUGO & (*pbits_to_set));
228
229         cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
230         return;
231 }
232
233 /*
234    Generate access flags to reflect permissions mode is the existing mode.
235    This function is called for every ACE in the DACL whose SID matches
236    with either owner or group or everyone.
237 */
238
239 static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
240                                 __u32 *pace_flags)
241 {
242         /* reset access mask */
243         *pace_flags = 0x0;
244
245         /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
246         mode &= bits_to_use;
247
248         /* check for R/W/X UGO since we do not know whose flags
249            is this but we have cleared all the bits sans RWX for
250            either user or group or other as per bits_to_use */
251         if (mode & S_IRUGO)
252                 *pace_flags |= SET_FILE_READ_RIGHTS;
253         if (mode & S_IWUGO)
254                 *pace_flags |= SET_FILE_WRITE_RIGHTS;
255         if (mode & S_IXUGO)
256                 *pace_flags |= SET_FILE_EXEC_RIGHTS;
257
258         cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
259         return;
260 }
261
262 static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
263                         const struct cifs_sid *psid, __u64 nmode, umode_t bits)
264 {
265         int i;
266         __u16 size = 0;
267         __u32 access_req = 0;
268
269         pntace->type = ACCESS_ALLOWED;
270         pntace->flags = 0x0;
271         mode_to_access_flags(nmode, bits, &access_req);
272         if (!access_req)
273                 access_req = SET_MINIMUM_RIGHTS;
274         pntace->access_req = cpu_to_le32(access_req);
275
276         pntace->sid.revision = psid->revision;
277         pntace->sid.num_subauth = psid->num_subauth;
278         for (i = 0; i < 6; i++)
279                 pntace->sid.authority[i] = psid->authority[i];
280         for (i = 0; i < psid->num_subauth; i++)
281                 pntace->sid.sub_auth[i] = psid->sub_auth[i];
282
283         size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
284         pntace->size = cpu_to_le16(size);
285
286         return size;
287 }
288
289
290 #ifdef CONFIG_CIFS_DEBUG2
291 static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
292 {
293         int num_subauth;
294
295         /* validate that we do not go past end of acl */
296
297         if (le16_to_cpu(pace->size) < 16) {
298                 cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
299                 return;
300         }
301
302         if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
303                 cERROR(1, "ACL too small to parse ACE");
304                 return;
305         }
306
307         num_subauth = pace->sid.num_subauth;
308         if (num_subauth) {
309                 int i;
310                 cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
311                         pace->sid.revision, pace->sid.num_subauth, pace->type,
312                         pace->flags, le16_to_cpu(pace->size));
313                 for (i = 0; i < num_subauth; ++i) {
314                         cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
315                                 le32_to_cpu(pace->sid.sub_auth[i]));
316                 }
317
318                 /* BB add length check to make sure that we do not have huge
319                         num auths and therefore go off the end */
320         }
321
322         return;
323 }
324 #endif
325
326
327 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
328                        struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
329                        struct cifs_fattr *fattr)
330 {
331         int i;
332         int num_aces = 0;
333         int acl_size;
334         char *acl_base;
335         struct cifs_ace **ppace;
336
337         /* BB need to add parm so we can store the SID BB */
338
339         if (!pdacl) {
340                 /* no DACL in the security descriptor, set
341                    all the permissions for user/group/other */
342                 fattr->cf_mode |= S_IRWXUGO;
343                 return;
344         }
345
346         /* validate that we do not go past end of acl */
347         if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
348                 cERROR(1, "ACL too small to parse DACL");
349                 return;
350         }
351
352         cFYI(DBG2, "DACL revision %d size %d num aces %d",
353                 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
354                 le32_to_cpu(pdacl->num_aces));
355
356         /* reset rwx permissions for user/group/other.
357            Also, if num_aces is 0 i.e. DACL has no ACEs,
358            user/group/other have no permissions */
359         fattr->cf_mode &= ~(S_IRWXUGO);
360
361         acl_base = (char *)pdacl;
362         acl_size = sizeof(struct cifs_acl);
363
364         num_aces = le32_to_cpu(pdacl->num_aces);
365         if (num_aces  > 0) {
366                 umode_t user_mask = S_IRWXU;
367                 umode_t group_mask = S_IRWXG;
368                 umode_t other_mask = S_IRWXO;
369
370                 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
371                                 GFP_KERNEL);
372
373                 for (i = 0; i < num_aces; ++i) {
374                         ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
375 #ifdef CONFIG_CIFS_DEBUG2
376                         dump_ace(ppace[i], end_of_acl);
377 #endif
378                         if (compare_sids(&(ppace[i]->sid), pownersid))
379                                 access_flags_to_mode(ppace[i]->access_req,
380                                                      ppace[i]->type,
381                                                      &fattr->cf_mode,
382                                                      &user_mask);
383                         if (compare_sids(&(ppace[i]->sid), pgrpsid))
384                                 access_flags_to_mode(ppace[i]->access_req,
385                                                      ppace[i]->type,
386                                                      &fattr->cf_mode,
387                                                      &group_mask);
388                         if (compare_sids(&(ppace[i]->sid), &sid_everyone))
389                                 access_flags_to_mode(ppace[i]->access_req,
390                                                      ppace[i]->type,
391                                                      &fattr->cf_mode,
392                                                      &other_mask);
393
394 /*                      memcpy((void *)(&(cifscred->aces[i])),
395                                 (void *)ppace[i],
396                                 sizeof(struct cifs_ace)); */
397
398                         acl_base = (char *)ppace[i];
399                         acl_size = le16_to_cpu(ppace[i]->size);
400                 }
401
402                 kfree(ppace);
403         }
404
405         return;
406 }
407
408
409 static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
410                         struct cifs_sid *pgrpsid, __u64 nmode)
411 {
412         u16 size = 0;
413         struct cifs_acl *pnndacl;
414
415         pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
416
417         size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
418                                         pownersid, nmode, S_IRWXU);
419         size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
420                                         pgrpsid, nmode, S_IRWXG);
421         size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
422                                          &sid_everyone, nmode, S_IRWXO);
423
424         pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
425         pndacl->num_aces = cpu_to_le32(3);
426
427         return 0;
428 }
429
430
431 static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
432 {
433         /* BB need to add parm so we can store the SID BB */
434
435         /* validate that we do not go past end of ACL - sid must be at least 8
436            bytes long (assuming no sub-auths - e.g. the null SID */
437         if (end_of_acl < (char *)psid + 8) {
438                 cERROR(1, "ACL too small to parse SID %p", psid);
439                 return -EINVAL;
440         }
441
442         if (psid->num_subauth) {
443 #ifdef CONFIG_CIFS_DEBUG2
444                 int i;
445                 cFYI(1, "SID revision %d num_auth %d",
446                         psid->revision, psid->num_subauth);
447
448                 for (i = 0; i < psid->num_subauth; i++) {
449                         cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
450                                 le32_to_cpu(psid->sub_auth[i]));
451                 }
452
453                 /* BB add length check to make sure that we do not have huge
454                         num auths and therefore go off the end */
455                 cFYI(1, "RID 0x%x",
456                         le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
457 #endif
458         }
459
460         return 0;
461 }
462
463
464 /* Convert CIFS ACL to POSIX form */
465 static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
466                           struct cifs_fattr *fattr)
467 {
468         int rc;
469         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
470         struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
471         char *end_of_acl = ((char *)pntsd) + acl_len;
472         __u32 dacloffset;
473
474         if (pntsd == NULL)
475                 return -EIO;
476
477         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
478                                 le32_to_cpu(pntsd->osidoffset));
479         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
480                                 le32_to_cpu(pntsd->gsidoffset));
481         dacloffset = le32_to_cpu(pntsd->dacloffset);
482         dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
483         cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
484                  "sacloffset 0x%x dacloffset 0x%x",
485                  pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
486                  le32_to_cpu(pntsd->gsidoffset),
487                  le32_to_cpu(pntsd->sacloffset), dacloffset);
488 /*      cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
489         rc = parse_sid(owner_sid_ptr, end_of_acl);
490         if (rc)
491                 return rc;
492
493         rc = parse_sid(group_sid_ptr, end_of_acl);
494         if (rc)
495                 return rc;
496
497         if (dacloffset)
498                 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
499                            group_sid_ptr, fattr);
500         else
501                 cFYI(1, "no ACL"); /* BB grant all or default perms? */
502
503 /*      cifscred->uid = owner_sid_ptr->rid;
504         cifscred->gid = group_sid_ptr->rid;
505         memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
506                         sizeof(struct cifs_sid));
507         memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
508                         sizeof(struct cifs_sid)); */
509
510         return 0;
511 }
512
513
514 /* Convert permission bits from mode to equivalent CIFS ACL */
515 static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
516                                 struct inode *inode, __u64 nmode)
517 {
518         int rc = 0;
519         __u32 dacloffset;
520         __u32 ndacloffset;
521         __u32 sidsoffset;
522         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
523         struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
524         struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
525
526         if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
527                 return -EIO;
528
529         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
530                                 le32_to_cpu(pntsd->osidoffset));
531         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
532                                 le32_to_cpu(pntsd->gsidoffset));
533
534         dacloffset = le32_to_cpu(pntsd->dacloffset);
535         dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
536
537         ndacloffset = sizeof(struct cifs_ntsd);
538         ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
539         ndacl_ptr->revision = dacl_ptr->revision;
540         ndacl_ptr->size = 0;
541         ndacl_ptr->num_aces = 0;
542
543         rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
544
545         sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
546
547         /* copy security descriptor control portion and owner and group sid */
548         copy_sec_desc(pntsd, pnntsd, sidsoffset);
549
550         return rc;
551 }
552
553 static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
554                 __u16 fid, u32 *pacllen)
555 {
556         struct cifs_ntsd *pntsd = NULL;
557         int xid, rc;
558         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
559
560         if (IS_ERR(tlink))
561                 return ERR_CAST(tlink);
562
563         xid = GetXid();
564         rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
565         FreeXid(xid);
566
567         cifs_put_tlink(tlink);
568
569         cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
570         if (rc)
571                 return ERR_PTR(rc);
572         return pntsd;
573 }
574
575 static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
576                 const char *path, u32 *pacllen)
577 {
578         struct cifs_ntsd *pntsd = NULL;
579         int oplock = 0;
580         int xid, rc;
581         __u16 fid;
582         struct cifsTconInfo *tcon;
583         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
584
585         if (IS_ERR(tlink))
586                 return ERR_CAST(tlink);
587
588         tcon = tlink_tcon(tlink);
589         xid = GetXid();
590
591         rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
592                          &fid, &oplock, NULL, cifs_sb->local_nls,
593                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
594         if (!rc) {
595                 rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
596                 CIFSSMBClose(xid, tcon, fid);
597         }
598
599         cifs_put_tlink(tlink);
600         FreeXid(xid);
601
602         cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
603         if (rc)
604                 return ERR_PTR(rc);
605         return pntsd;
606 }
607
608 /* Retrieve an ACL from the server */
609 struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
610                                       struct inode *inode, const char *path,
611                                       u32 *pacllen)
612 {
613         struct cifs_ntsd *pntsd = NULL;
614         struct cifsFileInfo *open_file = NULL;
615
616         if (inode)
617                 open_file = find_readable_file(CIFS_I(inode), true);
618         if (!open_file)
619                 return get_cifs_acl_by_path(cifs_sb, path, pacllen);
620
621         pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
622         cifsFileInfo_put(open_file);
623         return pntsd;
624 }
625
626 static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
627                 struct cifs_ntsd *pnntsd, u32 acllen)
628 {
629         int xid, rc;
630         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
631
632         if (IS_ERR(tlink))
633                 return PTR_ERR(tlink);
634
635         xid = GetXid();
636         rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
637         FreeXid(xid);
638         cifs_put_tlink(tlink);
639
640         cFYI(DBG2, "SetCIFSACL rc = %d", rc);
641         return rc;
642 }
643
644 static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
645                 struct cifs_ntsd *pnntsd, u32 acllen)
646 {
647         int oplock = 0;
648         int xid, rc;
649         __u16 fid;
650         struct cifsTconInfo *tcon;
651         struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
652
653         if (IS_ERR(tlink))
654                 return PTR_ERR(tlink);
655
656         tcon = tlink_tcon(tlink);
657         xid = GetXid();
658
659         rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
660                          &fid, &oplock, NULL, cifs_sb->local_nls,
661                          cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
662         if (rc) {
663                 cERROR(1, "Unable to open file to set ACL");
664                 goto out;
665         }
666
667         rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
668         cFYI(DBG2, "SetCIFSACL rc = %d", rc);
669
670         CIFSSMBClose(xid, tcon, fid);
671 out:
672         FreeXid(xid);
673         cifs_put_tlink(tlink);
674         return rc;
675 }
676
677 /* Set an ACL on the server */
678 static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
679                                 struct inode *inode, const char *path)
680 {
681         struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
682         struct cifsFileInfo *open_file;
683         int rc;
684
685         cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
686
687         open_file = find_readable_file(CIFS_I(inode), true);
688         if (!open_file)
689                 return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
690
691         rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
692         cifsFileInfo_put(open_file);
693         return rc;
694 }
695
696 /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
697 int
698 cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
699                   struct inode *inode, const char *path, const __u16 *pfid)
700 {
701         struct cifs_ntsd *pntsd = NULL;
702         u32 acllen = 0;
703         int rc = 0;
704
705         cFYI(DBG2, "converting ACL to mode for %s", path);
706
707         if (pfid)
708                 pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
709         else
710                 pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
711
712         /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
713         if (IS_ERR(pntsd)) {
714                 rc = PTR_ERR(pntsd);
715                 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
716         } else {
717                 rc = parse_sec_desc(pntsd, acllen, fattr);
718                 kfree(pntsd);
719                 if (rc)
720                         cERROR(1, "parse sec desc failed rc = %d", rc);
721         }
722
723         return rc;
724 }
725
726 /* Convert mode bits to an ACL so we can update the ACL on the server */
727 int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
728 {
729         int rc = 0;
730         __u32 secdesclen = 0;
731         struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
732         struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
733
734         cFYI(DBG2, "set ACL from mode for %s", path);
735
736         /* Get the security descriptor */
737         pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
738
739         /* Add three ACEs for owner, group, everyone getting rid of
740            other ACEs as chmod disables ACEs and set the security descriptor */
741
742         if (IS_ERR(pntsd)) {
743                 rc = PTR_ERR(pntsd);
744                 cERROR(1, "%s: error %d getting sec desc", __func__, rc);
745         } else {
746                 /* allocate memory for the smb header,
747                    set security descriptor request security descriptor
748                    parameters, and secuirty descriptor itself */
749
750                 secdesclen = secdesclen < DEFSECDESCLEN ?
751                                         DEFSECDESCLEN : secdesclen;
752                 pnntsd = kmalloc(secdesclen, GFP_KERNEL);
753                 if (!pnntsd) {
754                         cERROR(1, "Unable to allocate security descriptor");
755                         kfree(pntsd);
756                         return -ENOMEM;
757                 }
758
759                 rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
760
761                 cFYI(DBG2, "build_sec_desc rc: %d", rc);
762
763                 if (!rc) {
764                         /* Set the security descriptor */
765                         rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
766                         cFYI(DBG2, "set_cifs_acl rc: %d", rc);
767                 }
768
769                 kfree(pnntsd);
770                 kfree(pntsd);
771         }
772
773         return rc;
774 }