]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/cifs/cifsacl.c
[CIFS] Fix incorrect mode when ACL had deny access control entries
[net-next-2.6.git] / fs / cifs / cifsacl.c
CommitLineData
bcb02034
SF
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
65874007
SF
24#include <linux/fs.h>
25#include "cifspdu.h"
26#include "cifsglob.h"
d0d66c44 27#include "cifsacl.h"
65874007
SF
28#include "cifsproto.h"
29#include "cifs_debug.h"
65874007 30
297647c2
SF
31
32#ifdef CONFIG_CIFS_EXPERIMENTAL
33
af6f4612 34static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
297647c2
SF
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"},
ce51ae14
DK
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"},
44093ca2
SF
41 {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }
42;
297647c2
SF
43
44
bcb02034 45/* security id for everyone */
e01b6400
SP
46static const struct cifs_sid sid_everyone = {
47 1, 1, {0, 0, 0, 0, 0, 1}, {0} };
bcb02034
SF
48/* group users */
49static const struct cifs_sid sid_user =
d12fd121 50 {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
d0d66c44 51
297647c2
SF
52
53int 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 */
ce51ae14
DK
78 num_sat = ctsid->num_subauth;
79 num_saw = cwsid->num_subauth;
297647c2
SF
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
a750e77c
SF
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 */
630f3f0c 100int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
297647c2
SF
101{
102 int i;
103 int num_subauth, num_sat, num_saw;
104
105 if ((!ctsid) || (!cwsid))
a750e77c 106 return (0);
297647c2
SF
107
108 /* compare the revision */
109 if (ctsid->revision != cwsid->revision)
a750e77c 110 return (0);
297647c2
SF
111
112 /* compare all of the six auth values */
113 for (i = 0; i < 6; ++i) {
114 if (ctsid->authority[i] != cwsid->authority[i])
a750e77c 115 return (0);
297647c2
SF
116 }
117
118 /* compare all of the subauth values if any */
adbc0358 119 num_sat = ctsid->num_subauth;
adddd49d 120 num_saw = cwsid->num_subauth;
297647c2
SF
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])
a750e77c 125 return (0);
297647c2
SF
126 }
127 }
128
a750e77c 129 return (1); /* sids compare/match */
297647c2
SF
130}
131
630f3f0c
SF
132/*
133 change posix mode to reflect permissions
134 pmode is the existing mode (we only want to overwrite part of this
135 bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
136*/
15b03959
SF
137static void access_flags_to_mode(__u32 ace_flags, int type, umode_t *pmode,
138 umode_t *pbits_to_set)
630f3f0c 139{
15b03959
SF
140 /* the order of ACEs is important. The canonical order is to begin with
141 DENY entries then follow with ALLOW, otherwise an allow entry could be
142 encountered first, making the subsequent deny entry like "dead code"
143 which would be superflous since Windows stops when a match is made
144 for the operation you are trying to perform for your user */
145
146 /* For deny ACEs we change the mask so that subsequent allow access
147 control entries do not turn on the bits we are denying */
148 if (type == ACCESS_DENIED) {
149 if (ace_flags & GENERIC_ALL) {
150 *pbits_to_set &= ~S_IRWXUGO;
151 }
152 if ((ace_flags & GENERIC_WRITE) ||
153 ((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
154 *pbits_to_set &= ~S_IWUGO;
155 if ((ace_flags & GENERIC_READ) ||
156 ((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
157 *pbits_to_set &= ~S_IRUGO;
158 if ((ace_flags & GENERIC_EXECUTE) ||
159 ((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
160 *pbits_to_set &= ~S_IXUGO;
161 return;
162 } else if (type != ACCESS_ALLOWED) {
163 cERROR(1, ("unknown access control type %d", type));
164 return;
165 }
166 /* else ACCESS_ALLOWED type */
630f3f0c 167
d61e5808 168 if (ace_flags & GENERIC_ALL) {
15b03959 169 *pmode |= (S_IRWXUGO & (*pbits_to_set));
630f3f0c 170#ifdef CONFIG_CIFS_DEBUG2
d61e5808 171 cFYI(1, ("all perms"));
630f3f0c 172#endif
d61e5808
SF
173 return;
174 }
e01b6400
SP
175 if ((ace_flags & GENERIC_WRITE) ||
176 ((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
15b03959 177 *pmode |= (S_IWUGO & (*pbits_to_set));
e01b6400
SP
178 if ((ace_flags & GENERIC_READ) ||
179 ((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
15b03959 180 *pmode |= (S_IRUGO & (*pbits_to_set));
e01b6400
SP
181 if ((ace_flags & GENERIC_EXECUTE) ||
182 ((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
15b03959 183 *pmode |= (S_IXUGO & (*pbits_to_set));
630f3f0c 184
d61e5808 185#ifdef CONFIG_CIFS_DEBUG2
b9c7a2bb 186 cFYI(1, ("access flags 0x%x mode now 0x%x", ace_flags, *pmode));
d61e5808 187#endif
630f3f0c
SF
188 return;
189}
190
297647c2 191
953f8681
SF
192#ifdef CONFIG_CIFS_DEBUG2
193static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
d0d66c44 194{
d0d66c44 195 int num_subauth;
d0d66c44
SP
196
197 /* validate that we do not go past end of acl */
297647c2 198
44093ca2
SF
199 if (le16_to_cpu(pace->size) < 16) {
200 cERROR(1, ("ACE too small, %d", le16_to_cpu(pace->size)));
201 return;
202 }
203
204 if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
d0d66c44
SP
205 cERROR(1, ("ACL too small to parse ACE"));
206 return;
44093ca2 207 }
d0d66c44 208
44093ca2 209 num_subauth = pace->sid.num_subauth;
d0d66c44 210 if (num_subauth) {
8f18c131 211 int i;
44093ca2
SF
212 cFYI(1, ("ACE revision %d num_auth %d type %d flags %d size %d",
213 pace->sid.revision, pace->sid.num_subauth, pace->type,
214 pace->flags, pace->size));
d12fd121
SF
215 for (i = 0; i < num_subauth; ++i) {
216 cFYI(1, ("ACE sub_auth[%d]: 0x%x", i,
44093ca2 217 le32_to_cpu(pace->sid.sub_auth[i])));
d12fd121
SF
218 }
219
220 /* BB add length check to make sure that we do not have huge
221 num auths and therefore go off the end */
d12fd121
SF
222 }
223
224 return;
225}
953f8681 226#endif
d12fd121 227
d0d66c44 228
a750e77c 229static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
d61e5808 230 struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
630f3f0c 231 struct inode *inode)
d0d66c44
SP
232{
233 int i;
234 int num_aces = 0;
235 int acl_size;
236 char *acl_base;
d0d66c44
SP
237 struct cifs_ace **ppace;
238
239 /* BB need to add parm so we can store the SID BB */
240
241 /* validate that we do not go past end of acl */
af6f4612 242 if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
d0d66c44
SP
243 cERROR(1, ("ACL too small to parse DACL"));
244 return;
245 }
246
247#ifdef CONFIG_CIFS_DEBUG2
248 cFYI(1, ("DACL revision %d size %d num aces %d",
af6f4612
SF
249 le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
250 le32_to_cpu(pdacl->num_aces)));
d0d66c44
SP
251#endif
252
7505e052
SF
253 /* reset rwx permissions for user/group/other.
254 Also, if num_aces is 0 i.e. DACL has no ACEs,
255 user/group/other have no permissions */
256 inode->i_mode &= ~(S_IRWXUGO);
257
258 if (!pdacl) {
259 /* no DACL in the security descriptor, set
260 all the permissions for user/group/other */
261 inode->i_mode |= S_IRWXUGO;
262 return;
263 }
d0d66c44
SP
264 acl_base = (char *)pdacl;
265 acl_size = sizeof(struct cifs_acl);
266
adbc0358 267 num_aces = le32_to_cpu(pdacl->num_aces);
d0d66c44 268 if (num_aces > 0) {
15b03959
SF
269 umode_t user_mask = S_IRWXU;
270 umode_t group_mask = S_IRWXG;
271 umode_t other_mask = S_IRWXO;
272
d0d66c44
SP
273 ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
274 GFP_KERNEL);
275
d12fd121 276/* cifscred->cecount = pdacl->num_aces;
d12fd121
SF
277 cifscred->aces = kmalloc(num_aces *
278 sizeof(struct cifs_ace *), GFP_KERNEL);*/
d0d66c44 279
d0d66c44 280 for (i = 0; i < num_aces; ++i) {
44093ca2 281 ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
953f8681
SF
282#ifdef CONFIG_CIFS_DEBUG2
283 dump_ace(ppace[i], end_of_acl);
284#endif
e01b6400
SP
285 if (compare_sids(&(ppace[i]->sid), pownersid))
286 access_flags_to_mode(ppace[i]->access_req,
15b03959
SF
287 ppace[i]->type,
288 &(inode->i_mode),
289 &user_mask);
e01b6400
SP
290 if (compare_sids(&(ppace[i]->sid), pgrpsid))
291 access_flags_to_mode(ppace[i]->access_req,
15b03959
SF
292 ppace[i]->type,
293 &(inode->i_mode),
294 &group_mask);
e01b6400
SP
295 if (compare_sids(&(ppace[i]->sid), &sid_everyone))
296 access_flags_to_mode(ppace[i]->access_req,
15b03959
SF
297 ppace[i]->type,
298 &(inode->i_mode),
299 &other_mask);
e01b6400 300
44093ca2 301/* memcpy((void *)(&(cifscred->aces[i])),
d12fd121
SF
302 (void *)ppace[i],
303 sizeof(struct cifs_ace)); */
d0d66c44 304
44093ca2
SF
305 acl_base = (char *)ppace[i];
306 acl_size = le16_to_cpu(ppace[i]->size);
d0d66c44
SP
307 }
308
309 kfree(ppace);
d0d66c44
SP
310 }
311
312 return;
313}
314
bcb02034
SF
315
316static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
317{
318 /* BB need to add parm so we can store the SID BB */
319
b9c7a2bb
SF
320 /* validate that we do not go past end of ACL - sid must be at least 8
321 bytes long (assuming no sub-auths - e.g. the null SID */
322 if (end_of_acl < (char *)psid + 8) {
323 cERROR(1, ("ACL too small to parse SID %p", psid));
bcb02034
SF
324 return -EINVAL;
325 }
d0d66c44 326
af6f4612 327 if (psid->num_subauth) {
bcb02034 328#ifdef CONFIG_CIFS_DEBUG2
8f18c131 329 int i;
44093ca2
SF
330 cFYI(1, ("SID revision %d num_auth %d",
331 psid->revision, psid->num_subauth));
bcb02034 332
af6f4612 333 for (i = 0; i < psid->num_subauth; i++) {
d0d66c44 334 cFYI(1, ("SID sub_auth[%d]: 0x%x ", i,
297647c2 335 le32_to_cpu(psid->sub_auth[i])));
d0d66c44
SP
336 }
337
d12fd121 338 /* BB add length check to make sure that we do not have huge
d0d66c44 339 num auths and therefore go off the end */
d12fd121 340 cFYI(1, ("RID 0x%x",
af6f4612 341 le32_to_cpu(psid->sub_auth[psid->num_subauth-1])));
bcb02034 342#endif
d0d66c44
SP
343 }
344
bcb02034
SF
345 return 0;
346}
347
d0d66c44 348
bcb02034 349/* Convert CIFS ACL to POSIX form */
630f3f0c
SF
350static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
351 struct inode *inode)
bcb02034 352{
d0d66c44 353 int rc;
bcb02034
SF
354 struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
355 struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
bcb02034 356 char *end_of_acl = ((char *)pntsd) + acl_len;
7505e052 357 __u32 dacloffset;
bcb02034 358
b9c7a2bb
SF
359 if ((inode == NULL) || (pntsd == NULL))
360 return -EIO;
361
bcb02034 362 owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 363 le32_to_cpu(pntsd->osidoffset));
bcb02034 364 group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
af6f4612 365 le32_to_cpu(pntsd->gsidoffset));
7505e052 366 dacloffset = le32_to_cpu(pntsd->dacloffset);
63d2583f 367 dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
bcb02034
SF
368#ifdef CONFIG_CIFS_DEBUG2
369 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
370 "sacloffset 0x%x dacloffset 0x%x",
af6f4612
SF
371 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
372 le32_to_cpu(pntsd->gsidoffset),
7505e052 373 le32_to_cpu(pntsd->sacloffset), dacloffset));
bcb02034 374#endif
b9c7a2bb 375/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
bcb02034
SF
376 rc = parse_sid(owner_sid_ptr, end_of_acl);
377 if (rc)
378 return rc;
379
380 rc = parse_sid(group_sid_ptr, end_of_acl);
381 if (rc)
382 return rc;
383
7505e052
SF
384 if (dacloffset)
385 parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
63d2583f 386 group_sid_ptr, inode);
7505e052
SF
387 else
388 cFYI(1, ("no ACL")); /* BB grant all or default perms? */
d0d66c44 389
bcb02034
SF
390/* cifscred->uid = owner_sid_ptr->rid;
391 cifscred->gid = group_sid_ptr->rid;
392 memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
630f3f0c 393 sizeof(struct cifs_sid));
bcb02034 394 memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
630f3f0c 395 sizeof(struct cifs_sid)); */
bcb02034 396
297647c2 397
bcb02034
SF
398 return (0);
399}
b9c7a2bb
SF
400
401
7505e052
SF
402/* Retrieve an ACL from the server */
403static struct cifs_ntsd *get_cifs_acl(u32 *pacllen, struct inode *inode,
404 const char *path)
b9c7a2bb
SF
405{
406 struct cifsFileInfo *open_file;
407 int unlock_file = FALSE;
408 int xid;
409 int rc = -EIO;
410 __u16 fid;
411 struct super_block *sb;
412 struct cifs_sb_info *cifs_sb;
413 struct cifs_ntsd *pntsd = NULL;
b9c7a2bb
SF
414
415 cFYI(1, ("get mode from ACL for %s", path));
416
417 if (inode == NULL)
7505e052 418 return NULL;
b9c7a2bb
SF
419
420 xid = GetXid();
421 open_file = find_readable_file(CIFS_I(inode));
422 sb = inode->i_sb;
423 if (sb == NULL) {
424 FreeXid(xid);
7505e052 425 return NULL;
b9c7a2bb
SF
426 }
427 cifs_sb = CIFS_SB(sb);
428
429 if (open_file) {
430 unlock_file = TRUE;
431 fid = open_file->netfid;
432 } else {
433 int oplock = FALSE;
434 /* open file */
435 rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN,
953f8681 436 READ_CONTROL, 0, &fid, &oplock, NULL,
b9c7a2bb
SF
437 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
438 CIFS_MOUNT_MAP_SPECIAL_CHR);
439 if (rc != 0) {
440 cERROR(1, ("Unable to open file to get ACL"));
441 FreeXid(xid);
7505e052 442 return NULL;
b9c7a2bb
SF
443 }
444 }
445
7505e052
SF
446 rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
447 cFYI(1, ("GetCIFSACL rc = %d ACL len %d", rc, *pacllen));
b9c7a2bb
SF
448 if (unlock_file == TRUE)
449 atomic_dec(&open_file->wrtPending);
450 else
451 CIFSSMBClose(xid, cifs_sb->tcon, fid);
452
7505e052
SF
453 FreeXid(xid);
454 return pntsd;
455}
456
457/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
458void acl_to_uid_mode(struct inode *inode, const char *path)
459{
460 struct cifs_ntsd *pntsd = NULL;
461 u32 acllen = 0;
462 int rc = 0;
463
464#ifdef CONFIG_CIFS_DEBUG2
465 cFYI(1, ("converting ACL to mode for %s", path));
466#endif
467 pntsd = get_cifs_acl(&acllen, inode, path);
468
469 /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
470 if (pntsd)
b9c7a2bb 471 rc = parse_sec_desc(pntsd, acllen, inode);
7505e052
SF
472 if (rc)
473 cFYI(1, ("parse sec desc failed rc = %d", rc));
474
b9c7a2bb 475 kfree(pntsd);
b9c7a2bb
SF
476 return;
477}
953f8681 478
7505e052 479/* Convert mode bits to an ACL so we can update the ACL on the server */
953f8681
SF
480int mode_to_acl(struct inode *inode, const char *path)
481{
482 int rc = 0;
483 __u32 acllen = 0;
484 struct cifs_ntsd *pntsd = NULL;
485
486 cFYI(1, ("set ACL from mode for %s", path));
487
488 /* Get the security descriptor */
7505e052 489 pntsd = get_cifs_acl(&acllen, inode, path);
953f8681 490
7505e052
SF
491 /* Add/Modify the three ACEs for owner, group, everyone
492 while retaining the other ACEs */
953f8681
SF
493
494 /* Set the security descriptor */
953f8681 495
7505e052
SF
496
497 kfree(pntsd);
953f8681
SF
498 return rc;
499}
297647c2 500#endif /* CONFIG_CIFS_EXPERIMENTAL */