[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: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>

authored by Jeff Layton and committed by Steve French 67750fb9 02eadeff

+31 -17
+1
fs/cifs/cifspdu.h
··· 340 340 #define OPEN_NO_RECALL 0x00400000 341 341 #define OPEN_FREE_SPACE_QUERY 0x00800000 /* should be zero */ 342 342 #define CREATE_OPTIONS_MASK 0x007FFFFF 343 + #define CREATE_OPTION_READONLY 0x10000000 343 344 #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ 344 345 345 346 /* ImpersonationLevel flags */
+6 -10
fs/cifs/cifssmb.c
··· 1224 1224 else /* BB FIXME BB */ 1225 1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); 1226 1226 1227 - /* if ((omode & S_IWUGO) == 0) 1228 - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ 1229 - /* Above line causes problems due to vfs splitting create into two 1230 - pieces - need to set mode after file created not while it is 1231 - being created */ 1227 + if (create_options & CREATE_OPTION_READONLY) 1228 + pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY); 1232 1229 1233 1230 /* BB FIXME BB */ 1234 1231 /* pSMB->CreateOptions = cpu_to_le32(create_options & ··· 1328 1331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); 1329 1332 else 1330 1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); 1334 + 1331 1335 /* XP does not handle ATTR_POSIX_SEMANTICS */ 1332 1336 /* but it helps speed up case sensitive checks for other 1333 1337 servers such as Samba */ 1334 1338 if (tcon->ses->capabilities & CAP_UNIX) 1335 1339 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS); 1336 1340 1337 - /* if ((omode & S_IWUGO) == 0) 1338 - pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ 1339 - /* Above line causes problems due to vfs splitting create into two 1340 - pieces - need to set mode after file created not while it is 1341 - being created */ 1341 + if (create_options & CREATE_OPTION_READONLY) 1342 + pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY); 1343 + 1342 1344 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); 1343 1345 pSMB->CreateDisposition = cpu_to_le32(openDisposition); 1344 1346 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
+13 -3
fs/cifs/dir.c
··· 119 119 { 120 120 int rc = -ENOENT; 121 121 int xid; 122 + int create_options = CREATE_NOT_DIR; 122 123 int oplock = 0; 123 124 int desiredAccess = GENERIC_READ | GENERIC_WRITE; 124 125 __u16 fileHandle; ··· 177 176 FreeXid(xid); 178 177 return -ENOMEM; 179 178 } 179 + 180 + mode &= ~current->fs->umask; 181 + 182 + /* 183 + * if we're not using unix extensions, see if we need to set 184 + * ATTR_READONLY on the create call 185 + */ 186 + if (!pTcon->unix_ext && (mode & S_IWUGO) == 0) 187 + create_options |= CREATE_OPTION_READONLY; 188 + 180 189 if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) 181 190 rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, 182 - desiredAccess, CREATE_NOT_DIR, 191 + desiredAccess, create_options, 183 192 &fileHandle, &oplock, buf, cifs_sb->local_nls, 184 193 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 185 194 else ··· 198 187 if (rc == -EIO) { 199 188 /* old server, retry the open legacy style */ 200 189 rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, 201 - desiredAccess, CREATE_NOT_DIR, 190 + desiredAccess, create_options, 202 191 &fileHandle, &oplock, buf, cifs_sb->local_nls, 203 192 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 204 193 } ··· 208 197 /* If Open reported that we actually created a file 209 198 then we now have to set the mode if possible */ 210 199 if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) { 211 - mode &= ~current->fs->umask; 212 200 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 213 201 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, 214 202 (__u64)current->fsuid,
+11 -4
fs/cifs/inode.c
··· 974 974 * failed to get it from the server or was set bogus */ 975 975 if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2)) 976 976 direntry->d_inode->i_nlink = 2; 977 + mode &= ~current->fs->umask; 977 978 if (pTcon->unix_ext) { 978 - mode &= ~current->fs->umask; 979 979 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { 980 980 CIFSSMBUnixSetPerms(xid, pTcon, full_path, 981 981 mode, ··· 994 994 CIFS_MOUNT_MAP_SPECIAL_CHR); 995 995 } 996 996 } else { 997 - /* BB to be implemented via Windows secrty descriptors 998 - eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, 999 - -1, -1, local_nls); */ 997 + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) && 998 + (mode & S_IWUGO) == 0) { 999 + FILE_BASIC_INFO pInfo; 1000 + memset(&pInfo, 0, sizeof(pInfo)); 1001 + pInfo.Attributes = cpu_to_le32(ATTR_READONLY); 1002 + CIFSSMBSetTimes(xid, pTcon, full_path, 1003 + &pInfo, cifs_sb->local_nls, 1004 + cifs_sb->mnt_cifs_flags & 1005 + CIFS_MOUNT_MAP_SPECIAL_CHR); 1006 + } 1000 1007 if (direntry->d_inode) { 1001 1008 direntry->d_inode->i_mode = mode; 1002 1009 direntry->d_inode->i_mode |= S_IFDIR;