Commit 67750fb9 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French

[CIFS] when not using unix extensions, check for and set ATTR_READONLY on create and mkdir

When creating a directory on a CIFS share without POSIX extensions,
and the given mode has no write bits set, set the ATTR_READONLY bit.

When creating a file, set ATTR_READONLY if the create mode has no write
bits set and we're not using unix extensions.

There are some comments about this being problematic due to the VFS
splitting creates into 2 parts. I'm not sure what that's actually
talking about, but I'm assuming that it has something to do with how
mknod is implemented. In the simple case where we have no unix
extensions and we're just creating a regular file, there's no reason
we can't set ATTR_READONLY.
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 02eadeff
...@@ -340,6 +340,7 @@ ...@@ -340,6 +340,7 @@
#define OPEN_NO_RECALL 0x00400000 #define OPEN_NO_RECALL 0x00400000
#define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */
#define CREATE_OPTIONS_MASK 0x007FFFFF #define CREATE_OPTIONS_MASK 0x007FFFFF
#define CREATE_OPTION_READONLY 0x10000000
#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
/* ImpersonationLevel flags */ /* ImpersonationLevel flags */
......
...@@ -1224,11 +1224,8 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -1224,11 +1224,8 @@ SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
else /* BB FIXME BB */ else /* BB FIXME BB */
pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
/* if ((omode & S_IWUGO) == 0) if (create_options & CREATE_OPTION_READONLY)
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
/* BB FIXME BB */ /* BB FIXME BB */
/* pSMB->CreateOptions = cpu_to_le32(create_options & /* pSMB->CreateOptions = cpu_to_le32(create_options &
...@@ -1331,17 +1328,16 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ...@@ -1331,17 +1328,16 @@ CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
else else
pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
/* XP does not handle ATTR_POSIX_SEMANTICS */ /* XP does not handle ATTR_POSIX_SEMANTICS */
/* but it helps speed up case sensitive checks for other /* but it helps speed up case sensitive checks for other
servers such as Samba */ servers such as Samba */
if (tcon->ses->capabilities & CAP_UNIX) if (tcon->ses->capabilities & CAP_UNIX)
pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
/* if ((omode & S_IWUGO) == 0) if (create_options & CREATE_OPTION_READONLY)
pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
/* Above line causes problems due to vfs splitting create into two
pieces - need to set mode after file created not while it is
being created */
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
pSMB->CreateDisposition = cpu_to_le32(openDisposition); pSMB->CreateDisposition = cpu_to_le32(openDisposition);
pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
......
...@@ -119,6 +119,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -119,6 +119,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
{ {
int rc = -ENOENT; int rc = -ENOENT;
int xid; int xid;
int create_options = CREATE_NOT_DIR;
int oplock = 0; int oplock = 0;
int desiredAccess = GENERIC_READ | GENERIC_WRITE; int desiredAccess = GENERIC_READ | GENERIC_WRITE;
__u16 fileHandle; __u16 fileHandle;
...@@ -176,9 +177,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -176,9 +177,19 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
FreeXid(xid); FreeXid(xid);
return -ENOMEM; return -ENOMEM;
} }
mode &= ~current->fs->umask;
/*
* if we're not using unix extensions, see if we need to set
* ATTR_READONLY on the create call
*/
if (!pTcon->unix_ext && (mode & S_IWUGO) == 0)
create_options |= CREATE_OPTION_READONLY;
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
else else
...@@ -187,7 +198,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -187,7 +198,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
if (rc == -EIO) { if (rc == -EIO) {
/* old server, retry the open legacy style */ /* old server, retry the open legacy style */
rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, rc = SMBLegacyOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, desiredAccess, create_options,
&fileHandle, &oplock, buf, cifs_sb->local_nls, &fileHandle, &oplock, buf, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
...@@ -197,7 +208,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, ...@@ -197,7 +208,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
/* If Open reported that we actually created a file /* If Open reported that we actually created a file
then we now have to set the mode if possible */ then we now have to set the mode if possible */
if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
(__u64)current->fsuid, (__u64)current->fsuid,
......
...@@ -974,8 +974,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -974,8 +974,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
* failed to get it from the server or was set bogus */ * failed to get it from the server or was set bogus */
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
direntry->d_inode->i_nlink = 2; direntry->d_inode->i_nlink = 2;
mode &= ~current->fs->umask;
if (pTcon->unix_ext) { if (pTcon->unix_ext) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, CIFSSMBUnixSetPerms(xid, pTcon, full_path,
mode, mode,
...@@ -994,9 +994,16 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ...@@ -994,9 +994,16 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
} }
} else { } else {
/* BB to be implemented via Windows secrty descriptors if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, (mode & S_IWUGO) == 0) {
-1, -1, local_nls); */ FILE_BASIC_INFO pInfo;
memset(&pInfo, 0, sizeof(pInfo));
pInfo.Attributes = cpu_to_le32(ATTR_READONLY);
CIFSSMBSetTimes(xid, pTcon, full_path,
&pInfo, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
if (direntry->d_inode) { if (direntry->d_inode) {
direntry->d_inode->i_mode = mode; direntry->d_inode->i_mode = mode;
direntry->d_inode->i_mode |= S_IFDIR; direntry->d_inode->i_mode |= S_IFDIR;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment