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