[CIFS] acl support part 6
[powerpc.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, 0}, {} };
48 /* group users */
49 static const struct cifs_sid sid_user =
50                 {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
51
52
53 int match_sid(struct cifs_sid *ctsid)
54 {
55         int i, j;
56         int num_subauth, num_sat, num_saw;
57         struct cifs_sid *cwsid;
58
59         if (!ctsid)
60                 return (-1);
61
62         for (i = 0; i < NUM_WK_SIDS; ++i) {
63                 cwsid = &(wksidarr[i].cifssid);
64
65                 /* compare the revision */
66                 if (ctsid->revision != cwsid->revision)
67                         continue;
68
69                 /* compare all of the six auth values */
70                 for (j = 0; j < 6; ++j) {
71                         if (ctsid->authority[j] != cwsid->authority[j])
72                                 break;
73                 }
74                 if (j < 6)
75                         continue; /* all of the auth values did not match */
76
77                 /* compare all of the subauth values if any */
78                 num_sat = ctsid->num_subauth;
79                 num_saw = cwsid->num_subauth;
80                 num_subauth = num_sat < num_saw ? num_sat : num_saw;
81                 if (num_subauth) {
82                         for (j = 0; j < num_subauth; ++j) {
83                                 if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
84                                         break;
85                         }
86                         if (j < num_subauth)
87                                 continue; /* all sub_auth values do not match */
88                 }
89
90                 cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname));
91                 return (0); /* sids compare/match */
92         }
93
94         cFYI(1, ("No matching sid"));
95         return (-1);
96 }
97
98 /* if the two SIDs (roughly equivalent to a UUID for a user or group) are
99    the same returns 1, if they do not match returns 0 */
100 int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid)
101 {
102         int i;
103         int num_subauth, num_sat, num_saw;
104
105         if ((!ctsid) || (!cwsid))
106                 return (0);
107
108         /* compare the revision */
109         if (ctsid->revision != cwsid->revision)
110                 return (0);
111
112         /* compare all of the six auth values */
113         for (i = 0; i < 6; ++i) {
114                 if (ctsid->authority[i] != cwsid->authority[i])
115                         return (0);
116         }
117
118         /* compare all of the subauth values if any */
119         num_sat = ctsid->num_subauth;
120         num_saw = cwsid->num_subauth;
121         num_subauth = num_sat < num_saw ? num_sat : num_saw;
122         if (num_subauth) {
123                 for (i = 0; i < num_subauth; ++i) {
124                         if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
125                                 return (0);
126                 }
127         }
128
129         return (1); /* sids compare/match */
130 }
131
132 void get_mode_from_acl(struct inode * inode, const char * path)
133 {
134
135         cFYI(1, ("get mode from ACL for %s", path));
136         
137         if (inode == NULL)
138                 return;
139
140         /* find an open readable handle
141            if handle found
142                  lock handle 
143            else open file
144               if no open file can not hurt to check if path is null
145            GetCIFSACL
146            for all ACEs in ACL {
147                    if U or G or O
148                            inode->i_mode = parse_ace(file_type, UG or O, ace->perms, inode->i_mode)
149                    else continue
150            }
151            if handle open close it
152            else unlock handle */
153
154         return;
155 }
156
157
158 static void parse_ace(struct cifs_ace *pace, char *end_of_acl)
159 {
160         int num_subauth;
161
162         /* validate that we do not go past end of acl */
163
164         if (le16_to_cpu(pace->size) < 16) {
165                 cERROR(1, ("ACE too small, %d", le16_to_cpu(pace->size)));
166                 return;
167         }
168
169         if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
170                 cERROR(1, ("ACL too small to parse ACE"));
171                 return;
172         }
173
174         num_subauth = pace->sid.num_subauth;
175         if (num_subauth) {
176 #ifdef CONFIG_CIFS_DEBUG2
177                 int i;
178                 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
179                         pace->sid.revision, pace->sid.num_subauth, pace->type,
180                         pace->flags, pace->size));
181                 for (i = 0; i < num_subauth; ++i) {
182                         cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
183                                 le32_to_cpu(pace->sid.sub_auth[i])));
184                 }
185
186                 /* BB add length check to make sure that we do not have huge
187                         num auths and therefore go off the end */
188 #endif
189         }
190
191         return;
192 }
193
194
195 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
196                        struct cifs_sid *pownersid, struct cifs_sid *pgrpsid)
197 {
198         int i;
199         int num_aces = 0;
200         int acl_size;
201         char *acl_base;
202         struct cifs_ace **ppace;
203
204         /* BB need to add parm so we can store the SID BB */
205
206         /* validate that we do not go past end of acl */
207         if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
208                 cERROR(1, ("ACL too small to parse DACL"));
209                 return;
210         }
211
212 #ifdef CONFIG_CIFS_DEBUG2
213         cFYI(1, ("DACL revision %d size %d num aces %d",
214                 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
215                 le32_to_cpu(pdacl->num_aces)));
216 #endif
217
218         acl_base = (char *)pdacl;
219         acl_size = sizeof(struct cifs_acl);
220
221         num_aces = le32_to_cpu(pdacl->num_aces);
222         if (num_aces  > 0) {
223                 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
224                                 GFP_KERNEL);
225
226 /*              cifscred->cecount = pdacl->num_aces;
227                 cifscred->aces = kmalloc(num_aces *
228                         sizeof(struct cifs_ace *), GFP_KERNEL);*/
229
230                 for (i = 0; i < num_aces; ++i) {
231                         ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
232
233                         parse_ace(ppace[i], end_of_acl);
234
235 /*                      memcpy((void *)(&(cifscred->aces[i])),
236                                 (void *)ppace[i],
237                                 sizeof(struct cifs_ace)); */
238
239                         acl_base = (char *)ppace[i];
240                         acl_size = le16_to_cpu(ppace[i]->size);
241                 }
242
243                 kfree(ppace);
244         }
245
246         return;
247 }
248
249
250 static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
251 {
252
253         /* BB need to add parm so we can store the SID BB */
254
255         /* validate that we do not go past end of acl */
256         if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) {
257                 cERROR(1, ("ACL too small to parse SID"));
258                 return -EINVAL;
259         }
260
261         if (psid->num_subauth) {
262 #ifdef CONFIG_CIFS_DEBUG2
263                 int i;
264                 cFYI(1, ("SID revision %d num_auth %d",
265                         psid->revision, psid->num_subauth));
266
267                 for (i = 0; i < psid->num_subauth; i++) {
268                         cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
269                                 le32_to_cpu(psid->sub_auth[i])));
270                 }
271
272                 /* BB add length check to make sure that we do not have huge
273                         num auths and therefore go off the end */
274                 cFYI(1, ("RID 0x%x",
275                         le32_to_cpu(psid->sub_auth[psid->num_subauth-1])));
276 #endif
277         }
278
279         return 0;
280 }
281
282
283 /* Convert CIFS ACL to POSIX form */
284 int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
285 {
286         int rc;
287         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
288         struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
289         char *end_of_acl = ((char *)pntsd) + acl_len;
290
291         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
292                                 le32_to_cpu(pntsd->osidoffset));
293         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
294                                 le32_to_cpu(pntsd->gsidoffset));
295         dacl_ptr = (struct cifs_acl *)((char *)pntsd +
296                                 le32_to_cpu(pntsd->dacloffset));
297 #ifdef CONFIG_CIFS_DEBUG2
298         cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
299                  "sacloffset 0x%x dacloffset 0x%x",
300                  pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
301                  le32_to_cpu(pntsd->gsidoffset),
302                  le32_to_cpu(pntsd->sacloffset),
303                  le32_to_cpu(pntsd->dacloffset)));
304 #endif
305         rc = parse_sid(owner_sid_ptr, end_of_acl);
306         if (rc)
307                 return rc;
308
309         rc = parse_sid(group_sid_ptr, end_of_acl);
310         if (rc)
311                 return rc;
312
313         parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr);
314
315 /*      cifscred->uid = owner_sid_ptr->rid;
316         cifscred->gid = group_sid_ptr->rid;
317         memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
318                         sizeof (struct cifs_sid));
319         memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
320                         sizeof (struct cifs_sid)); */
321
322
323         return (0);
324 }
325 #endif /* CONFIG_CIFS_EXPERIMENTAL */