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