]> err.no Git - linux-2.6/blobdiff - fs/cifs/cifsacl.c
regression: cifs endianness bug
[linux-2.6] / fs / cifs / cifsacl.c
index bd75a3b8caffd418e2fef1a4271503eec3035d0b..c312adcba4fc1b0530cba4e869beeca9763c13d3 100644 (file)
@@ -134,29 +134,88 @@ int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
    pmode is the existing mode (we only want to overwrite part of this
    bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
 */
-static void access_flags_to_mode(__u32 ace_flags, umode_t *pmode,
-                                umode_t bits_to_set)
+static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
+                                umode_t *pbits_to_set)
 {
+       __u32 flags = le32_to_cpu(ace_flags);
+       /* the order of ACEs is important.  The canonical order is to begin with
+          DENY entries followed by ALLOW, otherwise an allow entry could be
+          encountered first, making the subsequent deny entry like "dead code"
+          which would be superflous since Windows stops when a match is made
+          for the operation you are trying to perform for your user */
+
+       /* For deny ACEs we change the mask so that subsequent allow access
+          control entries do not turn on the bits we are denying */
+       if (type == ACCESS_DENIED) {
+               if (flags & GENERIC_ALL) {
+                       *pbits_to_set &= ~S_IRWXUGO;
+               }
+               if ((flags & GENERIC_WRITE) ||
+                       ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
+                       *pbits_to_set &= ~S_IWUGO;
+               if ((flags & GENERIC_READ) ||
+                       ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
+                       *pbits_to_set &= ~S_IRUGO;
+               if ((flags & GENERIC_EXECUTE) ||
+                       ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
+                       *pbits_to_set &= ~S_IXUGO;
+               return;
+       } else if (type != ACCESS_ALLOWED) {
+               cERROR(1, ("unknown access control type %d", type));
+               return;
+       }
+       /* else ACCESS_ALLOWED type */
 
-       if (ace_flags & GENERIC_ALL) {
-               *pmode |= (S_IRWXUGO & bits_to_set);
+       if (flags & GENERIC_ALL) {
+               *pmode |= (S_IRWXUGO & (*pbits_to_set));
 #ifdef CONFIG_CIFS_DEBUG2
                cFYI(1, ("all perms"));
 #endif
                return;
        }
-       if ((ace_flags & GENERIC_WRITE) ||
-                       ((ace_flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
-               *pmode |= (S_IWUGO & bits_to_set);
-       if ((ace_flags & GENERIC_READ) ||
-                       ((ace_flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
-               *pmode |= (S_IRUGO & bits_to_set);
-       if ((ace_flags & GENERIC_EXECUTE) ||
-                       ((ace_flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
-               *pmode |= (S_IXUGO & bits_to_set);
+       if ((flags & GENERIC_WRITE) ||
+                       ((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
+               *pmode |= (S_IWUGO & (*pbits_to_set));
+       if ((flags & GENERIC_READ) ||
+                       ((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
+               *pmode |= (S_IRUGO & (*pbits_to_set));
+       if ((flags & GENERIC_EXECUTE) ||
+                       ((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
+               *pmode |= (S_IXUGO & (*pbits_to_set));
+
+#ifdef CONFIG_CIFS_DEBUG2
+       cFYI(1, ("access flags 0x%x mode now 0x%x", flags, *pmode));
+#endif
+       return;
+}
+
+/*
+   Generate access flags to reflect permissions mode is the existing mode.
+   This function is called for every ACE in the DACL whose SID matches
+   with either owner or group or everyone.
+*/
+
+static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
+                               __u32 *pace_flags)
+{
+       /* reset access mask */
+       *pace_flags = 0x0;
+
+       /* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
+       mode &= bits_to_use;
+
+       /* check for R/W/X UGO since we do not know whose flags
+          is this but we have cleared all the bits sans RWX for
+          either user or group or other as per bits_to_use */
+       if (mode & S_IRUGO)
+               *pace_flags |= SET_FILE_READ_RIGHTS;
+       if (mode & S_IWUGO)
+               *pace_flags |= SET_FILE_WRITE_RIGHTS;
+       if (mode & S_IXUGO)
+               *pace_flags |= SET_FILE_EXEC_RIGHTS;
 
 #ifdef CONFIG_CIFS_DEBUG2
-       cFYI(1, ("access flags 0x%x mode now 0x%x", ace_flags, *pmode));
+       cFYI(1, ("mode: 0x%x, access flags now 0x%x", mode, *pace_flags));
 #endif
        return;
 }
@@ -211,6 +270,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
 
        /* BB need to add parm so we can store the SID BB */
 
+       if (!pdacl) {
+               /* no DACL in the security descriptor, set
+                  all the permissions for user/group/other */
+               inode->i_mode |= S_IRWXUGO;
+               return;
+       }
+
        /* validate that we do not go past end of acl */
        if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
                cERROR(1, ("ACL too small to parse DACL"));
@@ -228,17 +294,15 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
           user/group/other have no permissions */
        inode->i_mode &= ~(S_IRWXUGO);
 
-       if (!pdacl) {
-               /* no DACL in the security descriptor, set
-                  all the permissions for user/group/other */
-               inode->i_mode |= S_IRWXUGO;
-               return;
-       }
        acl_base = (char *)pdacl;
        acl_size = sizeof(struct cifs_acl);
 
        num_aces = le32_to_cpu(pdacl->num_aces);
        if (num_aces  > 0) {
+               umode_t user_mask = S_IRWXU;
+               umode_t group_mask = S_IRWXG;
+               umode_t other_mask = S_IRWXO;
+
                ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
                                GFP_KERNEL);
 
@@ -253,13 +317,19 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
 #endif
                        if (compare_sids(&(ppace[i]->sid), pownersid))
                                access_flags_to_mode(ppace[i]->access_req,
-                                               &(inode->i_mode), S_IRWXU);
+                                                    ppace[i]->type,
+                                                    &(inode->i_mode),
+                                                    &user_mask);
                        if (compare_sids(&(ppace[i]->sid), pgrpsid))
                                access_flags_to_mode(ppace[i]->access_req,
-                                               &(inode->i_mode), S_IRWXG);
+                                                    ppace[i]->type,
+                                                    &(inode->i_mode),
+                                                    &group_mask);
                        if (compare_sids(&(ppace[i]->sid), &sid_everyone))
                                access_flags_to_mode(ppace[i]->access_req,
-                                               &(inode->i_mode), S_IRWXO);
+                                                    ppace[i]->type,
+                                                    &(inode->i_mode),
+                                                    &other_mask);
 
 /*                     memcpy((void *)(&(cifscred->aces[i])),
                                (void *)ppace[i],
@@ -327,7 +397,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
        group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
                                le32_to_cpu(pntsd->gsidoffset));
        dacloffset = le32_to_cpu(pntsd->dacloffset);
-       dacl_ptr = (struct cifs_acl *)(char *)pntsd + dacloffset;
+       dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
 #ifdef CONFIG_CIFS_DEBUG2
        cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x "
                 "sacloffset 0x%x dacloffset 0x%x",
@@ -346,7 +416,7 @@ static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
 
        if (dacloffset)
                parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
-               group_sid_ptr, inode);
+                          group_sid_ptr, inode);
        else
                cFYI(1, ("no ACL")); /* BB grant all or default perms? */