Commit 584d88b2 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS fixes from Steve French:
 "A set of small cifs fixes, including 3 relating to symlink handling"

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: don't instantiate new dentries in readdir for inodes that need to be revalidated immediately
  cifs: set sb->s_d_op before calling d_make_root()
  cifs: fix bad error handling in crypto code
  cifs: file: initialize oparms.reconnect before using it
  Do not attempt to do cifs operations reading symlinks with SMB2
  cifs: extend the buffer length enought for sprintf() using
parents fd4f35d0 757c4f62
...@@ -43,17 +43,18 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server) ...@@ -43,17 +43,18 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
server->secmech.md5 = crypto_alloc_shash("md5", 0, 0); server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
if (IS_ERR(server->secmech.md5)) { if (IS_ERR(server->secmech.md5)) {
cifs_dbg(VFS, "could not allocate crypto md5\n"); cifs_dbg(VFS, "could not allocate crypto md5\n");
return PTR_ERR(server->secmech.md5); rc = PTR_ERR(server->secmech.md5);
server->secmech.md5 = NULL;
return rc;
} }
size = sizeof(struct shash_desc) + size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.md5); crypto_shash_descsize(server->secmech.md5);
server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL); server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdescmd5) { if (!server->secmech.sdescmd5) {
rc = -ENOMEM;
crypto_free_shash(server->secmech.md5); crypto_free_shash(server->secmech.md5);
server->secmech.md5 = NULL; server->secmech.md5 = NULL;
return rc; return -ENOMEM;
} }
server->secmech.sdescmd5->shash.tfm = server->secmech.md5; server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
server->secmech.sdescmd5->shash.flags = 0x0; server->secmech.sdescmd5->shash.flags = 0x0;
...@@ -421,7 +422,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -421,7 +422,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
if (blobptr + attrsize > blobend) if (blobptr + attrsize > blobend)
break; break;
if (type == NTLMSSP_AV_NB_DOMAIN_NAME) { if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
if (!attrsize) if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
break; break;
if (!ses->domainName) { if (!ses->domainName) {
ses->domainName = ses->domainName =
...@@ -591,6 +592,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash) ...@@ -591,6 +592,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server) static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
{ {
int rc;
unsigned int size; unsigned int size;
/* check if already allocated */ /* check if already allocated */
...@@ -600,7 +602,9 @@ static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server) ...@@ -600,7 +602,9 @@ static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0); server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
if (IS_ERR(server->secmech.hmacmd5)) { if (IS_ERR(server->secmech.hmacmd5)) {
cifs_dbg(VFS, "could not allocate crypto hmacmd5\n"); cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
return PTR_ERR(server->secmech.hmacmd5); rc = PTR_ERR(server->secmech.hmacmd5);
server->secmech.hmacmd5 = NULL;
return rc;
} }
size = sizeof(struct shash_desc) + size = sizeof(struct shash_desc) +
......
...@@ -147,18 +147,17 @@ cifs_read_super(struct super_block *sb) ...@@ -147,18 +147,17 @@ cifs_read_super(struct super_block *sb)
goto out_no_root; goto out_no_root;
} }
if (cifs_sb_master_tcon(cifs_sb)->nocase)
sb->s_d_op = &cifs_ci_dentry_ops;
else
sb->s_d_op = &cifs_dentry_ops;
sb->s_root = d_make_root(inode); sb->s_root = d_make_root(inode);
if (!sb->s_root) { if (!sb->s_root) {
rc = -ENOMEM; rc = -ENOMEM;
goto out_no_root; goto out_no_root;
} }
/* do that *after* d_make_root() - we want NULL ->d_op for root here */
if (cifs_sb_master_tcon(cifs_sb)->nocase)
sb->s_d_op = &cifs_ci_dentry_ops;
else
sb->s_d_op = &cifs_dentry_ops;
#ifdef CONFIG_CIFS_NFSD_EXPORT #ifdef CONFIG_CIFS_NFSD_EXPORT
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cifs_dbg(FYI, "export ops supported\n"); cifs_dbg(FYI, "export ops supported\n");
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1) #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
#define MAX_SERVER_SIZE 15 #define MAX_SERVER_SIZE 15
#define MAX_SHARE_SIZE 80 #define MAX_SHARE_SIZE 80
#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */
#define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */ #define MAX_USERNAME_SIZE 256 /* reasonable maximum for current servers */
#define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */ #define MAX_PASSWORD_SIZE 512 /* max for windows seems to be 256 wide chars */
...@@ -369,6 +370,9 @@ struct smb_version_operations { ...@@ -369,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 */
...@@ -1675,7 +1675,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, ...@@ -1675,7 +1675,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (string == NULL) if (string == NULL)
goto out_nomem; goto out_nomem;
if (strnlen(string, 256) == 256) { if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
== CIFS_MAX_DOMAINNAME_LEN) {
printk(KERN_WARNING "CIFS: domain name too" printk(KERN_WARNING "CIFS: domain name too"
" long\n"); " long\n");
goto cifs_parse_mount_err; goto cifs_parse_mount_err;
...@@ -2276,8 +2277,8 @@ cifs_put_smb_ses(struct cifs_ses *ses) ...@@ -2276,8 +2277,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */ /* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1) #define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
/* Populate username and pw fields from keyring if possible */ /* Populate username and pw fields from keyring if possible */
static int static int
......
...@@ -647,6 +647,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush) ...@@ -647,6 +647,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
oflags, &oplock, &cfile->fid.netfid, xid); oflags, &oplock, &cfile->fid.netfid, xid);
if (rc == 0) { if (rc == 0) {
cifs_dbg(FYI, "posix reopen succeeded\n"); cifs_dbg(FYI, "posix reopen succeeded\n");
oparms.reconnect = true;
goto reopen_success; goto reopen_success;
} }
/* /*
......
...@@ -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;
} }
......
...@@ -111,6 +111,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, ...@@ -111,6 +111,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
return; return;
} }
/*
* If we know that the inode will need to be revalidated immediately,
* then don't create a new dentry for it. We'll end up doing an on
* the wire call either way and this spares us an invalidation.
*/
if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
return;
dentry = d_alloc(parent, name); dentry = d_alloc(parent, name);
if (!dentry) if (!dentry)
return; return;
......
...@@ -197,7 +197,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses, ...@@ -197,7 +197,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
bytes_ret = 0; bytes_ret = 0;
} else } else
bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName, bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
256, nls_cp); CIFS_MAX_DOMAINNAME_LEN, nls_cp);
bcc_ptr += 2 * bytes_ret; bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null terminator */ bcc_ptr += 2; /* account for null terminator */
...@@ -255,8 +255,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, ...@@ -255,8 +255,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
/* copy domain */ /* copy domain */
if (ses->domainName != NULL) { if (ses->domainName != NULL) {
strncpy(bcc_ptr, ses->domainName, 256); strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
bcc_ptr += strnlen(ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
} /* else we will send a null domain name } /* else we will send a null domain name
so the server will default to its own domain */ so the server will default to its own domain */
*bcc_ptr = 0; *bcc_ptr = 0;
......
...@@ -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 = {
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
static int static int
smb2_crypto_shash_allocate(struct TCP_Server_Info *server) smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
{ {
int rc;
unsigned int size; unsigned int size;
if (server->secmech.sdeschmacsha256 != NULL) if (server->secmech.sdeschmacsha256 != NULL)
...@@ -50,7 +51,9 @@ smb2_crypto_shash_allocate(struct TCP_Server_Info *server) ...@@ -50,7 +51,9 @@ smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0); server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
if (IS_ERR(server->secmech.hmacsha256)) { if (IS_ERR(server->secmech.hmacsha256)) {
cifs_dbg(VFS, "could not allocate crypto hmacsha256\n"); cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
return PTR_ERR(server->secmech.hmacsha256); rc = PTR_ERR(server->secmech.hmacsha256);
server->secmech.hmacsha256 = NULL;
return rc;
} }
size = sizeof(struct shash_desc) + size = sizeof(struct shash_desc) +
...@@ -87,7 +90,9 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) ...@@ -87,7 +90,9 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
server->secmech.sdeschmacsha256 = NULL; server->secmech.sdeschmacsha256 = NULL;
crypto_free_shash(server->secmech.hmacsha256); crypto_free_shash(server->secmech.hmacsha256);
server->secmech.hmacsha256 = NULL; server->secmech.hmacsha256 = NULL;
return PTR_ERR(server->secmech.cmacaes); rc = PTR_ERR(server->secmech.cmacaes);
server->secmech.cmacaes = NULL;
return rc;
} }
size = sizeof(struct shash_desc) + size = sizeof(struct shash_desc) +
......
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