Commit 1b244081 authored by Steve French's avatar Steve French

Do not attempt to do cifs operations reading symlinks with SMB2

When use of symlinks is enabled (mounting with mfsymlinks option) to
non-Samba servers, we always tried to use cifs, even when we
were mounted with SMB2 or SMB3, which causes the server to drop the
network connection.

This patch separates out the protocol specific operations for cifs from
the code which recognizes symlinks, and fixes the problem where
with SMB2 mounts we attempt cifs operations to open and read
symlinks.  The next patch will add support for SMB2 for opening
and reading symlinks.  Additional followon patches will address
the similar problem creating symlinks.
Signed-off-by: default avatarSteve French <smfrench@gmail.com>
parent 057d6332
...@@ -370,6 +370,9 @@ struct smb_version_operations { ...@@ -370,6 +370,9 @@ struct smb_version_operations {
void (*generate_signingkey)(struct TCP_Server_Info *server); void (*generate_signingkey)(struct TCP_Server_Info *server);
int (*calc_signature)(struct smb_rqst *rqst, int (*calc_signature)(struct smb_rqst *rqst,
struct TCP_Server_Info *server); struct TCP_Server_Info *server);
int (*query_mf_symlink)(const unsigned char *path, char *pbuf,
unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
unsigned int xid);
}; };
struct smb_version_values { struct smb_version_values {
......
...@@ -497,5 +497,7 @@ void cifs_writev_complete(struct work_struct *work); ...@@ -497,5 +497,7 @@ void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages, struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
work_func_t complete); work_func_t complete);
void cifs_writedata_release(struct kref *refcount); void cifs_writedata_release(struct kref *refcount);
int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
unsigned int xid);
#endif /* _CIFSPROTO_H */ #endif /* _CIFSPROTO_H */
...@@ -305,67 +305,89 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr) ...@@ -305,67 +305,89 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
} }
int int
CIFSCheckMFSymlink(struct cifs_fattr *fattr, open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
const unsigned char *path, unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
struct cifs_sb_info *cifs_sb, unsigned int xid) unsigned int xid)
{ {
int rc; int rc;
int oplock = 0; int oplock = 0;
__u16 netfid = 0; __u16 netfid = 0;
struct tcon_link *tlink; struct tcon_link *tlink;
struct cifs_tcon *pTcon; struct cifs_tcon *ptcon;
struct cifs_io_parms io_parms; struct cifs_io_parms io_parms;
u8 *buf;
char *pbuf;
unsigned int bytes_read = 0;
int buf_type = CIFS_NO_BUFFER; int buf_type = CIFS_NO_BUFFER;
unsigned int link_len = 0;
FILE_ALL_INFO file_info; FILE_ALL_INFO file_info;
if (!CIFSCouldBeMFSymlink(fattr))
/* it's not a symlink */
return 0;
tlink = cifs_sb_tlink(cifs_sb); tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink)) if (IS_ERR(tlink))
return PTR_ERR(tlink); return PTR_ERR(tlink);
pTcon = tlink_tcon(tlink); ptcon = tlink_tcon(tlink);
rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ,
CREATE_NOT_DIR, &netfid, &oplock, &file_info, CREATE_NOT_DIR, &netfid, &oplock, &file_info,
cifs_sb->local_nls, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR); CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc != 0) if (rc != 0) {
goto out; cifs_put_tlink(tlink);
return rc;
}
if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, ptcon, netfid);
cifs_put_tlink(tlink);
/* it's not a symlink */ /* it's not a symlink */
goto out; return rc;
} }
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
goto out;
}
pbuf = buf;
io_parms.netfid = netfid; io_parms.netfid = netfid;
io_parms.pid = current->tgid; io_parms.pid = current->tgid;
io_parms.tcon = pTcon; io_parms.tcon = ptcon;
io_parms.offset = 0; io_parms.offset = 0;
io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE; io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type); rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
CIFSSMBClose(xid, pTcon, netfid); CIFSSMBClose(xid, ptcon, netfid);
if (rc != 0) { cifs_put_tlink(tlink);
kfree(buf); return rc;
}
int
CIFSCheckMFSymlink(struct cifs_fattr *fattr,
const unsigned char *path,
struct cifs_sb_info *cifs_sb, unsigned int xid)
{
int rc = 0;
u8 *buf = NULL;
unsigned int link_len = 0;
unsigned int bytes_read = 0;
struct cifs_tcon *ptcon;
if (!CIFSCouldBeMFSymlink(fattr))
/* it's not a symlink */
return 0;
buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
if (!buf) {
rc = -ENOMEM;
goto out; goto out;
} }
ptcon = tlink_tcon(cifs_sb_tlink(cifs_sb));
if ((ptcon->ses) && (ptcon->ses->server->ops->query_mf_symlink))
rc = ptcon->ses->server->ops->query_mf_symlink(path, buf,
&bytes_read, cifs_sb, xid);
else
goto out;
if (rc != 0)
goto out;
if (bytes_read == 0) /* not a symlink */
goto out;
rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL); rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
kfree(buf);
if (rc == -EINVAL) { if (rc == -EINVAL) {
/* it's not a symlink */ /* it's not a symlink */
rc = 0; rc = 0;
...@@ -381,7 +403,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr, ...@@ -381,7 +403,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr,
fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
fattr->cf_dtype = DT_LNK; fattr->cf_dtype = DT_LNK;
out: out:
cifs_put_tlink(tlink); kfree(buf);
return rc; return rc;
} }
......
...@@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = { ...@@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
.mand_lock = cifs_mand_lock, .mand_lock = cifs_mand_lock,
.mand_unlock_range = cifs_unlock_range, .mand_unlock_range = cifs_unlock_range,
.push_mand_locks = cifs_push_mandatory_locks, .push_mand_locks = cifs_push_mandatory_locks,
.query_mf_symlink = open_query_close_cifs_symlink,
}; };
struct smb_version_values smb1_values = { struct smb_version_values smb1_values = {
......
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