Commit 5e9ae94e authored by Vitaly Lipatov's avatar Vitaly Lipatov

update 4.1 up to v4.1.49

parent 4f75e546
...@@ -46,6 +46,9 @@ ...@@ -46,6 +46,9 @@
#define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */ #define CIFS_MOUNT_CIFS_BACKUPUID 0x200000 /* backup intent bit for a user */
#define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */ #define CIFS_MOUNT_CIFS_BACKUPGID 0x400000 /* backup intent bit for a group */
#define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */ #define CIFS_MOUNT_MAP_SFM_CHR 0x800000 /* SFM/MAC mapping for illegal chars */
#define CIFS_MOUNT_USE_PREFIX_PATH 0x1000000 /* make subpath with unaccessible
* root mountable
*/
struct cifs_sb_info { struct cifs_sb_info {
struct rb_root tlink_tree; struct rb_root tlink_tree;
...@@ -67,5 +70,6 @@ struct cifs_sb_info { ...@@ -67,5 +70,6 @@ struct cifs_sb_info {
struct backing_dev_info bdi; struct backing_dev_info bdi;
struct delayed_work prune_tlinks; struct delayed_work prune_tlinks;
struct rcu_head rcu; struct rcu_head rcu;
char *prepath;
}; };
#endif /* _CIFS_FS_SB_H */ #endif /* _CIFS_FS_SB_H */
...@@ -83,6 +83,9 @@ convert_sfm_char(const __u16 src_char, char *target) ...@@ -83,6 +83,9 @@ convert_sfm_char(const __u16 src_char, char *target)
case SFM_COLON: case SFM_COLON:
*target = ':'; *target = ':';
break; break;
case SFM_DOUBLEQUOTE:
*target = '"';
break;
case SFM_ASTERISK: case SFM_ASTERISK:
*target = '*'; *target = '*';
break; break;
...@@ -101,6 +104,12 @@ convert_sfm_char(const __u16 src_char, char *target) ...@@ -101,6 +104,12 @@ convert_sfm_char(const __u16 src_char, char *target)
case SFM_SLASH: case SFM_SLASH:
*target = '\\'; *target = '\\';
break; break;
case SFM_SPACE:
*target = ' ';
break;
case SFM_PERIOD:
*target = '.';
break;
default: default:
return false; return false;
} }
...@@ -404,7 +413,7 @@ static __le16 convert_to_sfu_char(char src_char) ...@@ -404,7 +413,7 @@ static __le16 convert_to_sfu_char(char src_char)
return dest_char; return dest_char;
} }
static __le16 convert_to_sfm_char(char src_char) static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
{ {
__le16 dest_char; __le16 dest_char;
...@@ -412,6 +421,9 @@ static __le16 convert_to_sfm_char(char src_char) ...@@ -412,6 +421,9 @@ static __le16 convert_to_sfm_char(char src_char)
case ':': case ':':
dest_char = cpu_to_le16(SFM_COLON); dest_char = cpu_to_le16(SFM_COLON);
break; break;
case '"':
dest_char = cpu_to_le16(SFM_DOUBLEQUOTE);
break;
case '*': case '*':
dest_char = cpu_to_le16(SFM_ASTERISK); dest_char = cpu_to_le16(SFM_ASTERISK);
break; break;
...@@ -427,6 +439,18 @@ static __le16 convert_to_sfm_char(char src_char) ...@@ -427,6 +439,18 @@ static __le16 convert_to_sfm_char(char src_char)
case '|': case '|':
dest_char = cpu_to_le16(SFM_PIPE); dest_char = cpu_to_le16(SFM_PIPE);
break; break;
case '.':
if (end_of_string)
dest_char = cpu_to_le16(SFM_PERIOD);
else
dest_char = 0;
break;
case ' ':
if (end_of_string)
dest_char = cpu_to_le16(SFM_SPACE);
else
dest_char = 0;
break;
default: default:
dest_char = 0; dest_char = 0;
} }
...@@ -469,9 +493,16 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen, ...@@ -469,9 +493,16 @@ cifsConvertToUTF16(__le16 *target, const char *source, int srclen,
/* see if we must remap this char */ /* see if we must remap this char */
if (map_chars == SFU_MAP_UNI_RSVD) if (map_chars == SFU_MAP_UNI_RSVD)
dst_char = convert_to_sfu_char(src_char); dst_char = convert_to_sfu_char(src_char);
else if (map_chars == SFM_MAP_UNI_RSVD) else if (map_chars == SFM_MAP_UNI_RSVD) {
dst_char = convert_to_sfm_char(src_char); bool end_of_string;
else
if (i == srclen - 1)
end_of_string = true;
else
end_of_string = false;
dst_char = convert_to_sfm_char(src_char, end_of_string);
} else
dst_char = 0; dst_char = 0;
/* /*
* FIXME: We can not handle remapping backslash (UNI_SLASH) * FIXME: We can not handle remapping backslash (UNI_SLASH)
......
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
* not conflict (although almost does) with the mapping above. * not conflict (although almost does) with the mapping above.
*/ */
#define SFM_DOUBLEQUOTE ((__u16) 0xF020)
#define SFM_ASTERISK ((__u16) 0xF021) #define SFM_ASTERISK ((__u16) 0xF021)
#define SFM_QUESTION ((__u16) 0xF025) #define SFM_QUESTION ((__u16) 0xF025)
#define SFM_COLON ((__u16) 0xF022) #define SFM_COLON ((__u16) 0xF022)
...@@ -64,6 +65,8 @@ ...@@ -64,6 +65,8 @@
#define SFM_LESSTHAN ((__u16) 0xF023) #define SFM_LESSTHAN ((__u16) 0xF023)
#define SFM_PIPE ((__u16) 0xF027) #define SFM_PIPE ((__u16) 0xF027)
#define SFM_SLASH ((__u16) 0xF026) #define SFM_SLASH ((__u16) 0xF026)
#define SFM_SPACE ((__u16) 0xF028)
#define SFM_PERIOD ((__u16) 0xF029)
/* /*
* Mapping mechanism to use when one of the seven reserved characters is * Mapping mechanism to use when one of the seven reserved characters is
......
...@@ -731,24 +731,26 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -731,24 +731,26 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
memcpy(ses->auth_key.response + baselen, tiblob, tilen); memcpy(ses->auth_key.response + baselen, tiblob, tilen);
mutex_lock(&ses->server->srv_mutex);
rc = crypto_hmacmd5_alloc(ses->server); rc = crypto_hmacmd5_alloc(ses->server);
if (rc) { if (rc) {
cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc); cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
goto setup_ntlmv2_rsp_ret; goto unlock;
} }
/* calculate ntlmv2_hash */ /* calculate ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp); rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
if (rc) { if (rc) {
cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc); cifs_dbg(VFS, "could not get v2 hash rc %d\n", rc);
goto setup_ntlmv2_rsp_ret; goto unlock;
} }
/* calculate first part of the client response (CR1) */ /* calculate first part of the client response (CR1) */
rc = CalcNTLMv2_response(ses, ntlmv2_hash); rc = CalcNTLMv2_response(ses, ntlmv2_hash);
if (rc) { if (rc) {
cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc); cifs_dbg(VFS, "Could not calculate CR1 rc: %d\n", rc);
goto setup_ntlmv2_rsp_ret; goto unlock;
} }
/* now calculate the session key for NTLMv2 */ /* now calculate the session key for NTLMv2 */
...@@ -757,13 +759,13 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -757,13 +759,13 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n", cifs_dbg(VFS, "%s: Could not set NTLMV2 Hash as a key\n",
__func__); __func__);
goto setup_ntlmv2_rsp_ret; goto unlock;
} }
rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__); cifs_dbg(VFS, "%s: Could not init hmacmd5\n", __func__);
goto setup_ntlmv2_rsp_ret; goto unlock;
} }
rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash,
...@@ -771,7 +773,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -771,7 +773,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
CIFS_HMAC_MD5_HASH_SIZE); CIFS_HMAC_MD5_HASH_SIZE);
if (rc) { if (rc) {
cifs_dbg(VFS, "%s: Could not update with response\n", __func__); cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
goto setup_ntlmv2_rsp_ret; goto unlock;
} }
rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
...@@ -779,6 +781,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp) ...@@ -779,6 +781,8 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
if (rc) if (rc)
cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__);
unlock:
mutex_unlock(&ses->server->srv_mutex);
setup_ntlmv2_rsp_ret: setup_ntlmv2_rsp_ret:
kfree(tiblob); kfree(tiblob);
......
...@@ -682,6 +682,14 @@ cifs_do_mount(struct file_system_type *fs_type, ...@@ -682,6 +682,14 @@ cifs_do_mount(struct file_system_type *fs_type,
goto out_cifs_sb; goto out_cifs_sb;
} }
if (volume_info->prepath) {
cifs_sb->prepath = kstrdup(volume_info->prepath, GFP_KERNEL);
if (cifs_sb->prepath == NULL) {
root = ERR_PTR(-ENOMEM);
goto out_cifs_sb;
}
}
cifs_setup_cifs_sb(volume_info, cifs_sb); cifs_setup_cifs_sb(volume_info, cifs_sb);
rc = cifs_mount(cifs_sb, volume_info); rc = cifs_mount(cifs_sb, volume_info);
...@@ -720,7 +728,11 @@ cifs_do_mount(struct file_system_type *fs_type, ...@@ -720,7 +728,11 @@ cifs_do_mount(struct file_system_type *fs_type,
sb->s_flags |= MS_ACTIVE; sb->s_flags |= MS_ACTIVE;
} }
root = cifs_get_root(volume_info, sb); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
root = dget(sb->s_root);
else
root = cifs_get_root(volume_info, sb);
if (IS_ERR(root)) if (IS_ERR(root))
goto out_super; goto out_super;
......
...@@ -615,6 +615,8 @@ struct TCP_Server_Info { ...@@ -615,6 +615,8 @@ struct TCP_Server_Info {
#ifdef CONFIG_CIFS_SMB2 #ifdef CONFIG_CIFS_SMB2
unsigned int max_read; unsigned int max_read;
unsigned int max_write; unsigned int max_write;
struct delayed_work reconnect; /* reconnect workqueue job */
struct mutex reconnect_mutex; /* prevent simultaneous reconnects */
#endif /* CONFIG_CIFS_SMB2 */ #endif /* CONFIG_CIFS_SMB2 */
}; };
...@@ -814,6 +816,7 @@ cap_unix(struct cifs_ses *ses) ...@@ -814,6 +816,7 @@ cap_unix(struct cifs_ses *ses)
struct cifs_tcon { struct cifs_tcon {
struct list_head tcon_list; struct list_head tcon_list;
int tc_count; int tc_count;
struct list_head rlist; /* reconnect list */
struct list_head openFileList; struct list_head openFileList;
struct cifs_ses *ses; /* pointer to session associated with */ struct cifs_ses *ses; /* pointer to session associated with */
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
...@@ -888,7 +891,6 @@ struct cifs_tcon { ...@@ -888,7 +891,6 @@ struct cifs_tcon {
bool need_reconnect:1; /* connection reset, tid now invalid */ bool need_reconnect:1; /* connection reset, tid now invalid */
#ifdef CONFIG_CIFS_SMB2 #ifdef CONFIG_CIFS_SMB2
bool print:1; /* set if connection to printer share */ bool print:1; /* set if connection to printer share */
bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
__le32 capabilities; __le32 capabilities;
__u32 share_flags; __u32 share_flags;
__u32 maximal_access; __u32 maximal_access;
......
...@@ -207,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid, ...@@ -207,6 +207,9 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink, struct tcon_link *tlink,
struct cifs_pending_open *open); struct cifs_pending_open *open);
extern void cifs_del_pending_open(struct cifs_pending_open *open); extern void cifs_del_pending_open(struct cifs_pending_open *open);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect);
extern void cifs_put_tcon(struct cifs_tcon *tcon);
#if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
extern void cifs_dfs_release_automount_timer(void); extern void cifs_dfs_release_automount_timer(void);
......
...@@ -716,6 +716,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server) ...@@ -716,6 +716,9 @@ CIFSSMBEcho(struct TCP_Server_Info *server)
if (rc) if (rc)
return rc; return rc;
if (server->capabilities & CAP_UNICODE)
smb->hdr.Flags2 |= SMBFLG2_UNICODE;
/* set up echo request */ /* set up echo request */
smb->hdr.Tid = 0xffff; smb->hdr.Tid = 0xffff;
smb->hdr.WordCount = 1; smb->hdr.WordCount = 1;
......
...@@ -52,6 +52,9 @@ ...@@ -52,6 +52,9 @@
#include "nterr.h" #include "nterr.h"
#include "rfc1002pdu.h" #include "rfc1002pdu.h"
#include "fscache.h" #include "fscache.h"
#ifdef CONFIG_CIFS_SMB2
#include "smb2proto.h"
#endif
#define CIFS_PORT 445 #define CIFS_PORT 445
#define RFC1001_PORT 139 #define RFC1001_PORT 139
...@@ -399,6 +402,9 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -399,6 +402,9 @@ cifs_reconnect(struct TCP_Server_Info *server)
} }
} while (server->tcpStatus == CifsNeedReconnect); } while (server->tcpStatus == CifsNeedReconnect);
if (server->tcpStatus == CifsNeedNegotiate)
mod_delayed_work(cifsiod_wq, &server->echo, 0);
return rc; return rc;
} }
...@@ -408,16 +414,27 @@ cifs_echo_request(struct work_struct *work) ...@@ -408,16 +414,27 @@ cifs_echo_request(struct work_struct *work)
int rc; int rc;
struct TCP_Server_Info *server = container_of(work, struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, echo.work); struct TCP_Server_Info, echo.work);
unsigned long echo_interval;
/*
* If we need to renegotiate, set echo interval to zero to
* immediately call echo service where we can renegotiate.
*/
if (server->tcpStatus == CifsNeedNegotiate)
echo_interval = 0;
else
echo_interval = SMB_ECHO_INTERVAL;
/* /*
* We cannot send an echo if it is disabled or until the * We cannot send an echo if it is disabled.
* NEGOTIATE_PROTOCOL request is done, which is indicated by * Also, no need to ping if we got a response recently.
* server->ops->need_neg() == true. Also, no need to ping if
* we got a response recently.
*/ */
if (!server->ops->need_neg || server->ops->need_neg(server) ||
if (server->tcpStatus == CifsNeedReconnect ||
server->tcpStatus == CifsExiting ||
server->tcpStatus == CifsNew ||
(server->ops->can_echo && !server->ops->can_echo(server)) || (server->ops->can_echo && !server->ops->can_echo(server)) ||
time_before(jiffies, server->lstrp + SMB_ECHO_INTERVAL - HZ)) time_before(jiffies, server->lstrp + echo_interval - HZ))
goto requeue_echo; goto requeue_echo;
rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS; rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
...@@ -2072,8 +2089,8 @@ cifs_find_tcp_session(struct smb_vol *vol) ...@@ -2072,8 +2089,8 @@ cifs_find_tcp_session(struct smb_vol *vol)
return NULL; return NULL;
} }
static void void
cifs_put_tcp_session(struct TCP_Server_Info *server) cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
{ {
struct task_struct *task; struct task_struct *task;
...@@ -2090,6 +2107,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) ...@@ -2090,6 +2107,19 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
cancel_delayed_work_sync(&server->echo); cancel_delayed_work_sync(&server->echo);
#ifdef CONFIG_CIFS_SMB2
if (from_reconnect)
/*
* Avoid deadlock here: reconnect work calls
* cifs_put_tcp_session() at its end. Need to be sure
* that reconnect work does nothing with server pointer after
* that step.
*/
cancel_delayed_work(&server->reconnect);
else
cancel_delayed_work_sync(&server->reconnect);
#endif
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting; server->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
...@@ -2154,6 +2184,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info) ...@@ -2154,6 +2184,10 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
INIT_LIST_HEAD(&tcp_ses->smb_ses_list); INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
#ifdef CONFIG_CIFS_SMB2
INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
mutex_init(&tcp_ses->reconnect_mutex);
#endif
memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
sizeof(tcp_ses->srcaddr)); sizeof(tcp_ses->srcaddr));
memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr, memcpy(&tcp_ses->dstaddr, &volume_info->dstaddr,
...@@ -2306,7 +2340,7 @@ cifs_put_smb_ses(struct cifs_ses *ses) ...@@ -2306,7 +2340,7 @@ cifs_put_smb_ses(struct cifs_ses *ses)
spin_unlock(&cifs_tcp_ses_lock); spin_unlock(&cifs_tcp_ses_lock);
sesInfoFree(ses); sesInfoFree(ses);
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
} }
#ifdef CONFIG_KEYS #ifdef CONFIG_KEYS
...@@ -2479,7 +2513,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) ...@@ -2479,7 +2513,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
mutex_unlock(&ses->session_mutex); mutex_unlock(&ses->session_mutex);
/* existing SMB ses has a server reference already */ /* existing SMB ses has a server reference already */
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
free_xid(xid); free_xid(xid);
return ses; return ses;
} }
...@@ -2569,7 +2603,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc) ...@@ -2569,7 +2603,7 @@ cifs_find_tcon(struct cifs_ses *ses, const char *unc)
return NULL; return NULL;
} }
static void void
cifs_put_tcon(struct cifs_tcon *tcon) cifs_put_tcon(struct cifs_tcon *tcon)
{ {
unsigned int xid; unsigned int xid;
...@@ -3439,6 +3473,44 @@ cifs_get_volume_info(char *mount_data, const char *devname) ...@@ -3439,6 +3473,44 @@ cifs_get_volume_info(char *mount_data, const char *devname)
return volume_info; return volume_info;
} }
static int
cifs_are_all_path_components_accessible(struct TCP_Server_Info *server,
unsigned int xid,
struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
char *full_path)
{
int rc;
char *s;
char sep, tmp;
sep = CIFS_DIR_SEP(cifs_sb);
s = full_path;
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb, "");
while (rc == 0) {
/* skip separators */
while (*s == sep)
s++;
if (!*s)
break;
/* next separator */
while (*s && *s != sep)
s++;
/*
* temporarily null-terminate the path at the end of
* the current component
*/
tmp = *s;
*s = 0;
rc = server->ops->is_path_accessible(xid, tcon, cifs_sb,
full_path);
*s = tmp;
}
return rc;
}
int int
cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info)
{ {
...@@ -3565,6 +3637,16 @@ remote_path_check: ...@@ -3565,6 +3637,16 @@ remote_path_check:
kfree(full_path); kfree(full_path);
goto mount_fail_check; goto mount_fail_check;
} }
rc = cifs_are_all_path_components_accessible(server,
xid, tcon, cifs_sb,
full_path);
if (rc != 0) {
cifs_dbg(VFS, "cannot query dirs between root and final path, "
"enabling CIFS_MOUNT_USE_PREFIX_PATH\n");
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_USE_PREFIX_PATH;
rc = 0;
}
kfree(full_path); kfree(full_path);
} }
...@@ -3628,7 +3710,7 @@ mount_fail_check: ...@@ -3628,7 +3710,7 @@ mount_fail_check:
else if (ses) else if (ses)
cifs_put_smb_ses(ses); cifs_put_smb_ses(ses);
else else
cifs_put_tcp_session(server); cifs_put_tcp_session(server, 0);
bdi_destroy(&cifs_sb->bdi); bdi_destroy(&cifs_sb->bdi);
} }
...@@ -3834,6 +3916,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb) ...@@ -3834,6 +3916,7 @@ cifs_umount(struct cifs_sb_info *cifs_sb)
bdi_destroy(&cifs_sb->bdi); bdi_destroy(&cifs_sb->bdi);
kfree(cifs_sb->mountdata); kfree(cifs_sb->mountdata);
kfree(cifs_sb->prepath);
call_rcu(&cifs_sb->rcu, delayed_free); call_rcu(&cifs_sb->rcu, delayed_free);
} }
...@@ -3879,6 +3962,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses, ...@@ -3879,6 +3962,14 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n", cifs_dbg(FYI, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d\n",
server->sec_mode, server->capabilities, server->timeAdj); server->sec_mode, server->capabilities, server->timeAdj);
if (ses->auth_key.response) {
cifs_dbg(VFS, "Free previous auth_key.response = %p\n",
ses->auth_key.response);
kfree(ses->auth_key.response);
ses->auth_key.response = NULL;
ses->auth_key.len = 0;
}
if (server->ops->sess_setup) if (server->ops->sess_setup)
rc = server->ops->sess_setup(xid, ses, nls_info); rc = server->ops->sess_setup(xid, ses, nls_info);
...@@ -3938,7 +4029,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) ...@@ -3938,7 +4029,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
if (IS_ERR(ses)) { if (IS_ERR(ses)) {
tcon = (struct cifs_tcon *)ses; tcon = (struct cifs_tcon *)ses;
cifs_put_tcp_session(master_tcon->ses->server); cifs_put_tcp_session(master_tcon->ses->server, 0);
goto out; goto out;
} }
......
...@@ -84,6 +84,7 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -84,6 +84,7 @@ build_path_from_dentry(struct dentry *direntry)
struct dentry *temp; struct dentry *temp;
int namelen; int namelen;
int dfsplen; int dfsplen;
int pplen = 0;
char *full_path; char *full_path;
char dirsep; char dirsep;
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
...@@ -95,8 +96,12 @@ build_path_from_dentry(struct dentry *direntry) ...@@ -95,8 +96,12 @@ build_path_from_dentry(struct dentry *direntry)
dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1); dfsplen = strnlen(tcon->treeName, MAX_TREE_SIZE + 1);
else else
dfsplen = 0; dfsplen = 0;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0;
cifs_bp_rename_retry: cifs_bp_rename_retry:
namelen = dfsplen; namelen = dfsplen + pplen;
seq = read_seqbegin(&rename_lock); seq = read_seqbegin(&rename_lock);
rcu_read_lock(); rcu_read_lock();
for (temp = direntry; !IS_ROOT(temp);) { for (temp = direntry; !IS_ROOT(temp);) {
...@@ -137,7 +142,7 @@ cifs_bp_rename_retry: ...@@ -137,7 +142,7 @@ cifs_bp_rename_retry:
} }
} }
rcu_read_unlock(); rcu_read_unlock();
if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) { if (namelen != dfsplen + pplen || read_seqretry(&rename_lock, seq)) {
cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n", cifs_dbg(FYI, "did not end path lookup where expected. namelen=%ddfsplen=%d\n",
namelen, dfsplen); namelen, dfsplen);
/* presumably this is only possible if racing with a rename /* presumably this is only possible if racing with a rename
...@@ -153,6 +158,17 @@ cifs_bp_rename_retry: ...@@ -153,6 +158,17 @@ cifs_bp_rename_retry:
those safely to '/' if any are found in the middle of the prepath */ those safely to '/' if any are found in the middle of the prepath */
/* BB test paths to Windows with '/' in the midst of prepath */ /* BB test paths to Windows with '/' in the midst of prepath */
if (pplen) {
int i;
cifs_dbg(FYI, "using cifs_sb prepath <%s>\n", cifs_sb->prepath);
memcpy(full_path+dfsplen+1, cifs_sb->prepath, pplen-1);
full_path[dfsplen] = '\\';
for (i = 0; i < pplen-1; i++)
if (full_path[dfsplen+1+i] == '/')
full_path[dfsplen+1+i] = CIFS_DIR_SEP(cifs_sb);
}
if (dfsplen) { if (dfsplen) {
strncpy(full_path, tcon->treeName, dfsplen); strncpy(full_path, tcon->treeName, dfsplen);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
...@@ -167,15 +183,21 @@ cifs_bp_rename_retry: ...@@ -167,15 +183,21 @@ cifs_bp_rename_retry:
} }
/* /*
* Don't allow path components longer than the server max.
* Don't allow the separator character in a path component. * Don't allow the separator character in a path component.
* The VFS will not allow "/", but "\" is allowed by posix. * The VFS will not allow "/", but "\" is allowed by posix.
*/ */
static int static int
check_name(struct dentry *direntry) check_name(struct dentry *direntry, struct cifs_tcon *tcon)
{ {
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
int i; int i;
if (unlikely(tcon->fsAttrInfo.MaxPathNameComponentLength &&
direntry->d_name.len >
le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength)))
return -ENAMETOOLONG;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) { if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
for (i = 0; i < direntry->d_name.len; i++) { for (i = 0; i < direntry->d_name.len; i++) {
if (direntry->d_name.name[i] == '\\') { if (direntry->d_name.name[i] == '\\') {
...@@ -231,6 +253,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, ...@@ -231,6 +253,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
goto cifs_create_get_file_info; goto cifs_create_get_file_info;
} }
if (S_ISDIR(newinode->i_mode)) {
CIFSSMBClose(xid, tcon, fid->netfid);
iput(newinode);
rc = -EISDIR;
goto out;
}
if (!S_ISREG(newinode->i_mode)) { if (!S_ISREG(newinode->i_mode)) {
/* /*
* The server may allow us to open things like * The server may allow us to open things like
...@@ -404,10 +433,14 @@ cifs_create_set_dentry: ...@@ -404,10 +433,14 @@ cifs_create_set_dentry:
if (rc != 0) { if (rc != 0) {
cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n", cifs_dbg(FYI, "Create worked, get_inode_info failed rc = %d\n",
rc); rc);
if (server->ops->close) goto out_err;
server->ops->close(xid, tcon, fid);
goto out;
} }
if (S_ISDIR(newinode->i_mode)) {
rc = -EISDIR;
goto out_err;
}
d_drop(direntry); d_drop(direntry);
d_add(direntry, newinode); d_add(direntry, newinode);
...@@ -415,6 +448,13 @@ out: ...@@ -415,6 +448,13 @@ out:
kfree(buf); kfree(buf);
kfree(full_path); kfree(full_path);
return rc; return rc;
out_err:
if (server->ops->close)
server->ops->close(xid, tcon, fid);
if (newinode)
iput(newinode);
goto out;
} }
int int
...@@ -460,10 +500,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -460,10 +500,6 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
return finish_no_open(file, res); return finish_no_open(file, res);
} }
rc = check_name(direntry);
if (rc)
return rc;
xid = get_xid(); xid = get_xid();
cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n", cifs_dbg(FYI, "parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
...@@ -476,6 +512,11 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, ...@@ -476,6 +512,11 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
} }
tcon = tlink_tcon(tlink); tcon = tlink_tcon(tlink);
rc = check_name(direntry, tcon);
if (rc)
goto out;
server = tcon->ses->server; server = tcon->ses->server;
if (server->ops->new_lease_key) if (server->ops->new_lease_key)
...@@ -736,7 +777,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -736,7 +777,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
} }
pTcon = tlink_tcon(tlink); pTcon = tlink_tcon(tlink);
rc = check_name(direntry); rc = check_name(direntry, pTcon);
if (rc) if (rc)
goto lookup_out; goto lookup_out;
......
...@@ -226,6 +226,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, ...@@ -226,6 +226,13 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
if (backup_cred(cifs_sb)) if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT; create_options |= CREATE_OPEN_BACKUP_INTENT;
/* O_SYNC also has bit for O_DSYNC so following check picks up either */
if (f_flags & O_SYNC)
create_options |= CREATE_WRITE_THROUGH;
if (f_flags & O_DIRECT)
create_options |= CREATE_NO_BUFFER;
oparms.tcon = tcon; oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb; oparms.cifs_sb = cifs_sb;
oparms.desired_access = desired_access; oparms.desired_access = desired_access;
...@@ -2543,7 +2550,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, ...@@ -2543,7 +2550,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from,
wdata->credits = credits; wdata->credits = credits;
if (!wdata->cfile->invalidHandle || if (!wdata->cfile->invalidHandle ||
!cifs_reopen_file(wdata->cfile, false)) !(rc = cifs_reopen_file(wdata->cfile, false)))
rc = server->ops->async_writev(wdata, rc = server->ops->async_writev(wdata,
cifs_uncached_writedata_release); cifs_uncached_writedata_release);
if (rc) { if (rc) {
...@@ -2956,7 +2963,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, ...@@ -2956,7 +2963,7 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file,
rdata->credits = credits; rdata->credits = credits;
if (!rdata->cfile->invalidHandle || if (!rdata->cfile->invalidHandle ||
!cifs_reopen_file(rdata->cfile, true)) !(rc = cifs_reopen_file(rdata->cfile, true)))
rc = server->ops->async_readv(rdata); rc = server->ops->async_readv(rdata);
error: error:
if (rc) { if (rc) {
...@@ -3542,7 +3549,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, ...@@ -3542,7 +3549,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
} }
if (!rdata->cfile->invalidHandle || if (!rdata->cfile->invalidHandle ||
!cifs_reopen_file(rdata->cfile, true)) !(rc = cifs_reopen_file(rdata->cfile, true)))
rc = server->ops->async_readv(rdata); rc = server->ops->async_readv(rdata);
if (rc) { if (rc) {
add_credits_and_wake_if(server, rdata->credits, 0); add_credits_and_wake_if(server, rdata->credits, 0);
......
...@@ -983,10 +983,26 @@ struct inode *cifs_root_iget(struct super_block *sb) ...@@ -983,10 +983,26 @@ struct inode *cifs_root_iget(struct super_block *sb)
struct inode *inode = NULL; struct inode *inode = NULL;
long rc; long rc;
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
char *path = NULL;
int len;
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH)
&& cifs_sb->prepath) {
len = strlen(cifs_sb->prepath);
path = kzalloc(len + 2 /* leading sep + null */, GFP_KERNEL);
if (path == NULL)
return ERR_PTR(-ENOMEM);
path[0] = '/';
memcpy(path+1, cifs_sb->prepath, len);
} else {
path = kstrdup("", GFP_KERNEL);
if (path == NULL)
return ERR_PTR(-ENOMEM);
}
xid = get_xid(); xid = get_xid();
if (tcon->unix_ext) { if (tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&inode, "", sb, xid); rc = cifs_get_inode_info_unix(&inode, path, sb, xid);
/* some servers mistakenly claim POSIX support */ /* some servers mistakenly claim POSIX support */
if (rc != -EOPNOTSUPP) if (rc != -EOPNOTSUPP)
goto iget_no_retry; goto iget_no_retry;
...@@ -994,7 +1010,8 @@ struct inode *cifs_root_iget(struct super_block *sb) ...@@ -994,7 +1010,8 @@ struct inode *cifs_root_iget(struct super_block *sb)
tcon->unix_ext = false; tcon->unix_ext = false;
} }
rc = cifs_get_inode_info(&inode, "", NULL, sb, xid, NULL); convert_delimiter(path, CIFS_DIR_SEP(cifs_sb));
rc = cifs_get_inode_info(&inode, path, NULL, sb, xid, NULL);
iget_no_retry: iget_no_retry:
if (!inode) { if (!inode) {
...@@ -1023,6 +1040,7 @@ iget_no_retry: ...@@ -1023,6 +1040,7 @@ iget_no_retry:
} }
out: out:
kfree(path);
/* can not call macro free_xid here since in a void func /* can not call macro free_xid here since in a void func
* TODO: This is no longer true * TODO: This is no longer true
*/ */
...@@ -2121,7 +2139,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) ...@@ -2121,7 +2139,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE; attrs->ia_valid |= ATTR_FORCE;
rc = inode_change_ok(inode, attrs); rc = setattr_prepare(direntry, attrs);
if (rc < 0) if (rc < 0)
goto out; goto out;
...@@ -2261,7 +2279,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2261,7 +2279,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
attrs->ia_valid |= ATTR_FORCE; attrs->ia_valid |= ATTR_FORCE;
rc = inode_change_ok(inode, attrs); rc = setattr_prepare(direntry, attrs);
if (rc < 0) { if (rc < 0) {
free_xid(xid); free_xid(xid);
return rc; return rc;
......
...@@ -133,6 +133,6 @@ typedef struct _AUTHENTICATE_MESSAGE { ...@@ -133,6 +133,6 @@ typedef struct _AUTHENTICATE_MESSAGE {
int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses); int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, struct cifs_ses *ses);
void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses); void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, struct cifs_ses *ses);
int build_ntlmssp_auth_blob(unsigned char *pbuffer, u16 *buflen, int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
const struct nls_table *nls_cp); const struct nls_table *nls_cp);
...@@ -364,19 +364,43 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, ...@@ -364,19 +364,43 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
sec_blob->DomainName.MaximumLength = 0; sec_blob->DomainName.MaximumLength = 0;
} }
/* We do not malloc the blob, it is passed in pbuffer, because its static int size_of_ntlmssp_blob(struct cifs_ses *ses)
maximum possible size is fixed and small, making this approach cleaner. {
This function returns the length of the data in the blob */ int sz = sizeof(AUTHENTICATE_MESSAGE) + ses->auth_key.len
int build_ntlmssp_auth_blob(unsigned char *pbuffer, - CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2;
if (ses->domainName)
sz += 2 * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
else
sz += 2;
if (ses->user_name)
sz += 2 * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
else
sz += 2;
return sz;
}
int build_ntlmssp_auth_blob(unsigned char **pbuffer,
u16 *buflen, u16 *buflen,
struct cifs_ses *ses, struct cifs_ses *ses,
const struct nls_table *nls_cp) const struct nls_table *nls_cp)
{ {
int rc; int rc;
AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; AUTHENTICATE_MESSAGE *sec_blob;
__u32 flags; __u32 flags;
unsigned char *tmp; unsigned char *tmp;
rc = setup_ntlmv2_rsp(ses, nls_cp);
if (rc) {
cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
*buflen = 0;
goto setup_ntlmv2_ret;
}
*pbuffer = kmalloc(size_of_ntlmssp_blob(ses), GFP_KERNEL);
sec_blob = (AUTHENTICATE_MESSAGE *)*pbuffer;
memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
sec_blob->MessageType = NtLmAuthenticate; sec_blob->MessageType = NtLmAuthenticate;
...@@ -391,7 +415,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -391,7 +415,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
flags |= NTLMSSP_NEGOTIATE_KEY_XCH; flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
} }
tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE);
sec_blob->NegotiateFlags = cpu_to_le32(flags); sec_blob->NegotiateFlags = cpu_to_le32(flags);
sec_blob->LmChallengeResponse.BufferOffset = sec_blob->LmChallengeResponse.BufferOffset =
...@@ -399,13 +423,9 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -399,13 +423,9 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
sec_blob->LmChallengeResponse.Length = 0; sec_blob->LmChallengeResponse.Length = 0;
sec_blob->LmChallengeResponse.MaximumLength = 0; sec_blob->LmChallengeResponse.MaximumLength = 0;
sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->NtChallengeResponse.BufferOffset =
cpu_to_le32(tmp - *pbuffer);
if (ses->user_name != NULL) { if (ses->user_name != NULL) {
rc = setup_ntlmv2_rsp(ses, nls_cp);
if (rc) {
cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc);
goto setup_ntlmv2_ret;
}
memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE,
ses->auth_key.len - CIFS_SESS_KEY_SIZE); ses->auth_key.len - CIFS_SESS_KEY_SIZE);
tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE; tmp += ses->auth_key.len - CIFS_SESS_KEY_SIZE;
...@@ -423,7 +443,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -423,7 +443,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
} }
if (ses->domainName == NULL) { if (ses->domainName == NULL) {
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->DomainName.Length = 0; sec_blob->DomainName.Length = 0;
sec_blob->DomainName.MaximumLength = 0; sec_blob->DomainName.MaximumLength = 0;
tmp += 2; tmp += 2;
...@@ -432,14 +452,14 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -432,14 +452,14 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName, len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName,
CIFS_MAX_USERNAME_LEN, nls_cp); CIFS_MAX_USERNAME_LEN, nls_cp);
len *= 2; /* unicode is 2 bytes each */ len *= 2; /* unicode is 2 bytes each */
sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->DomainName.Length = cpu_to_le16(len); sec_blob->DomainName.Length = cpu_to_le16(len);
sec_blob->DomainName.MaximumLength = cpu_to_le16(len); sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
tmp += len; tmp += len;
} }
if (ses->user_name == NULL) { if (ses->user_name == NULL) {
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->UserName.Length = 0; sec_blob->UserName.Length = 0;
sec_blob->UserName.MaximumLength = 0; sec_blob->UserName.MaximumLength = 0;
tmp += 2; tmp += 2;
...@@ -448,13 +468,13 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -448,13 +468,13 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name, len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name,
CIFS_MAX_USERNAME_LEN, nls_cp); CIFS_MAX_USERNAME_LEN, nls_cp);
len *= 2; /* unicode is 2 bytes each */ len *= 2; /* unicode is 2 bytes each */
sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->UserName.Length = cpu_to_le16(len); sec_blob->UserName.Length = cpu_to_le16(len);
sec_blob->UserName.MaximumLength = cpu_to_le16(len); sec_blob->UserName.MaximumLength = cpu_to_le16(len);
tmp += len; tmp += len;
} }
sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->WorkstationName.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->WorkstationName.Length = 0; sec_blob->WorkstationName.Length = 0;
sec_blob->WorkstationName.MaximumLength = 0; sec_blob->WorkstationName.MaximumLength = 0;
tmp += 2; tmp += 2;
...@@ -463,19 +483,19 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer, ...@@ -463,19 +483,19 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
(ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC))
&& !calc_seckey(ses)) { && !calc_seckey(ses)) {
memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
sec_blob->SessionKey.MaximumLength = sec_blob->SessionKey.MaximumLength =
cpu_to_le16(CIFS_CPHTXT_SIZE); cpu_to_le16(CIFS_CPHTXT_SIZE);
tmp += CIFS_CPHTXT_SIZE; tmp += CIFS_CPHTXT_SIZE;
} else { } else {
sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - *pbuffer);
sec_blob->SessionKey.Length = 0; sec_blob->SessionKey.Length = 0;
sec_blob->SessionKey.MaximumLength = 0; sec_blob->SessionKey.MaximumLength = 0;
} }
*buflen = tmp - *pbuffer;
setup_ntlmv2_ret: setup_ntlmv2_ret:
*buflen = tmp - pbuffer;
return rc; return rc;
} }
...@@ -1266,7 +1286,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) ...@@ -1266,7 +1286,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
struct cifs_ses *ses = sess_data->ses; struct cifs_ses *ses = sess_data->ses;
__u16 bytes_remaining; __u16 bytes_remaining;
char *bcc_ptr; char *bcc_ptr;
char *ntlmsspblob = NULL; unsigned char *ntlmsspblob = NULL;
u16 blob_len; u16 blob_len;
cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n"); cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
...@@ -1279,19 +1299,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data) ...@@ -1279,19 +1299,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
/* Build security blob before we assemble the request */ /* Build security blob before we assemble the request */
pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
smb_buf = (struct smb_hdr *)pSMB; smb_buf = (struct smb_hdr *)pSMB;
/* rc = build_ntlmssp_auth_blob(&ntlmsspblob,
* 5 is an empirical value, large enough to hold
* authenticate message plus max 10 of av paris,
* domain, user, workstation names, flags, etc.
*/
ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE),
GFP_KERNEL);
if (!ntlmsspblob) {
rc = -ENOMEM;
goto out;
}
rc = build_ntlmssp_auth_blob(ntlmsspblob,
&blob_len, ses, sess_data->nls_cp); &blob_len, ses, sess_data->nls_cp);
if (rc) if (rc)
goto out_free_ntlmsspblob; goto out_free_ntlmsspblob;
......
...@@ -851,8 +851,13 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -851,8 +851,13 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_fid *fid, __u16 search_flags, struct cifs_fid *fid, __u16 search_flags,
struct cifs_search_info *srch_inf) struct cifs_search_info *srch_inf)
{ {
return CIFSFindFirst(xid, tcon, path, cifs_sb, int rc;
&fid->netfid, search_flags, srch_inf, true);
rc = CIFSFindFirst(xid, tcon, path, cifs_sb,
&fid->netfid, search_flags, srch_inf, true);
if (rc)
cifs_dbg(FYI, "find first failed=%d\n", rc);
return rc;
} }
static int static int
...@@ -1018,6 +1023,15 @@ cifs_dir_needs_close(struct cifsFileInfo *cfile) ...@@ -1018,6 +1023,15 @@ cifs_dir_needs_close(struct cifsFileInfo *cfile)
return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
} }
static bool
cifs_can_echo(struct TCP_Server_Info *server)
{
if (server->tcpStatus == CifsGood)
return true;
return false;
}
struct smb_version_operations smb1_operations = { struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel, .send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids, .compare_fids = cifs_compare_fids,
...@@ -1052,6 +1066,7 @@ struct smb_version_operations smb1_operations = { ...@@ -1052,6 +1066,7 @@ struct smb_version_operations smb1_operations = {
.get_dfs_refer = CIFSGetDFSRefer, .get_dfs_refer = CIFSGetDFSRefer,
.qfs_tcon = cifs_qfs_tcon, .qfs_tcon = cifs_qfs_tcon,
.is_path_accessible = cifs_is_path_accessible, .is_path_accessible = cifs_is_path_accessible,
.can_echo = cifs_can_echo,
.query_path_info = cifs_query_path_info, .query_path_info = cifs_query_path_info,
.query_file_info = cifs_query_file_info, .query_file_info = cifs_query_file_info,
.get_srv_inum = cifs_get_srv_inum, .get_srv_inum = cifs_get_srv_inum,
......
...@@ -241,7 +241,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile) ...@@ -241,7 +241,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
* and check it for zero before using. * and check it for zero before using.
*/ */
max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf; max_buf = tlink_tcon(cfile->tlink)->ses->server->maxBuf;
if (!max_buf) { if (max_buf < sizeof(struct smb2_lock_element)) {
free_xid(xid); free_xid(xid);
return -EINVAL; return -EINVAL;
} }
......
...@@ -847,7 +847,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -847,7 +847,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL); rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
kfree(utf16_path); kfree(utf16_path);
if (rc) { if (rc) {
cifs_dbg(VFS, "open dir failed\n"); cifs_dbg(FYI, "open dir failed rc=%d\n", rc);
return rc; return rc;
} }
...@@ -857,7 +857,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -857,7 +857,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_query_directory(xid, tcon, fid->persistent_fid, rc = SMB2_query_directory(xid, tcon, fid->persistent_fid,
fid->volatile_fid, 0, srch_inf); fid->volatile_fid, 0, srch_inf);
if (rc) { if (rc) {
cifs_dbg(VFS, "query directory failed\n"); cifs_dbg(FYI, "query directory failed rc=%d\n", rc);
SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid); SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
} }
return rc; return rc;
...@@ -978,6 +978,9 @@ smb2_new_lease_key(struct cifs_fid *fid) ...@@ -978,6 +978,9 @@ smb2_new_lease_key(struct cifs_fid *fid)
get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE); get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
} }
#define SMB2_SYMLINK_STRUCT_SIZE \
(sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
static int static int
smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, char **target_path, const char *full_path, char **target_path,
...@@ -990,7 +993,10 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -990,7 +993,10 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_fid fid; struct cifs_fid fid;
struct smb2_err_rsp *err_buf = NULL; struct smb2_err_rsp *err_buf = NULL;
struct smb2_symlink_err_rsp *symlink; struct smb2_symlink_err_rsp *symlink;
unsigned int sub_len, sub_offset; unsigned int sub_len;
unsigned int sub_offset;
unsigned int print_len;
unsigned int print_offset;
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path); cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
...@@ -1012,11 +1018,33 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -1012,11 +1018,33 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
kfree(utf16_path); kfree(utf16_path);
return -ENOENT; return -ENOENT;
} }
if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
get_rfc1002_length(err_buf) + 4 < SMB2_SYMLINK_STRUCT_SIZE) {
kfree(utf16_path);
return -ENOENT;
}
/* open must fail on symlink - reset rc */ /* open must fail on symlink - reset rc */
rc = 0; rc = 0;
symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData; symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
sub_len = le16_to_cpu(symlink->SubstituteNameLength); sub_len = le16_to_cpu(symlink->SubstituteNameLength);
sub_offset = le16_to_cpu(symlink->SubstituteNameOffset); sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
print_len = le16_to_cpu(symlink->PrintNameLength);
print_offset = le16_to_cpu(symlink->PrintNameOffset);
if (get_rfc1002_length(err_buf) + 4 <
SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
kfree(utf16_path);
return -ENOENT;
}
if (get_rfc1002_length(err_buf) + 4 <
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
kfree(utf16_path);
return -ENOENT;
}
*target_path = cifs_strndup_from_utf16( *target_path = cifs_strndup_from_utf16(
(char *)symlink->PathBuffer + sub_offset, (char *)symlink->PathBuffer + sub_offset,
sub_len, true, cifs_sb->local_nls); sub_len, true, cifs_sb->local_nls);
......
...@@ -264,7 +264,7 @@ out: ...@@ -264,7 +264,7 @@ out:
case SMB2_CHANGE_NOTIFY: case SMB2_CHANGE_NOTIFY:
case SMB2_QUERY_INFO: case SMB2_QUERY_INFO:
case SMB2_SET_INFO: case SMB2_SET_INFO:
return -EAGAIN; rc = -EAGAIN;
} }
unload_nls(nls_codepage); unload_nls(nls_codepage);
return rc; return rc;
...@@ -453,15 +453,22 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -453,15 +453,22 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
/* /*
* validation ioctl must be signed, so no point sending this if we * validation ioctl must be signed, so no point sending this if we
* can not sign it. We could eventually change this to selectively * can not sign it (ie are not known user). Even if signing is not
* required (enabled but not negotiated), in those cases we selectively
* sign just this, the first and only signed request on a connection. * sign just this, the first and only signed request on a connection.
* This is good enough for now since a user who wants better security * Having validation of negotiate info helps reduce attack vectors.
* would also enable signing on the mount. Having validation of
* negotiate info for signed connections helps reduce attack vectors
*/ */
if (tcon->ses->server->sign == false) if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_GUEST)
return 0; /* validation requires signing */ return 0; /* validation requires signing */
if (tcon->ses->user_name == NULL) {
cifs_dbg(FYI, "Can't validate negotiate: null user mount\n");
return 0; /* validation requires signing */
}
if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL)
cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n");
vneg_inbuf.Capabilities = vneg_inbuf.Capabilities =
cpu_to_le32(tcon->ses->server->vals->req_capabilities); cpu_to_le32(tcon->ses->server->vals->req_capabilities);
memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid, memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid,
...@@ -491,8 +498,12 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) ...@@ -491,8 +498,12 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon)
} }
if (rsplen != sizeof(struct validate_negotiate_info_rsp)) { if (rsplen != sizeof(struct validate_negotiate_info_rsp)) {
cifs_dbg(VFS, "invalid size of protocol negotiate response\n"); cifs_dbg(VFS, "invalid protocol negotiate response size: %d\n",
return -EIO; rsplen);
/* relax check since Mac returns max bufsize allowed on ioctl */
if (rsplen > CIFSMaxBufSize)
return -EIO;
} }
/* check validate negotiate info response matches what we got earlier */ /* check validate negotiate info response matches what we got earlier */
...@@ -532,7 +543,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, ...@@ -532,7 +543,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
u16 blob_length = 0; u16 blob_length = 0;
struct key *spnego_key = NULL; struct key *spnego_key = NULL;
char *security_blob = NULL; char *security_blob = NULL;
char *ntlmssp_blob = NULL; unsigned char *ntlmssp_blob = NULL;
bool use_spnego = false; /* else use raw ntlmssp */ bool use_spnego = false; /* else use raw ntlmssp */
cifs_dbg(FYI, "Session Setup\n"); cifs_dbg(FYI, "Session Setup\n");
...@@ -657,13 +668,7 @@ ssetup_ntlmssp_authenticate: ...@@ -657,13 +668,7 @@ ssetup_ntlmssp_authenticate:
iov[1].iov_len = blob_length; iov[1].iov_len = blob_length;
} else if (phase == NtLmAuthenticate) { } else if (phase == NtLmAuthenticate) {
req->hdr.SessionId = ses->Suid; req->hdr.SessionId = ses->Suid;
ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500, rc = build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, ses,
GFP_KERNEL);
if (ntlmssp_blob == NULL) {
rc = -ENOMEM;
goto ssetup_exit;
}
rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses,
nls_cp); nls_cp);
if (rc) { if (rc) {
cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n",
...@@ -860,9 +865,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -860,9 +865,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
else else
return -EIO; return -EIO;
if (tcon && tcon->bad_network_name)
return -ENOENT;
unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); unc_path = kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL);
if (unc_path == NULL) if (unc_path == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -874,6 +876,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, ...@@ -874,6 +876,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
return -EINVAL; return -EINVAL;
} }
/* SMB2 TREE_CONNECT request must be called with TreeId == 0 */
if (tcon)
tcon->tid = 0;
rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req);
if (rc) { if (rc) {
kfree(unc_path); kfree(unc_path);
...@@ -952,8 +958,6 @@ tcon_exit: ...@@ -952,8 +958,6 @@ tcon_exit:
tcon_error_exit: tcon_error_exit:
if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
if (tcon)
tcon->bad_network_name = true;
} }
goto tcon_exit; goto tcon_exit;
} }
...@@ -1320,8 +1324,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, ...@@ -1320,8 +1324,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
* than one credit. Windows typically sets this smaller, but for some * than one credit. Windows typically sets this smaller, but for some
* ioctls it may be useful to allow server to send more. No point * ioctls it may be useful to allow server to send more. No point
* limiting what the server can send as long as fits in one credit * limiting what the server can send as long as fits in one credit
* Unfortunately - we can not handle more than CIFS_MAX_MSG_SIZE
* (by default, note that it can be overridden to make max larger)
* in responses (except for read responses which can be bigger.
* We may want to bump this limit up
*/ */
req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */ req->MaxOutputResponse = cpu_to_le32(CIFSMaxBufSize);
if (is_fsctl) if (is_fsctl)
req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL); req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
...@@ -1621,6 +1629,54 @@ smb2_echo_callback(struct mid_q_entry *mid) ...@@ -1621,6 +1629,54 @@ smb2_echo_callback(struct mid_q_entry *mid)
add_credits(server, credits_received, CIFS_ECHO_OP); add_credits(server, credits_received, CIFS_ECHO_OP);
} }
void smb2_reconnect_server(struct work_struct *work)
{
struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, reconnect.work);
struct cifs_ses *ses;
struct cifs_tcon *tcon, *tcon2;
struct list_head tmp_list;
int tcon_exist = false;
/* Prevent simultaneous reconnects that can corrupt tcon->rlist list */
mutex_lock(&server->reconnect_mutex);
INIT_LIST_HEAD(&tmp_list);
cifs_dbg(FYI, "Need negotiate, reconnecting tcons\n");
spin_lock(&cifs_tcp_ses_lock);
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->need_reconnect) {
tcon->tc_count++;
list_add_tail(&tcon->rlist, &tmp_list);
tcon_exist = true;
}
}
}
/*
* Get the reference to server struct to be sure that the last call of
* cifs_put_tcon() in the loop below won't release the server pointer.
*/
if (tcon_exist)
server->srv_count++;
spin_unlock(&cifs_tcp_ses_lock);
list_for_each_entry_safe(tcon, tcon2, &tmp_list, rlist) {
smb2_reconnect(SMB2_ECHO, tcon);
list_del_init(&tcon->rlist);
cifs_put_tcon(tcon);
}
cifs_dbg(FYI, "Reconnecting tcons finished\n");
mutex_unlock(&server->reconnect_mutex);
/* now we can safely release srv struct */
if (tcon_exist)
cifs_put_tcp_session(server, 1);
}
int int
SMB2_echo(struct TCP_Server_Info *server) SMB2_echo(struct TCP_Server_Info *server)
{ {
...@@ -1632,6 +1688,12 @@ SMB2_echo(struct TCP_Server_Info *server) ...@@ -1632,6 +1688,12 @@ SMB2_echo(struct TCP_Server_Info *server)
cifs_dbg(FYI, "In echo request\n"); cifs_dbg(FYI, "In echo request\n");
if (server->tcpStatus == CifsNeedNegotiate) {
/* No need to send echo on newly established connections */
queue_delayed_work(cifsiod_wq, &server->reconnect, 0);
return rc;
}
rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req); rc = small_smb2_init(SMB2_ECHO, NULL, (void **)&req);
if (rc) if (rc)
return rc; return rc;
...@@ -2499,8 +2561,8 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf, ...@@ -2499,8 +2561,8 @@ copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) * kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
le32_to_cpu(pfs_inf->SectorsPerAllocationUnit); le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits); kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits); kst->f_bfree = kst->f_bavail =
kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits); le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
return; return;
} }
......
...@@ -82,8 +82,8 @@ ...@@ -82,8 +82,8 @@
#define NUMBER_OF_SMB2_COMMANDS 0x0013 #define NUMBER_OF_SMB2_COMMANDS 0x0013
/* BB FIXME - analyze following length BB */ /* 4 len + 52 transform hdr + 64 hdr + 56 create rsp */
#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */ #define MAX_SMB2_HDR_SIZE 0x00b0
#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe) #define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
......
...@@ -95,6 +95,7 @@ extern int smb2_open_file(const unsigned int xid, ...@@ -95,6 +95,7 @@ extern int smb2_open_file(const unsigned int xid,
extern int smb2_unlock_range(struct cifsFileInfo *cfile, extern int smb2_unlock_range(struct cifsFileInfo *cfile,
struct file_lock *flock, const unsigned int xid); struct file_lock *flock, const unsigned int xid);
extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
extern void smb2_reconnect_server(struct work_struct *work);
/* /*
* SMB2 Worker functions - most of protocol specific implementation details * SMB2 Worker functions - most of protocol specific implementation details
......
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