forked from Minki/linux
disable most mode changes on non-unix/non-cifsacl mounts
CIFS currently allows you to change the mode of an inode on a share that doesn't have unix extensions enabled, and isn't using cifsacl. The inode in this case *only* has its mode changed in memory on the client. This is problematic since it can change any time the inode is purged from the cache. This patch makes cifs_setattr silently ignore most mode changes when unix extensions and cifsacl support are not enabled, and when the share is not mounted with the "dynperm" option. The exceptions are: When a mode change would remove all write access to an inode we turn on the ATTR_READONLY bit on the server and remove all write bits from the inode's mode in memory. When a mode change would add a write bit to an inode that previously had them all turned off, it turns off the ATTR_READONLY bit on the server, and resets the mode back to what it would normally be (generally, the file_mode or dir_mode of the share). Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
parent
b7206153f6
commit
5132861a7a
@ -1575,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
attrs->ia_valid &= ~ATTR_MODE;
|
||||
|
||||
if (attrs->ia_valid & ATTR_MODE) {
|
||||
cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
|
||||
cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
|
||||
mode = attrs->ia_mode;
|
||||
}
|
||||
|
||||
@ -1590,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
|
||||
rc = mode_to_acl(inode, full_path, mode);
|
||||
else if ((mode & S_IWUGO) == 0) {
|
||||
#else
|
||||
if ((mode & S_IWUGO) == 0) {
|
||||
else
|
||||
#endif
|
||||
/* not writeable */
|
||||
if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
|
||||
set_dosattr = true;
|
||||
time_buf.Attributes =
|
||||
cpu_to_le32(cifsInode->cifsAttrs |
|
||||
ATTR_READONLY);
|
||||
}
|
||||
} else if (cifsInode->cifsAttrs & ATTR_READONLY) {
|
||||
if (((mode & S_IWUGO) == 0) &&
|
||||
(cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
|
||||
set_dosattr = true;
|
||||
time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
|
||||
ATTR_READONLY);
|
||||
/* fix up mode if we're not using dynperm */
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
|
||||
attrs->ia_mode = inode->i_mode & ~S_IWUGO;
|
||||
} else if ((mode & S_IWUGO) &&
|
||||
(cifsInode->cifsAttrs & ATTR_READONLY)) {
|
||||
/* If file is readonly on server, we would
|
||||
not be able to write to it - so if any write
|
||||
bit is enabled for user or group or other we
|
||||
@ -1612,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
|
||||
/* Windows ignores set to zero */
|
||||
if (time_buf.Attributes == 0)
|
||||
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
|
||||
|
||||
/* reset local inode permissions to normal */
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
|
||||
attrs->ia_mode &= ~(S_IALLUGO);
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
attrs->ia_mode |=
|
||||
cifs_sb->mnt_dir_mode;
|
||||
else
|
||||
attrs->ia_mode |=
|
||||
cifs_sb->mnt_file_mode;
|
||||
}
|
||||
} else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
|
||||
/* ignore mode change - ATTR_READONLY hasn't changed */
|
||||
attrs->ia_valid &= ~ATTR_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user