[CIFS] ACL support part 5
[sfrench/cifs-2.6.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         if (inode == NULL)
136                 return;
137
138         /* find an open readable handle
139            if handle found
140                  lock handle 
141            else open file
142               if no open file can not hurt to check if path is null
143            GetCIFSACL
144            for all ACEs in ACL {
145                    if U or G or O
146                            inode->i_mode = parse_ace(file_type, UG or O, ace->perms, inode->i_mode)
147                    else continue
148            }
149            if handle open close it
150            else unlock handle */
151
152         return;
153 }
154
155
156 static void parse_ace(struct cifs_ace *pace, char *end_of_acl)
157 {
158         int num_subauth;
159
160         /* validate that we do not go past end of acl */
161
162         /* XXX this if statement can be removed
163         if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) {
164                 cERROR(1, ("ACL too small to parse ACE"));
165                 return;
166         } */
167
168         num_subauth = pace->num_subauth;
169         if (num_subauth) {
170 #ifdef CONFIG_CIFS_DEBUG2
171                 int i;
172                 cFYI(1, ("ACE revision %d num_subauth %d",
173                         pace->revision, pace->num_subauth));
174                 for (i = 0; i < num_subauth; ++i) {
175                         cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
176                                 le32_to_cpu(pace->sub_auth[i])));
177                 }
178
179                 /* BB add length check to make sure that we do not have huge
180                         num auths and therefore go off the end */
181
182                 cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1])));
183 #endif
184         }
185
186         return;
187 }
188
189 static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl)
190 {
191         /* validate that we do not go past end of acl */
192         if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) {
193                 cERROR(1, ("ACL too small to parse NT ACE"));
194                 return;
195         }
196
197 #ifdef CONFIG_CIFS_DEBUG2
198         cFYI(1, ("NTACE type %d flags 0x%x size %d, access Req 0x%x",
199                 pntace->type, pntace->flags, pntace->size,
200                 pntace->access_req));
201 #endif
202         return;
203 }
204
205
206
207 static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
208                        struct cifs_sid *pownersid, struct cifs_sid *pgrpsid)
209 {
210         int i;
211         int num_aces = 0;
212         int acl_size;
213         char *acl_base;
214         struct cifs_ntace **ppntace;
215         struct cifs_ace **ppace;
216
217         /* BB need to add parm so we can store the SID BB */
218
219         /* validate that we do not go past end of acl */
220         if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
221                 cERROR(1, ("ACL too small to parse DACL"));
222                 return;
223         }
224
225 #ifdef CONFIG_CIFS_DEBUG2
226         cFYI(1, ("DACL revision %d size %d num aces %d",
227                 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
228                 le32_to_cpu(pdacl->num_aces)));
229 #endif
230
231         acl_base = (char *)pdacl;
232         acl_size = sizeof(struct cifs_acl);
233
234         num_aces = le32_to_cpu(pdacl->num_aces);
235         if (num_aces  > 0) {
236                 ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *),
237                                 GFP_KERNEL);
238                 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
239                                 GFP_KERNEL);
240
241 /*              cifscred->cecount = pdacl->num_aces;
242                 cifscred->ntaces = kmalloc(num_aces *
243                         sizeof(struct cifs_ntace *), GFP_KERNEL);
244                 cifscred->aces = kmalloc(num_aces *
245                         sizeof(struct cifs_ace *), GFP_KERNEL);*/
246
247                 for (i = 0; i < num_aces; ++i) {
248                         ppntace[i] = (struct cifs_ntace *)
249                                         (acl_base + acl_size);
250                         ppace[i] = (struct cifs_ace *) ((char *)ppntace[i] +
251                                         sizeof(struct cifs_ntace));
252
253                         parse_ntace(ppntace[i], end_of_acl);
254                         if (end_of_acl < ((char *)ppace[i] +
255                                         (le16_to_cpu(ppntace[i]->size) -
256                                         sizeof(struct cifs_ntace)))) {
257                                 cERROR(1, ("ACL too small to parse ACE"));
258                                 break;
259                         } else
260                                 parse_ace(ppace[i], end_of_acl);
261
262 /*                      memcpy((void *)(&(cifscred->ntaces[i])),
263                                 (void *)ppntace[i],
264                                 sizeof(struct cifs_ntace));
265                         memcpy((void *)(&(cifscred->aces[i])),
266                                 (void *)ppace[i],
267                                 sizeof(struct cifs_ace)); */
268
269                         acl_base = (char *)ppntace[i];
270                         acl_size = le16_to_cpu(ppntace[i]->size);
271                 }
272
273                 kfree(ppace);
274                 kfree(ppntace);
275         }
276
277         return;
278 }
279
280
281 static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
282 {
283
284         /* BB need to add parm so we can store the SID BB */
285
286         /* validate that we do not go past end of acl */
287         if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) {
288                 cERROR(1, ("ACL too small to parse SID"));
289                 return -EINVAL;
290         }
291
292         if (psid->num_subauth) {
293 #ifdef CONFIG_CIFS_DEBUG2
294                 int i;
295                 cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x",
296                         psid->revision, psid->num_subauth, psid->sub_auth[0]));
297
298                 for (i = 0; i < psid->num_subauth; i++) {
299                         cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
300                                 le32_to_cpu(psid->sub_auth[i])));
301                 }
302
303                 /* BB add length check to make sure that we do not have huge
304                         num auths and therefore go off the end */
305                 cFYI(1, ("RID 0x%x",
306                         le32_to_cpu(psid->sub_auth[psid->num_subauth-1])));
307 #endif
308         }
309
310         return 0;
311 }
312
313
314 /* Convert CIFS ACL to POSIX form */
315 int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len)
316 {
317         int rc;
318         struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
319         struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
320         char *end_of_acl = ((char *)pntsd) + acl_len;
321
322         owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
323                                 le32_to_cpu(pntsd->osidoffset));
324         group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
325                                 le32_to_cpu(pntsd->gsidoffset));
326         dacl_ptr = (struct cifs_acl *)((char *)pntsd +
327                                 le32_to_cpu(pntsd->dacloffset));
328 #ifdef CONFIG_CIFS_DEBUG2
329         cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
330                  "sacloffset 0x%x dacloffset 0x%x",
331                  pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
332                  le32_to_cpu(pntsd->gsidoffset),
333                  le32_to_cpu(pntsd->sacloffset),
334                  le32_to_cpu(pntsd->dacloffset)));
335 #endif
336         rc = parse_sid(owner_sid_ptr, end_of_acl);
337         if (rc)
338                 return rc;
339
340         rc = parse_sid(group_sid_ptr, end_of_acl);
341         if (rc)
342                 return rc;
343
344         parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr);
345
346 /*      cifscred->uid = owner_sid_ptr->rid;
347         cifscred->gid = group_sid_ptr->rid;
348         memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
349                         sizeof (struct cifs_sid));
350         memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
351                         sizeof (struct cifs_sid)); */
352
353
354         return (0);
355 }
356 #endif /* CONFIG_CIFS_EXPERIMENTAL */