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