Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6: (31 commits) [CIFS] Remove redundant test [CIFS] make sure that DFS pathnames are properly formed Remove an already-checked error condition in SendReceiveBlockingLock Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition Streamline SendReceiveBlockingLock: Use "goto out:" in an error condition [CIFS] Streamline SendReceive[2] by using "goto out:" in an error condition Slightly streamline SendReceive[2] Check the return value of cifs_sign_smb[2] [CIFS] Cleanup: Move the check for too large R/W requests [CIFS] Slightly simplify wait_for_free_request(), remove an unnecessary "else" branch Simplify allocate_mid() slightly: Remove some unnecessary "else" branches [CIFS] In SendReceive, move consistency check out of the mutexed region cifs: store password in tcon cifs: have calc_lanman_hash take more granular args cifs: zero out session password before freeing it cifs: fix wait_for_response to time out sleeping processes correctly [CIFS] Can not mount with prefixpath if root directory of share is inaccessible [CIFS] various minor cleanups pointed out by checkpatch script [CIFS] fix typo [CIFS] remove sparse warning ... Fix trivial conflict in fs/cifs/cifs_fs_sb.h due to comment changes for the CIFS_MOUNT_xyz bit definitions between cifs updates and security updates.
This commit is contained in:
commit
54a696bd07
@ -36,7 +36,9 @@ Miklos Szeredi
|
||||
Kazeon team for various fixes especially for 2.4 version.
|
||||
Asser Ferno (Change Notify support)
|
||||
Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup
|
||||
Gunter Kukkukk (testing and suggestions for support of old servers)
|
||||
Igor Mammedov (DFS support)
|
||||
Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
|
||||
|
||||
Test case and Bug Report contributors
|
||||
-------------------------------------
|
||||
|
@ -1,3 +1,12 @@
|
||||
Version 1.56
|
||||
------------
|
||||
Add "forcemandatorylock" mount option to allow user to use mandatory
|
||||
rather than posix (advisory) byte range locks, even though server would
|
||||
support posix byte range locks. Fix query of root inode when prefixpath
|
||||
specified and user does not have access to query information about the
|
||||
top of the share. Fix problem in 2.6.28 resolving DFS paths to
|
||||
Samba servers (worked to Windows).
|
||||
|
||||
Version 1.55
|
||||
------------
|
||||
Various fixes to make delete of open files behavior more predictable
|
||||
|
@ -463,9 +463,19 @@ A partial list of the supported mount options follows:
|
||||
with cifs style mandatory byte range locks (and most
|
||||
cifs servers do not yet support requesting advisory
|
||||
byte range locks).
|
||||
forcemandatorylock Even if the server supports posix (advisory) byte range
|
||||
locking, send only mandatory lock requests. For some
|
||||
(presumably rare) applications, originally coded for
|
||||
DOS/Windows, which require Windows style mandatory byte range
|
||||
locking, they may be able to take advantage of this option,
|
||||
forcing the cifs client to only send mandatory locks
|
||||
even if the cifs server would support posix advisory locks.
|
||||
"forcemand" is accepted as a shorter form of this mount
|
||||
option.
|
||||
nodfs Disable DFS (global name space support) even if the
|
||||
server claims to support it. This can help work around
|
||||
a problem with parsing of DFS paths with Samba 3.0.24 server.
|
||||
a problem with parsing of DFS paths with Samba server
|
||||
versions 3.0.24 and 3.0.25.
|
||||
remount remount the share (often used to change from ro to rw mounts
|
||||
or vice versa)
|
||||
cifsacl Report mode bits (e.g. on stat) based on the Windows ACL for
|
||||
|
@ -122,7 +122,7 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
char **devname)
|
||||
{
|
||||
int rc;
|
||||
char *mountdata;
|
||||
char *mountdata = NULL;
|
||||
int md_len;
|
||||
char *tkn_e;
|
||||
char *srvIP = NULL;
|
||||
@ -136,10 +136,9 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
*devname = cifs_get_share_name(ref->node_name);
|
||||
rc = dns_resolve_server_name_to_ip(*devname, &srvIP);
|
||||
if (rc != 0) {
|
||||
cERROR(1, ("%s: Failed to resolve server part of %s to IP",
|
||||
__func__, *devname));
|
||||
mountdata = ERR_PTR(rc);
|
||||
goto compose_mount_options_out;
|
||||
cERROR(1, ("%s: Failed to resolve server part of %s to IP: %d",
|
||||
__func__, *devname, rc));;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
/* md_len = strlen(...) + 12 for 'sep+prefixpath='
|
||||
* assuming that we have 'unc=' and 'ip=' in
|
||||
@ -149,8 +148,8 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
strlen(ref->node_name) + 12;
|
||||
mountdata = kzalloc(md_len+1, GFP_KERNEL);
|
||||
if (mountdata == NULL) {
|
||||
mountdata = ERR_PTR(-ENOMEM);
|
||||
goto compose_mount_options_out;
|
||||
rc = -ENOMEM;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
|
||||
/* copy all options except of unc,ip,prefixpath */
|
||||
@ -197,18 +196,32 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
|
||||
/* find & copy prefixpath */
|
||||
tkn_e = strchr(ref->node_name + 2, '\\');
|
||||
if (tkn_e == NULL) /* invalid unc, missing share name*/
|
||||
goto compose_mount_options_out;
|
||||
if (tkn_e == NULL) {
|
||||
/* invalid unc, missing share name*/
|
||||
rc = -EINVAL;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function gives us a path with a double backslash prefix. We
|
||||
* require a single backslash for DFS. Temporarily increment fullpath
|
||||
* to put it in the proper form and decrement before freeing it.
|
||||
*/
|
||||
fullpath = build_path_from_dentry(dentry);
|
||||
if (!fullpath) {
|
||||
rc = -ENOMEM;
|
||||
goto compose_mount_options_err;
|
||||
}
|
||||
++fullpath;
|
||||
tkn_e = strchr(tkn_e + 1, '\\');
|
||||
if (tkn_e || strlen(fullpath) - (ref->path_consumed)) {
|
||||
if (tkn_e || (strlen(fullpath) - ref->path_consumed)) {
|
||||
strncat(mountdata, &sep, 1);
|
||||
strcat(mountdata, "prefixpath=");
|
||||
if (tkn_e)
|
||||
strcat(mountdata, tkn_e + 1);
|
||||
strcat(mountdata, fullpath + (ref->path_consumed));
|
||||
strcat(mountdata, fullpath + ref->path_consumed);
|
||||
}
|
||||
--fullpath;
|
||||
kfree(fullpath);
|
||||
|
||||
/*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/
|
||||
@ -217,6 +230,11 @@ static char *compose_mount_options(const char *sb_mountdata,
|
||||
compose_mount_options_out:
|
||||
kfree(srvIP);
|
||||
return mountdata;
|
||||
|
||||
compose_mount_options_err:
|
||||
kfree(mountdata);
|
||||
mountdata = ERR_PTR(rc);
|
||||
goto compose_mount_options_out;
|
||||
}
|
||||
|
||||
|
||||
@ -309,13 +327,19 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* The MSDFS spec states that paths in DFS referral requests and
|
||||
* responses must be prefixed by a single '\' character instead of
|
||||
* the double backslashes usually used in the UNC. This function
|
||||
* gives us the latter, so we must adjust the result.
|
||||
*/
|
||||
full_path = build_path_from_dentry(dentry);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
rc = get_dfs_path(xid, ses , full_path, cifs_sb->local_nls,
|
||||
rc = get_dfs_path(xid, ses , full_path + 1, cifs_sb->local_nls,
|
||||
&num_referrals, &referrals,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#define CIFS_MOUNT_NO_PERM 1 /* do not do client vfs_perm check */
|
||||
#define CIFS_MOUNT_SET_UID 2 /* set current's euid in create etc. */
|
||||
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
|
||||
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
|
||||
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
|
||||
#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
|
||||
#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
|
||||
@ -30,7 +30,8 @@
|
||||
#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
|
||||
#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
|
||||
#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
|
||||
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
|
||||
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
|
||||
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
|
||||
|
||||
struct cifs_sb_info {
|
||||
struct cifsTconInfo *tcon; /* primary mount */
|
||||
|
@ -37,7 +37,7 @@
|
||||
|
||||
extern void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
|
||||
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
|
||||
extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
|
||||
@ -280,25 +280,22 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
|
||||
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
|
||||
char *lnm_session_key)
|
||||
{
|
||||
int i;
|
||||
char password_with_pad[CIFS_ENCPWD_SIZE];
|
||||
|
||||
if (ses->server == NULL)
|
||||
return;
|
||||
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
if (ses->password)
|
||||
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
|
||||
if (password)
|
||||
strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
|
||||
|
||||
if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||
if (extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||
memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
|
||||
memcpy(lnm_session_key, password_with_pad,
|
||||
CIFS_ENCPWD_SIZE);
|
||||
return;
|
||||
}
|
||||
if (!encrypt && extended_security & CIFSSEC_MAY_PLNTXT) {
|
||||
memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
|
||||
memcpy(lnm_session_key, password_with_pad,
|
||||
CIFS_ENCPWD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* calculate old style session key */
|
||||
/* calling toupper is less broken than repeatedly
|
||||
@ -314,7 +311,8 @@ void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
|
||||
for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
|
||||
password_with_pad[i] = toupper(password_with_pad[i]);
|
||||
|
||||
SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key);
|
||||
SMBencrypt(password_with_pad, cryptkey, lnm_session_key);
|
||||
|
||||
/* clear password before we return/free memory */
|
||||
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
|
||||
}
|
||||
|
@ -26,7 +26,8 @@
|
||||
extern void mdfour(unsigned char *out, unsigned char *in, int n);
|
||||
/* smbdes.c */
|
||||
extern void E_P16(unsigned char *p14, unsigned char *p16);
|
||||
extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
|
||||
extern void E_P24(unsigned char *p21, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
|
||||
|
||||
|
||||
|
@ -66,7 +66,9 @@ unsigned int sign_CIFS_PDUs = 1;
|
||||
extern struct task_struct *oplockThread; /* remove sparse warning */
|
||||
struct task_struct *oplockThread = NULL;
|
||||
/* extern struct task_struct * dnotifyThread; remove sparse warning */
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static struct task_struct *dnotifyThread = NULL;
|
||||
#endif
|
||||
static const struct super_operations cifs_super_ops;
|
||||
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
|
||||
module_param(CIFSMaxBufSize, int, 0);
|
||||
@ -337,39 +339,58 @@ static int
|
||||
cifs_show_options(struct seq_file *s, struct vfsmount *m)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *tcon;
|
||||
struct TCP_Server_Info *server;
|
||||
|
||||
cifs_sb = CIFS_SB(m->mnt_sb);
|
||||
|
||||
if (cifs_sb) {
|
||||
if (cifs_sb->tcon) {
|
||||
/* BB add prepath to mount options displayed */
|
||||
tcon = cifs_sb->tcon;
|
||||
if (tcon) {
|
||||
seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
|
||||
if (cifs_sb->tcon->ses) {
|
||||
if (cifs_sb->tcon->ses->userName)
|
||||
if (tcon->ses) {
|
||||
if (tcon->ses->userName)
|
||||
seq_printf(s, ",username=%s",
|
||||
cifs_sb->tcon->ses->userName);
|
||||
if (cifs_sb->tcon->ses->domainName)
|
||||
tcon->ses->userName);
|
||||
if (tcon->ses->domainName)
|
||||
seq_printf(s, ",domain=%s",
|
||||
cifs_sb->tcon->ses->domainName);
|
||||
tcon->ses->domainName);
|
||||
server = tcon->ses->server;
|
||||
if (server) {
|
||||
seq_printf(s, ",addr=");
|
||||
switch (server->addr.sockAddr6.
|
||||
sin6_family) {
|
||||
case AF_INET6:
|
||||
seq_printf(s, NIP6_FMT,
|
||||
NIP6(server->addr.sockAddr6.sin6_addr));
|
||||
break;
|
||||
case AF_INET:
|
||||
seq_printf(s, NIPQUAD_FMT,
|
||||
NIPQUAD(server->addr.sockAddr.sin_addr.s_addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
|
||||
!(cifs_sb->tcon->unix_ext))
|
||||
!(tcon->unix_ext))
|
||||
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
|
||||
!(cifs_sb->tcon->unix_ext))
|
||||
!(tcon->unix_ext))
|
||||
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
|
||||
if (!cifs_sb->tcon->unix_ext) {
|
||||
if (!tcon->unix_ext) {
|
||||
seq_printf(s, ",file_mode=0%o,dir_mode=0%o",
|
||||
cifs_sb->mnt_file_mode,
|
||||
cifs_sb->mnt_dir_mode);
|
||||
}
|
||||
if (cifs_sb->tcon->seal)
|
||||
if (tcon->seal)
|
||||
seq_printf(s, ",seal");
|
||||
if (cifs_sb->tcon->nocase)
|
||||
if (tcon->nocase)
|
||||
seq_printf(s, ",nocase");
|
||||
if (cifs_sb->tcon->retry)
|
||||
if (tcon->retry)
|
||||
seq_printf(s, ",hard");
|
||||
}
|
||||
if (cifs_sb->prepath)
|
||||
seq_printf(s, ",prepath=%s", cifs_sb->prepath);
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
|
||||
seq_printf(s, ",posixpaths");
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)
|
||||
@ -417,9 +438,8 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@ -441,9 +461,8 @@ int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@ -464,9 +483,8 @@ int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@ -479,17 +497,16 @@ int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
|
||||
struct cifsTconInfo *pTcon;
|
||||
|
||||
if (cifs_sb) {
|
||||
if (cifs_sb)
|
||||
pTcon = cifs_sb->tcon;
|
||||
} else {
|
||||
else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
xid = GetXid();
|
||||
if (pTcon) {
|
||||
cFYI(1, ("pqstats %p", qstats));
|
||||
} else {
|
||||
} else
|
||||
rc = -EIO;
|
||||
}
|
||||
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
@ -1029,6 +1046,7 @@ static int cifs_oplock_thread(void *dummyarg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
static int cifs_dnotify_thread(void *dummyarg)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
@ -1054,6 +1072,7 @@ static int cifs_dnotify_thread(void *dummyarg)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init
|
||||
init_cifs(void)
|
||||
@ -1131,16 +1150,20 @@ init_cifs(void)
|
||||
goto out_unregister_dfs_key_type;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
|
||||
if (IS_ERR(dnotifyThread)) {
|
||||
rc = PTR_ERR(dnotifyThread);
|
||||
cERROR(1, ("error %d create dnotify thread", rc));
|
||||
goto out_stop_oplock_thread;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
out_stop_oplock_thread:
|
||||
#endif
|
||||
kthread_stop(oplockThread);
|
||||
out_unregister_dfs_key_type:
|
||||
#ifdef CONFIG_CIFS_DFS_UPCALL
|
||||
@ -1179,8 +1202,10 @@ exit_cifs(void)
|
||||
cifs_destroy_inodecache();
|
||||
cifs_destroy_mids();
|
||||
cifs_destroy_request_bufs();
|
||||
kthread_stop(oplockThread);
|
||||
#ifdef CONFIG_CIFS_EXPERIMENTAL
|
||||
kthread_stop(dnotifyThread);
|
||||
#endif
|
||||
kthread_stop(oplockThread);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
|
||||
|
@ -101,5 +101,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||
extern const struct export_operations cifs_export_ops;
|
||||
#endif /* EXPERIMENTAL */
|
||||
|
||||
#define CIFS_VERSION "1.55"
|
||||
#define CIFS_VERSION "1.56"
|
||||
#endif /* _CIFSFS_H */
|
||||
|
@ -47,7 +47,11 @@
|
||||
*/
|
||||
#define CIFS_MAX_REQ 50
|
||||
|
||||
#define SERVER_NAME_LENGTH 15
|
||||
#define RFC1001_NAME_LEN 15
|
||||
#define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1)
|
||||
|
||||
/* currently length of NIP6_FMT */
|
||||
#define SERVER_NAME_LENGTH 40
|
||||
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
|
||||
|
||||
/* used to define string lengths for reversing unicode strings */
|
||||
@ -125,8 +129,7 @@ struct TCP_Server_Info {
|
||||
struct list_head smb_ses_list;
|
||||
int srv_count; /* reference counter */
|
||||
/* 15 character server name + 0x20 16th byte indicating type = srv */
|
||||
char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
|
||||
char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
char *hostname; /* hostname portion of UNC string */
|
||||
struct socket *ssocket;
|
||||
union {
|
||||
@ -151,7 +154,7 @@ struct TCP_Server_Info {
|
||||
atomic_t num_waiters; /* blocked waiting to get in sendrecv */
|
||||
#endif
|
||||
enum statusEnum tcpStatus; /* what we think the status is */
|
||||
struct semaphore tcpSem;
|
||||
struct mutex srv_mutex;
|
||||
struct task_struct *tsk;
|
||||
char server_GUID[16];
|
||||
char secMode;
|
||||
@ -171,7 +174,7 @@ struct TCP_Server_Info {
|
||||
__u16 CurrentMid; /* multiplex id - rotating counter */
|
||||
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
|
||||
/* 16th byte of RFC1001 workstation name is always null */
|
||||
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
|
||||
char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
|
||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||
struct mac_key mac_signing_key;
|
||||
char ntlmv2_hash[16];
|
||||
@ -239,6 +242,7 @@ struct cifsTconInfo {
|
||||
struct cifsSesInfo *ses; /* pointer to session associated with */
|
||||
char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
|
||||
char *nativeFileSystem;
|
||||
char *password; /* for share-level security */
|
||||
__u16 tid; /* The 2 byte tree id */
|
||||
__u16 Flags; /* optional support bits */
|
||||
enum statusEnum tidStatus;
|
||||
@ -422,7 +426,6 @@ struct mid_q_entry {
|
||||
unsigned long when_sent; /* time when smb send finished */
|
||||
unsigned long when_received; /* when demux complete (taken off wire) */
|
||||
#endif
|
||||
struct cifsSesInfo *ses; /* smb was sent to this server */
|
||||
struct task_struct *tsk; /* task waiting for response */
|
||||
struct smb_hdr *resp_buf; /* response buffer */
|
||||
int midState; /* wish this were enum but can not pass to wait_event */
|
||||
|
@ -1922,7 +1922,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
|
||||
/* DFS server target type */
|
||||
#define DFS_TYPE_LINK 0x0000 /* also for sysvol targets */
|
||||
#define DFS_TYPE_ROOT 0x0001
|
||||
|
||||
|
||||
/* Referral Entry Flags */
|
||||
#define DFS_NAME_LIST_REF 0x0200
|
||||
|
||||
|
@ -330,7 +330,8 @@ extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
|
||||
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
|
||||
const struct nls_table *);
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
|
||||
extern void calc_lanman_hash(const char *password, const char *cryptkey,
|
||||
bool encrypt, char *lnm_session_key);
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
extern int CIFSSMBCopy(int xid,
|
||||
struct cifsTconInfo *source_tcon,
|
||||
|
@ -1382,13 +1382,13 @@ openRetry:
|
||||
if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
|
||||
*pOplock |= CIFS_CREATE_ACTION;
|
||||
if (pfile_info) {
|
||||
memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
|
||||
36 /* CreationTime to Attributes */);
|
||||
/* the file_info buf is endian converted by caller */
|
||||
pfile_info->AllocationSize = pSMBr->AllocationSize;
|
||||
pfile_info->EndOfFile = pSMBr->EndOfFile;
|
||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||
pfile_info->DeletePending = 0;
|
||||
memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
|
||||
36 /* CreationTime to Attributes */);
|
||||
/* the file_info buf is endian converted by caller */
|
||||
pfile_info->AllocationSize = pSMBr->AllocationSize;
|
||||
pfile_info->EndOfFile = pSMBr->EndOfFile;
|
||||
pfile_info->NumberOfLinks = cpu_to_le32(1);
|
||||
pfile_info->DeletePending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1414,8 +1414,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
|
||||
cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
||||
wct = 12;
|
||||
else
|
||||
else {
|
||||
wct = 10; /* old style read */
|
||||
if ((lseek >> 32) > 0) {
|
||||
/* can not handle this big offset for old */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
*nbytes = 0;
|
||||
rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
|
||||
@ -1431,8 +1436,6 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
|
||||
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
|
||||
if (wct == 12)
|
||||
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
|
||||
else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
|
||||
return -EIO;
|
||||
|
||||
pSMB->Remaining = 0;
|
||||
pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
|
||||
@ -1519,8 +1522,13 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
||||
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
||||
wct = 14;
|
||||
else
|
||||
else {
|
||||
wct = 12;
|
||||
if ((offset >> 32) > 0) {
|
||||
/* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
@ -1535,8 +1543,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
||||
if (wct == 14)
|
||||
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
||||
else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
|
||||
pSMB->Reserved = 0xFFFFFFFF;
|
||||
pSMB->WriteMode = 0;
|
||||
@ -1558,7 +1564,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->DataOffset =
|
||||
cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
|
||||
if (buf)
|
||||
memcpy(pSMB->Data, buf, bytes_sent);
|
||||
memcpy(pSMB->Data, buf, bytes_sent);
|
||||
else if (ubuf) {
|
||||
if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
|
||||
cifs_buf_release(pSMB);
|
||||
@ -1621,10 +1627,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
||||
|
||||
cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
|
||||
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES)
|
||||
if (tcon->ses->capabilities & CAP_LARGE_FILES) {
|
||||
wct = 14;
|
||||
else
|
||||
} else {
|
||||
wct = 12;
|
||||
if ((offset >> 32) > 0) {
|
||||
/* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -1637,8 +1648,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
|
||||
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
|
||||
if (wct == 14)
|
||||
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
|
||||
else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
|
||||
return -EIO;
|
||||
pSMB->Reserved = 0xFFFFFFFF;
|
||||
pSMB->WriteMode = 0;
|
||||
pSMB->Remaining = 0;
|
||||
@ -1862,10 +1871,6 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
|
||||
rc = -EIO; /* bad smb */
|
||||
goto plk_err_exit;
|
||||
}
|
||||
if (pLockData == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto plk_err_exit;
|
||||
}
|
||||
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
||||
data_count = le16_to_cpu(pSMBr->t2.DataCount);
|
||||
if (data_count < sizeof(struct cifs_posix_lock)) {
|
||||
|
@ -89,6 +89,7 @@ struct smb_vol {
|
||||
bool nullauth:1; /* attempt to authenticate with null user */
|
||||
bool nocase:1; /* request case insensitive filenames */
|
||||
bool nobrl:1; /* disable sending byte range locks to srv */
|
||||
bool mand_lock:1; /* send mandatory not posix byte range lock reqs */
|
||||
bool seal:1; /* request transport encryption on share */
|
||||
bool nodfs:1; /* Do not request DFS, even if available */
|
||||
bool local_lease:1; /* check leases only on local system, not remote */
|
||||
@ -101,25 +102,17 @@ struct smb_vol {
|
||||
char *prepath;
|
||||
};
|
||||
|
||||
static int ipv4_connect(struct sockaddr_in *psin_server,
|
||||
struct socket **csocket,
|
||||
char *netb_name,
|
||||
char *server_netb_name,
|
||||
bool noblocksnd,
|
||||
bool nosndbuf); /* ipv6 never set sndbuf size */
|
||||
static int ipv6_connect(struct sockaddr_in6 *psin_server,
|
||||
struct socket **csocket, bool noblocksnd);
|
||||
|
||||
|
||||
/*
|
||||
* cifs tcp session reconnection
|
||||
*
|
||||
* mark tcp session as reconnecting so temporarily locked
|
||||
* mark all smb sessions as reconnecting for tcp session
|
||||
* reconnect tcp session
|
||||
* wake up waiters on reconnection? - (not needed currently)
|
||||
*/
|
||||
static int ipv4_connect(struct TCP_Server_Info *server);
|
||||
static int ipv6_connect(struct TCP_Server_Info *server);
|
||||
|
||||
/*
|
||||
* cifs tcp session reconnection
|
||||
*
|
||||
* mark tcp session as reconnecting so temporarily locked
|
||||
* mark all smb sessions as reconnecting for tcp session
|
||||
* reconnect tcp session
|
||||
* wake up waiters on reconnection? - (not needed currently)
|
||||
*/
|
||||
static int
|
||||
cifs_reconnect(struct TCP_Server_Info *server)
|
||||
{
|
||||
@ -156,7 +149,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||
}
|
||||
read_unlock(&cifs_tcp_ses_lock);
|
||||
/* do not want to be sending data on a socket we are freeing */
|
||||
down(&server->tcpSem);
|
||||
mutex_lock(&server->srv_mutex);
|
||||
if (server->ssocket) {
|
||||
cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
|
||||
server->ssocket->flags));
|
||||
@ -182,21 +175,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
|
||||
}
|
||||
}
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
up(&server->tcpSem);
|
||||
mutex_unlock(&server->srv_mutex);
|
||||
|
||||
while ((server->tcpStatus != CifsExiting) &&
|
||||
(server->tcpStatus != CifsGood)) {
|
||||
try_to_freeze();
|
||||
if (server->addr.sockAddr6.sin6_family == AF_INET6) {
|
||||
rc = ipv6_connect(&server->addr.sockAddr6,
|
||||
&server->ssocket, server->noautotune);
|
||||
} else {
|
||||
rc = ipv4_connect(&server->addr.sockAddr,
|
||||
&server->ssocket,
|
||||
server->workstation_RFC1001_name,
|
||||
server->server_RFC1001_name,
|
||||
server->noblocksnd, server->noautotune);
|
||||
}
|
||||
if (server->addr.sockAddr6.sin6_family == AF_INET6)
|
||||
rc = ipv6_connect(server);
|
||||
else
|
||||
rc = ipv4_connect(server);
|
||||
if (rc) {
|
||||
cFYI(1, ("reconnect error %d", rc));
|
||||
msleep(3000);
|
||||
@ -776,7 +763,7 @@ multi_t2_fnd:
|
||||
set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
module_put_and_exit(0);
|
||||
}
|
||||
|
||||
/* extract the host portion of the UNC string */
|
||||
@ -1260,6 +1247,17 @@ cifs_parse_mount_options(char *options, const char *devname,
|
||||
if (vol->file_mode ==
|
||||
(S_IALLUGO & ~(S_ISUID | S_IXGRP)))
|
||||
vol->file_mode = S_IALLUGO;
|
||||
} else if (strnicmp(data, "forcemandatorylock", 9) == 0) {
|
||||
/* will take the shorter form "forcemand" as well */
|
||||
/* This mount option will force use of mandatory
|
||||
(DOS/Windows style) byte range locks, instead of
|
||||
using posix advisory byte range locks, even if the
|
||||
Unix extensions are available and posix locks would
|
||||
be supported otherwise. If Unix extensions are not
|
||||
negotiated this has no effect since mandatory locks
|
||||
would be used (mandatory locks is all that those
|
||||
those servers support) */
|
||||
vol->mand_lock = 1;
|
||||
} else if (strnicmp(data, "setuids", 7) == 0) {
|
||||
vol->setuids = 1;
|
||||
} else if (strnicmp(data, "nosetuids", 9) == 0) {
|
||||
@ -1417,6 +1415,143 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
|
||||
force_sig(SIGKILL, task);
|
||||
}
|
||||
|
||||
static struct TCP_Server_Info *
|
||||
cifs_get_tcp_session(struct smb_vol *volume_info)
|
||||
{
|
||||
struct TCP_Server_Info *tcp_ses = NULL;
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
|
||||
struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
|
||||
int rc;
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr));
|
||||
|
||||
if (volume_info->UNCip && volume_info->UNC) {
|
||||
rc = cifs_inet_pton(AF_INET, volume_info->UNCip,
|
||||
&sin_server->sin_addr.s_addr);
|
||||
|
||||
if (rc <= 0) {
|
||||
/* not ipv4 address, try ipv6 */
|
||||
rc = cifs_inet_pton(AF_INET6, volume_info->UNCip,
|
||||
&sin_server6->sin6_addr.in6_u);
|
||||
if (rc > 0)
|
||||
addr.sa_family = AF_INET6;
|
||||
} else {
|
||||
addr.sa_family = AF_INET;
|
||||
}
|
||||
|
||||
if (rc <= 0) {
|
||||
/* we failed translating address */
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
cFYI(1, ("UNC: %s ip: %s", volume_info->UNC,
|
||||
volume_info->UNCip));
|
||||
} else if (volume_info->UNCip) {
|
||||
/* BB using ip addr as tcp_ses name to connect to the
|
||||
DFS root below */
|
||||
cERROR(1, ("Connecting to DFS root not implemented yet"));
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
} else /* which tcp_sess DFS root would we conect to */ {
|
||||
cERROR(1,
|
||||
("CIFS mount error: No UNC path (e.g. -o "
|
||||
"unc=//192.168.1.100/public) specified"));
|
||||
rc = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* see if we already have a matching tcp_ses */
|
||||
tcp_ses = cifs_find_tcp_session(&addr);
|
||||
if (tcp_ses)
|
||||
return tcp_ses;
|
||||
|
||||
tcp_ses = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
|
||||
if (!tcp_ses) {
|
||||
rc = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
tcp_ses->hostname = extract_hostname(volume_info->UNC);
|
||||
if (IS_ERR(tcp_ses->hostname)) {
|
||||
rc = PTR_ERR(tcp_ses->hostname);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
tcp_ses->noblocksnd = volume_info->noblocksnd;
|
||||
tcp_ses->noautotune = volume_info->noautotune;
|
||||
atomic_set(&tcp_ses->inFlight, 0);
|
||||
init_waitqueue_head(&tcp_ses->response_q);
|
||||
init_waitqueue_head(&tcp_ses->request_q);
|
||||
INIT_LIST_HEAD(&tcp_ses->pending_mid_q);
|
||||
mutex_init(&tcp_ses->srv_mutex);
|
||||
memcpy(tcp_ses->workstation_RFC1001_name,
|
||||
volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
memcpy(tcp_ses->server_RFC1001_name,
|
||||
volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
tcp_ses->sequence_number = 0;
|
||||
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
|
||||
INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
|
||||
|
||||
/*
|
||||
* at this point we are the only ones with the pointer
|
||||
* to the struct since the kernel thread not created yet
|
||||
* no need to spinlock this init of tcpStatus or srv_count
|
||||
*/
|
||||
tcp_ses->tcpStatus = CifsNew;
|
||||
++tcp_ses->srv_count;
|
||||
|
||||
if (addr.sa_family == AF_INET6) {
|
||||
cFYI(1, ("attempting ipv6 connect"));
|
||||
/* BB should we allow ipv6 on port 139? */
|
||||
/* other OS never observed in Wild doing 139 with v6 */
|
||||
memcpy(&tcp_ses->addr.sockAddr6, sin_server6,
|
||||
sizeof(struct sockaddr_in6));
|
||||
sin_server6->sin6_port = htons(volume_info->port);
|
||||
rc = ipv6_connect(tcp_ses);
|
||||
} else {
|
||||
memcpy(&tcp_ses->addr.sockAddr, sin_server,
|
||||
sizeof(struct sockaddr_in));
|
||||
sin_server->sin_port = htons(volume_info->port);
|
||||
rc = ipv4_connect(tcp_ses);
|
||||
}
|
||||
if (rc < 0) {
|
||||
cERROR(1, ("Error connecting to socket. Aborting operation"));
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/*
|
||||
* since we're in a cifs function already, we know that
|
||||
* this will succeed. No need for try_module_get().
|
||||
*/
|
||||
__module_get(THIS_MODULE);
|
||||
tcp_ses->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread,
|
||||
tcp_ses, "cifsd");
|
||||
if (IS_ERR(tcp_ses->tsk)) {
|
||||
rc = PTR_ERR(tcp_ses->tsk);
|
||||
cERROR(1, ("error %d create cifsd thread", rc));
|
||||
module_put(THIS_MODULE);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* thread spawned, put it on the list */
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
return tcp_ses;
|
||||
|
||||
out_err:
|
||||
if (tcp_ses) {
|
||||
kfree(tcp_ses->hostname);
|
||||
if (tcp_ses->ssocket)
|
||||
sock_release(tcp_ses->ssocket);
|
||||
kfree(tcp_ses);
|
||||
}
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
static struct cifsSesInfo *
|
||||
cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
|
||||
{
|
||||
@ -1593,93 +1728,96 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
|
||||
|
||||
|
||||
static int
|
||||
ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
|
||||
char *netbios_name, char *target_name,
|
||||
bool noblocksnd, bool noautotune)
|
||||
ipv4_connect(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
int connected = 0;
|
||||
bool connected = false;
|
||||
__be16 orig_port = 0;
|
||||
struct socket *socket = server->ssocket;
|
||||
|
||||
if (*csocket == NULL) {
|
||||
if (socket == NULL) {
|
||||
rc = sock_create_kern(PF_INET, SOCK_STREAM,
|
||||
IPPROTO_TCP, csocket);
|
||||
IPPROTO_TCP, &socket);
|
||||
if (rc < 0) {
|
||||
cERROR(1, ("Error %d creating socket", rc));
|
||||
*csocket = NULL;
|
||||
return rc;
|
||||
} else {
|
||||
/* BB other socket options to set KEEPALIVE, NODELAY? */
|
||||
cFYI(1, ("Socket created"));
|
||||
(*csocket)->sk->sk_allocation = GFP_NOFS;
|
||||
cifs_reclassify_socket4(*csocket);
|
||||
}
|
||||
|
||||
/* BB other socket options to set KEEPALIVE, NODELAY? */
|
||||
cFYI(1, ("Socket created"));
|
||||
server->ssocket = socket;
|
||||
socket->sk->sk_allocation = GFP_NOFS;
|
||||
cifs_reclassify_socket4(socket);
|
||||
}
|
||||
|
||||
psin_server->sin_family = AF_INET;
|
||||
if (psin_server->sin_port) { /* user overrode default port */
|
||||
rc = (*csocket)->ops->connect(*csocket,
|
||||
(struct sockaddr *) psin_server,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
/* user overrode default port */
|
||||
if (server->addr.sockAddr.sin_port) {
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (rc >= 0)
|
||||
connected = 1;
|
||||
connected = true;
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
/* save original port so we can retry user specified port
|
||||
later if fall back ports fail this time */
|
||||
orig_port = psin_server->sin_port;
|
||||
orig_port = server->addr.sockAddr.sin_port;
|
||||
|
||||
/* do not retry on the same port we just failed on */
|
||||
if (psin_server->sin_port != htons(CIFS_PORT)) {
|
||||
psin_server->sin_port = htons(CIFS_PORT);
|
||||
|
||||
rc = (*csocket)->ops->connect(*csocket,
|
||||
(struct sockaddr *) psin_server,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) {
|
||||
server->addr.sockAddr.sin_port = htons(CIFS_PORT);
|
||||
rc = socket->ops->connect(socket,
|
||||
(struct sockaddr *)
|
||||
&server->addr.sockAddr,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (rc >= 0)
|
||||
connected = 1;
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
psin_server->sin_port = htons(RFC1001_PORT);
|
||||
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
|
||||
psin_server,
|
||||
server->addr.sockAddr.sin_port = htons(RFC1001_PORT);
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr,
|
||||
sizeof(struct sockaddr_in), 0);
|
||||
if (rc >= 0)
|
||||
connected = 1;
|
||||
connected = true;
|
||||
}
|
||||
|
||||
/* give up here - unless we want to retry on different
|
||||
protocol families some day */
|
||||
if (!connected) {
|
||||
if (orig_port)
|
||||
psin_server->sin_port = orig_port;
|
||||
server->addr.sockAddr.sin_port = orig_port;
|
||||
cFYI(1, ("Error %d connecting to server via ipv4", rc));
|
||||
sock_release(*csocket);
|
||||
*csocket = NULL;
|
||||
sock_release(socket);
|
||||
server->ssocket = NULL;
|
||||
return rc;
|
||||
}
|
||||
/* Eventually check for other socket options to change from
|
||||
the default. sock_setsockopt not used because it expects
|
||||
user space buffer */
|
||||
cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
|
||||
(*csocket)->sk->sk_sndbuf,
|
||||
(*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
|
||||
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
|
||||
if (!noblocksnd)
|
||||
(*csocket)->sk->sk_sndtimeo = 3 * HZ;
|
||||
|
||||
|
||||
/*
|
||||
* Eventually check for other socket options to change from
|
||||
* the default. sock_setsockopt not used because it expects
|
||||
* user space buffer
|
||||
*/
|
||||
socket->sk->sk_rcvtimeo = 7 * HZ;
|
||||
socket->sk->sk_sndtimeo = 3 * HZ;
|
||||
|
||||
/* make the bufsizes depend on wsize/rsize and max requests */
|
||||
if (noautotune) {
|
||||
if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
|
||||
(*csocket)->sk->sk_sndbuf = 200 * 1024;
|
||||
if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
|
||||
(*csocket)->sk->sk_rcvbuf = 140 * 1024;
|
||||
if (server->noautotune) {
|
||||
if (socket->sk->sk_sndbuf < (200 * 1024))
|
||||
socket->sk->sk_sndbuf = 200 * 1024;
|
||||
if (socket->sk->sk_rcvbuf < (140 * 1024))
|
||||
socket->sk->sk_rcvbuf = 140 * 1024;
|
||||
}
|
||||
|
||||
cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
|
||||
socket->sk->sk_sndbuf,
|
||||
socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo));
|
||||
|
||||
/* send RFC1001 sessinit */
|
||||
if (psin_server->sin_port == htons(RFC1001_PORT)) {
|
||||
if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) {
|
||||
/* some servers require RFC1001 sessinit before sending
|
||||
negprot - BB check reconnection in case where second
|
||||
sessinit is sent but no second negprot */
|
||||
@ -1689,31 +1827,42 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
|
||||
GFP_KERNEL);
|
||||
if (ses_init_buf) {
|
||||
ses_init_buf->trailer.session_req.called_len = 32;
|
||||
if (target_name && (target_name[0] != 0)) {
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
|
||||
target_name, 16);
|
||||
} else {
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
|
||||
DEFAULT_CIFS_CALLED_NAME, 16);
|
||||
}
|
||||
if (server->server_RFC1001_name &&
|
||||
server->server_RFC1001_name[0] != 0)
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.called_name,
|
||||
server->server_RFC1001_name,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
else
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.called_name,
|
||||
DEFAULT_CIFS_CALLED_NAME,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
ses_init_buf->trailer.session_req.calling_len = 32;
|
||||
|
||||
/* calling name ends in null (byte 16) from old smb
|
||||
convention. */
|
||||
if (netbios_name && (netbios_name[0] != 0)) {
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
|
||||
netbios_name, 16);
|
||||
} else {
|
||||
rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
|
||||
"LINUX_CIFS_CLNT", 16);
|
||||
}
|
||||
if (server->workstation_RFC1001_name &&
|
||||
server->workstation_RFC1001_name[0] != 0)
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.calling_name,
|
||||
server->workstation_RFC1001_name,
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
else
|
||||
rfc1002mangle(ses_init_buf->trailer.
|
||||
session_req.calling_name,
|
||||
"LINUX_CIFS_CLNT",
|
||||
RFC1001_NAME_LEN_WITH_NULL);
|
||||
|
||||
ses_init_buf->trailer.session_req.scope1 = 0;
|
||||
ses_init_buf->trailer.session_req.scope2 = 0;
|
||||
smb_buf = (struct smb_hdr *)ses_init_buf;
|
||||
/* sizeof RFC1002_SESSION_REQUEST with no scope */
|
||||
smb_buf->smb_buf_length = 0x81000044;
|
||||
rc = smb_send(*csocket, smb_buf, 0x44,
|
||||
(struct sockaddr *)psin_server, noblocksnd);
|
||||
rc = smb_send(socket, smb_buf, 0x44,
|
||||
(struct sockaddr *) &server->addr.sockAddr,
|
||||
server->noblocksnd);
|
||||
kfree(ses_init_buf);
|
||||
msleep(1); /* RFC1001 layer in at least one server
|
||||
requires very short break before negprot
|
||||
@ -1733,79 +1882,81 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
|
||||
}
|
||||
|
||||
static int
|
||||
ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
|
||||
bool noblocksnd)
|
||||
ipv6_connect(struct TCP_Server_Info *server)
|
||||
{
|
||||
int rc = 0;
|
||||
int connected = 0;
|
||||
bool connected = false;
|
||||
__be16 orig_port = 0;
|
||||
struct socket *socket = server->ssocket;
|
||||
|
||||
if (*csocket == NULL) {
|
||||
if (socket == NULL) {
|
||||
rc = sock_create_kern(PF_INET6, SOCK_STREAM,
|
||||
IPPROTO_TCP, csocket);
|
||||
IPPROTO_TCP, &socket);
|
||||
if (rc < 0) {
|
||||
cERROR(1, ("Error %d creating ipv6 socket", rc));
|
||||
*csocket = NULL;
|
||||
socket = NULL;
|
||||
return rc;
|
||||
} else {
|
||||
/* BB other socket options to set KEEPALIVE, NODELAY? */
|
||||
cFYI(1, ("ipv6 Socket created"));
|
||||
(*csocket)->sk->sk_allocation = GFP_NOFS;
|
||||
cifs_reclassify_socket6(*csocket);
|
||||
}
|
||||
|
||||
/* BB other socket options to set KEEPALIVE, NODELAY? */
|
||||
cFYI(1, ("ipv6 Socket created"));
|
||||
server->ssocket = socket;
|
||||
socket->sk->sk_allocation = GFP_NOFS;
|
||||
cifs_reclassify_socket6(socket);
|
||||
}
|
||||
|
||||
psin_server->sin6_family = AF_INET6;
|
||||
|
||||
if (psin_server->sin6_port) { /* user overrode default port */
|
||||
rc = (*csocket)->ops->connect(*csocket,
|
||||
(struct sockaddr *) psin_server,
|
||||
/* user overrode default port */
|
||||
if (server->addr.sockAddr6.sin6_port) {
|
||||
rc = socket->ops->connect(socket,
|
||||
(struct sockaddr *) &server->addr.sockAddr6,
|
||||
sizeof(struct sockaddr_in6), 0);
|
||||
if (rc >= 0)
|
||||
connected = 1;
|
||||
connected = true;
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
/* save original port so we can retry user specified port
|
||||
later if fall back ports fail this time */
|
||||
|
||||
orig_port = psin_server->sin6_port;
|
||||
orig_port = server->addr.sockAddr6.sin6_port;
|
||||
/* do not retry on the same port we just failed on */
|
||||
if (psin_server->sin6_port != htons(CIFS_PORT)) {
|
||||
psin_server->sin6_port = htons(CIFS_PORT);
|
||||
|
||||
rc = (*csocket)->ops->connect(*csocket,
|
||||
(struct sockaddr *) psin_server,
|
||||
if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) {
|
||||
server->addr.sockAddr6.sin6_port = htons(CIFS_PORT);
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr6,
|
||||
sizeof(struct sockaddr_in6), 0);
|
||||
if (rc >= 0)
|
||||
connected = 1;
|
||||
connected = true;
|
||||
}
|
||||
}
|
||||
if (!connected) {
|
||||
psin_server->sin6_port = htons(RFC1001_PORT);
|
||||
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
|
||||
psin_server, sizeof(struct sockaddr_in6), 0);
|
||||
server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT);
|
||||
rc = socket->ops->connect(socket, (struct sockaddr *)
|
||||
&server->addr.sockAddr6,
|
||||
sizeof(struct sockaddr_in6), 0);
|
||||
if (rc >= 0)
|
||||
connected = 1;
|
||||
connected = true;
|
||||
}
|
||||
|
||||
/* give up here - unless we want to retry on different
|
||||
protocol families some day */
|
||||
if (!connected) {
|
||||
if (orig_port)
|
||||
psin_server->sin6_port = orig_port;
|
||||
server->addr.sockAddr6.sin6_port = orig_port;
|
||||
cFYI(1, ("Error %d connecting to server via ipv6", rc));
|
||||
sock_release(*csocket);
|
||||
*csocket = NULL;
|
||||
sock_release(socket);
|
||||
server->ssocket = NULL;
|
||||
return rc;
|
||||
}
|
||||
/* Eventually check for other socket options to change from
|
||||
the default. sock_setsockopt not used because it expects
|
||||
user space buffer */
|
||||
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
|
||||
if (!noblocksnd)
|
||||
(*csocket)->sk->sk_sndtimeo = 3 * HZ;
|
||||
|
||||
/*
|
||||
* Eventually check for other socket options to change from
|
||||
* the default. sock_setsockopt not used because it expects
|
||||
* user space buffer
|
||||
*/
|
||||
socket->sk->sk_rcvtimeo = 7 * HZ;
|
||||
socket->sk->sk_sndtimeo = 3 * HZ;
|
||||
server->ssocket = socket;
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -2011,6 +2162,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
|
||||
if (pvolume_info->nobrl)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
|
||||
if (pvolume_info->mand_lock)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NOPOSIXBRL;
|
||||
if (pvolume_info->cifs_acl)
|
||||
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
|
||||
if (pvolume_info->override_uid)
|
||||
@ -2035,32 +2188,30 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
{
|
||||
int rc = 0;
|
||||
int xid;
|
||||
struct socket *csocket = NULL;
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
|
||||
struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
|
||||
struct smb_vol volume_info;
|
||||
struct smb_vol *volume_info;
|
||||
struct cifsSesInfo *pSesInfo = NULL;
|
||||
struct cifsTconInfo *tcon = NULL;
|
||||
struct TCP_Server_Info *srvTcp = NULL;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
|
||||
volume_info = kzalloc(sizeof(struct smb_vol), GFP_KERNEL);
|
||||
if (!volume_info) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(struct sockaddr));
|
||||
memset(&volume_info, 0, sizeof(struct smb_vol));
|
||||
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
|
||||
if (cifs_parse_mount_options(mount_data, devname, volume_info)) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (volume_info.nullauth) {
|
||||
if (volume_info->nullauth) {
|
||||
cFYI(1, ("null user"));
|
||||
volume_info.username = "";
|
||||
} else if (volume_info.username) {
|
||||
volume_info->username = "";
|
||||
} else if (volume_info->username) {
|
||||
/* BB fixme parse for domain name here */
|
||||
cFYI(1, ("Username: %s", volume_info.username));
|
||||
cFYI(1, ("Username: %s", volume_info->username));
|
||||
} else {
|
||||
cifserror("No username specified");
|
||||
/* In userspace mount helper we can get user name from alternate
|
||||
@ -2069,139 +2220,29 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (volume_info.UNCip && volume_info.UNC) {
|
||||
rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
|
||||
&sin_server->sin_addr.s_addr);
|
||||
|
||||
if (rc <= 0) {
|
||||
/* not ipv4 address, try ipv6 */
|
||||
rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
|
||||
&sin_server6->sin6_addr.in6_u);
|
||||
if (rc > 0)
|
||||
addr.sa_family = AF_INET6;
|
||||
} else {
|
||||
addr.sa_family = AF_INET;
|
||||
}
|
||||
|
||||
if (rc <= 0) {
|
||||
/* we failed translating address */
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
|
||||
/* success */
|
||||
rc = 0;
|
||||
} else if (volume_info.UNCip) {
|
||||
/* BB using ip addr as server name to connect to the
|
||||
DFS root below */
|
||||
cERROR(1, ("Connecting to DFS root not implemented yet"));
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
} else /* which servers DFS root would we conect to */ {
|
||||
cERROR(1,
|
||||
("CIFS mount error: No UNC path (e.g. -o "
|
||||
"unc=//192.168.1.100/public) specified"));
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* this is needed for ASCII cp to Unicode converts */
|
||||
if (volume_info.iocharset == NULL) {
|
||||
if (volume_info->iocharset == NULL) {
|
||||
cifs_sb->local_nls = load_nls_default();
|
||||
/* load_nls_default can not return null */
|
||||
} else {
|
||||
cifs_sb->local_nls = load_nls(volume_info.iocharset);
|
||||
cifs_sb->local_nls = load_nls(volume_info->iocharset);
|
||||
if (cifs_sb->local_nls == NULL) {
|
||||
cERROR(1, ("CIFS mount error: iocharset %s not found",
|
||||
volume_info.iocharset));
|
||||
volume_info->iocharset));
|
||||
rc = -ELIBACC;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
srvTcp = cifs_find_tcp_session(&addr);
|
||||
if (!srvTcp) { /* create socket */
|
||||
if (addr.sa_family == AF_INET6) {
|
||||
cFYI(1, ("attempting ipv6 connect"));
|
||||
/* BB should we allow ipv6 on port 139? */
|
||||
/* other OS never observed in Wild doing 139 with v6 */
|
||||
sin_server6->sin6_port = htons(volume_info.port);
|
||||
rc = ipv6_connect(sin_server6, &csocket,
|
||||
volume_info.noblocksnd);
|
||||
} else {
|
||||
sin_server->sin_port = htons(volume_info.port);
|
||||
rc = ipv4_connect(sin_server, &csocket,
|
||||
volume_info.source_rfc1001_name,
|
||||
volume_info.target_rfc1001_name,
|
||||
volume_info.noblocksnd,
|
||||
volume_info.noautotune);
|
||||
}
|
||||
if (rc < 0) {
|
||||
cERROR(1, ("Error connecting to socket. "
|
||||
"Aborting operation"));
|
||||
if (csocket != NULL)
|
||||
sock_release(csocket);
|
||||
goto out;
|
||||
}
|
||||
|
||||
srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL);
|
||||
if (!srvTcp) {
|
||||
rc = -ENOMEM;
|
||||
sock_release(csocket);
|
||||
goto out;
|
||||
} else {
|
||||
srvTcp->noblocksnd = volume_info.noblocksnd;
|
||||
srvTcp->noautotune = volume_info.noautotune;
|
||||
if (addr.sa_family == AF_INET6)
|
||||
memcpy(&srvTcp->addr.sockAddr6, sin_server6,
|
||||
sizeof(struct sockaddr_in6));
|
||||
else
|
||||
memcpy(&srvTcp->addr.sockAddr, sin_server,
|
||||
sizeof(struct sockaddr_in));
|
||||
atomic_set(&srvTcp->inFlight, 0);
|
||||
/* BB Add code for ipv6 case too */
|
||||
srvTcp->ssocket = csocket;
|
||||
srvTcp->hostname = extract_hostname(volume_info.UNC);
|
||||
if (IS_ERR(srvTcp->hostname)) {
|
||||
rc = PTR_ERR(srvTcp->hostname);
|
||||
sock_release(csocket);
|
||||
goto out;
|
||||
}
|
||||
init_waitqueue_head(&srvTcp->response_q);
|
||||
init_waitqueue_head(&srvTcp->request_q);
|
||||
INIT_LIST_HEAD(&srvTcp->pending_mid_q);
|
||||
/* at this point we are the only ones with the pointer
|
||||
to the struct since the kernel thread not created yet
|
||||
so no need to spinlock this init of tcpStatus */
|
||||
srvTcp->tcpStatus = CifsNew;
|
||||
init_MUTEX(&srvTcp->tcpSem);
|
||||
srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
|
||||
if (IS_ERR(srvTcp->tsk)) {
|
||||
rc = PTR_ERR(srvTcp->tsk);
|
||||
cERROR(1, ("error %d create cifsd thread", rc));
|
||||
srvTcp->tsk = NULL;
|
||||
sock_release(csocket);
|
||||
kfree(srvTcp->hostname);
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
memcpy(srvTcp->workstation_RFC1001_name,
|
||||
volume_info.source_rfc1001_name, 16);
|
||||
memcpy(srvTcp->server_RFC1001_name,
|
||||
volume_info.target_rfc1001_name, 16);
|
||||
srvTcp->sequence_number = 0;
|
||||
INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
|
||||
INIT_LIST_HEAD(&srvTcp->smb_ses_list);
|
||||
++srvTcp->srv_count;
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
list_add(&srvTcp->tcp_ses_list,
|
||||
&cifs_tcp_ses_list);
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
}
|
||||
/* get a reference to a tcp session */
|
||||
srvTcp = cifs_get_tcp_session(volume_info);
|
||||
if (IS_ERR(srvTcp)) {
|
||||
rc = PTR_ERR(srvTcp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
|
||||
pSesInfo = cifs_find_smb_ses(srvTcp, volume_info->username);
|
||||
if (pSesInfo) {
|
||||
cFYI(1, ("Existing smb sess found (status=%d)",
|
||||
pSesInfo->status));
|
||||
@ -2228,31 +2269,38 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
|
||||
/* new SMB session uses our srvTcp ref */
|
||||
pSesInfo->server = srvTcp;
|
||||
sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
|
||||
NIPQUAD(sin_server->sin_addr.s_addr));
|
||||
if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6)
|
||||
sprintf(pSesInfo->serverName, NIP6_FMT,
|
||||
NIP6(srvTcp->addr.sockAddr6.sin6_addr));
|
||||
else
|
||||
sprintf(pSesInfo->serverName, NIPQUAD_FMT,
|
||||
NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr));
|
||||
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
|
||||
/* volume_info.password freed at unmount */
|
||||
if (volume_info.password) {
|
||||
pSesInfo->password = volume_info.password;
|
||||
/* set to NULL to prevent freeing on exit */
|
||||
volume_info.password = NULL;
|
||||
/* volume_info->password freed at unmount */
|
||||
if (volume_info->password) {
|
||||
pSesInfo->password = kstrdup(volume_info->password,
|
||||
GFP_KERNEL);
|
||||
if (!pSesInfo->password) {
|
||||
rc = -ENOMEM;
|
||||
goto mount_fail_check;
|
||||
}
|
||||
}
|
||||
if (volume_info.username)
|
||||
strncpy(pSesInfo->userName, volume_info.username,
|
||||
if (volume_info->username)
|
||||
strncpy(pSesInfo->userName, volume_info->username,
|
||||
MAX_USERNAME_SIZE);
|
||||
if (volume_info.domainname) {
|
||||
int len = strlen(volume_info.domainname);
|
||||
if (volume_info->domainname) {
|
||||
int len = strlen(volume_info->domainname);
|
||||
pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (pSesInfo->domainName)
|
||||
strcpy(pSesInfo->domainName,
|
||||
volume_info.domainname);
|
||||
volume_info->domainname);
|
||||
}
|
||||
pSesInfo->linux_uid = volume_info.linux_uid;
|
||||
pSesInfo->overrideSecFlg = volume_info.secFlg;
|
||||
pSesInfo->linux_uid = volume_info->linux_uid;
|
||||
pSesInfo->overrideSecFlg = volume_info->secFlg;
|
||||
down(&pSesInfo->sesSem);
|
||||
|
||||
/* BB FIXME need to pass vol->secFlgs BB */
|
||||
@ -2263,14 +2311,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
|
||||
/* search for existing tcon to this server share */
|
||||
if (!rc) {
|
||||
setup_cifs_sb(&volume_info, cifs_sb);
|
||||
setup_cifs_sb(volume_info, cifs_sb);
|
||||
|
||||
tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
|
||||
tcon = cifs_find_tcon(pSesInfo, volume_info->UNC);
|
||||
if (tcon) {
|
||||
cFYI(1, ("Found match on UNC path"));
|
||||
/* existing tcon already has a reference */
|
||||
cifs_put_smb_ses(pSesInfo);
|
||||
if (tcon->seal != volume_info.seal)
|
||||
if (tcon->seal != volume_info->seal)
|
||||
cERROR(1, ("transport encryption setting "
|
||||
"conflicts with existing tid"));
|
||||
} else {
|
||||
@ -2279,11 +2327,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
rc = -ENOMEM;
|
||||
goto mount_fail_check;
|
||||
}
|
||||
|
||||
tcon->ses = pSesInfo;
|
||||
if (volume_info->password) {
|
||||
tcon->password = kstrdup(volume_info->password,
|
||||
GFP_KERNEL);
|
||||
if (!tcon->password) {
|
||||
rc = -ENOMEM;
|
||||
goto mount_fail_check;
|
||||
}
|
||||
}
|
||||
|
||||
/* check for null share name ie connect to dfs root */
|
||||
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
|
||||
&& (strchr(volume_info.UNC + 3, '/') == NULL)) {
|
||||
if ((strchr(volume_info->UNC + 3, '\\') == NULL)
|
||||
&& (strchr(volume_info->UNC + 3, '/') == NULL)) {
|
||||
/* rc = connect_to_dfs_path(...) */
|
||||
cFYI(1, ("DFS root not supported"));
|
||||
rc = -ENODEV;
|
||||
@ -2292,10 +2349,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
/* BB Do we need to wrap sesSem around
|
||||
* this TCon call and Unix SetFS as
|
||||
* we do on SessSetup and reconnect? */
|
||||
rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
|
||||
rc = CIFSTCon(xid, pSesInfo, volume_info->UNC,
|
||||
tcon, cifs_sb->local_nls);
|
||||
cFYI(1, ("CIFS Tcon rc = %d", rc));
|
||||
if (volume_info.nodfs) {
|
||||
if (volume_info->nodfs) {
|
||||
tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
|
||||
cFYI(1, ("DFS disabled (%d)",
|
||||
tcon->Flags));
|
||||
@ -2303,7 +2360,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
}
|
||||
if (rc)
|
||||
goto mount_fail_check;
|
||||
tcon->seal = volume_info.seal;
|
||||
tcon->seal = volume_info->seal;
|
||||
write_lock(&cifs_tcp_ses_lock);
|
||||
list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
|
||||
write_unlock(&cifs_tcp_ses_lock);
|
||||
@ -2313,9 +2370,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
||||
to a share so for resources mounted more than once
|
||||
to the same server share the last value passed in
|
||||
for the retry flag is used */
|
||||
tcon->retry = volume_info.retry;
|
||||
tcon->nocase = volume_info.nocase;
|
||||
tcon->local_lease = volume_info.local_lease;
|
||||
tcon->retry = volume_info->retry;
|
||||
tcon->nocase = volume_info->nocase;
|
||||
tcon->local_lease = volume_info->local_lease;
|
||||
}
|
||||
if (pSesInfo) {
|
||||
if (pSesInfo->capabilities & CAP_LARGE_FILES) {
|
||||
@ -2352,7 +2409,7 @@ mount_fail_check:
|
||||
if (tcon->ses->capabilities & CAP_UNIX)
|
||||
/* reset of caps checks mount to see if unix extensions
|
||||
disabled for just this mount */
|
||||
reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
|
||||
reset_cifs_unix_caps(xid, tcon, sb, volume_info);
|
||||
else
|
||||
tcon->unix_ext = 0; /* server does not support them */
|
||||
|
||||
@ -2371,18 +2428,22 @@ mount_fail_check:
|
||||
cifs_sb->rsize = min(cifs_sb->rsize,
|
||||
(tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
|
||||
|
||||
/* volume_info.password is freed above when existing session found
|
||||
/* volume_info->password is freed above when existing session found
|
||||
(in which case it is not needed anymore) but when new sesion is created
|
||||
the password ptr is put in the new session structure (in which case the
|
||||
password will be freed at unmount time) */
|
||||
out:
|
||||
/* zero out password before freeing */
|
||||
if (volume_info.password != NULL) {
|
||||
memset(volume_info.password, 0, strlen(volume_info.password));
|
||||
kfree(volume_info.password);
|
||||
if (volume_info) {
|
||||
if (volume_info->password != NULL) {
|
||||
memset(volume_info->password, 0,
|
||||
strlen(volume_info->password));
|
||||
kfree(volume_info->password);
|
||||
}
|
||||
kfree(volume_info->UNC);
|
||||
kfree(volume_info->prepath);
|
||||
kfree(volume_info);
|
||||
}
|
||||
kfree(volume_info.UNC);
|
||||
kfree(volume_info.prepath);
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
@ -2533,7 +2594,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
__u16 action = le16_to_cpu(pSMBr->resp.Action);
|
||||
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
|
||||
if (action & GUEST_LOGIN)
|
||||
cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
|
||||
cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */
|
||||
ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
|
||||
(little endian) */
|
||||
cFYI(1, ("UID = %d ", ses->Suid));
|
||||
@ -2679,13 +2740,11 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
len));
|
||||
}
|
||||
} else {
|
||||
cERROR(1,
|
||||
(" Security Blob Length extends beyond "
|
||||
cERROR(1, ("Security Blob Length extends beyond "
|
||||
"end of SMB"));
|
||||
}
|
||||
} else {
|
||||
cERROR(1,
|
||||
(" Invalid Word count %d: ",
|
||||
cERROR(1, ("Invalid Word count %d: ",
|
||||
smb_buffer_response->WordCount));
|
||||
rc = -EIO;
|
||||
}
|
||||
@ -2843,7 +2902,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
||||
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
|
||||
|
||||
if (action & GUEST_LOGIN)
|
||||
cFYI(1, (" Guest login"));
|
||||
cFYI(1, ("Guest login"));
|
||||
/* Do we want to set anything in SesInfo struct when guest login? */
|
||||
|
||||
bcc_ptr = pByteArea(smb_buffer_response);
|
||||
@ -2851,8 +2910,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
||||
|
||||
SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
|
||||
if (SecurityBlob2->MessageType != NtLmChallenge) {
|
||||
cFYI(1,
|
||||
("Unexpected NTLMSSP message type received %d",
|
||||
cFYI(1, ("Unexpected NTLMSSP message type received %d",
|
||||
SecurityBlob2->MessageType));
|
||||
} else if (ses) {
|
||||
ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
|
||||
@ -3024,8 +3082,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
|
||||
cERROR(1, ("No session structure passed in."));
|
||||
}
|
||||
} else {
|
||||
cERROR(1,
|
||||
(" Invalid Word count %d:",
|
||||
cERROR(1, ("Invalid Word count %d:",
|
||||
smb_buffer_response->WordCount));
|
||||
rc = -EIO;
|
||||
}
|
||||
@ -3264,7 +3321,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
|
||||
__u16 action = le16_to_cpu(pSMBr->resp.Action);
|
||||
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
|
||||
if (action & GUEST_LOGIN)
|
||||
cFYI(1, (" Guest login")); /* BB Should we set anything
|
||||
cFYI(1, ("Guest login")); /* BB Should we set anything
|
||||
in SesInfo struct ? */
|
||||
/* if (SecurityBlob2->MessageType != NtLm??) {
|
||||
cFYI("Unexpected message type on auth response is %d"));
|
||||
@ -3487,12 +3544,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
|
||||
NTLMv2 password here) */
|
||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||
if ((extended_security & CIFSSEC_MAY_LANMAN) &&
|
||||
(ses->server->secType == LANMAN))
|
||||
calc_lanman_hash(ses, bcc_ptr);
|
||||
(ses->server->secType == LANMAN))
|
||||
calc_lanman_hash(tcon->password, ses->server->cryptKey,
|
||||
ses->server->secMode &
|
||||
SECMODE_PW_ENCRYPT ? true : false,
|
||||
bcc_ptr);
|
||||
else
|
||||
#endif /* CIFS_WEAK_PW_HASH */
|
||||
SMBNTencrypt(ses->password,
|
||||
ses->server->cryptKey,
|
||||
SMBNTencrypt(tcon->password, ses->server->cryptKey,
|
||||
bcc_ptr);
|
||||
|
||||
bcc_ptr += CIFS_SESS_KEY_SIZE;
|
||||
|
@ -483,7 +483,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p",
|
||||
cFYI(1, ("parent inode = 0x%p name is: %s and dentry = 0x%p",
|
||||
parent_dir_inode, direntry->d_name.name, direntry));
|
||||
|
||||
/* check whether path exists */
|
||||
@ -515,12 +515,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
}
|
||||
|
||||
if (direntry->d_inode != NULL) {
|
||||
cFYI(1, (" non-NULL inode in lookup"));
|
||||
cFYI(1, ("non-NULL inode in lookup"));
|
||||
} else {
|
||||
cFYI(1, (" NULL inode in lookup"));
|
||||
cFYI(1, ("NULL inode in lookup"));
|
||||
}
|
||||
cFYI(1,
|
||||
(" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
|
||||
cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode));
|
||||
|
||||
if (pTcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&newInode, full_path,
|
||||
|
@ -644,10 +644,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
__u64 length;
|
||||
bool wait_flag = false;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct cifsTconInfo *pTcon;
|
||||
struct cifsTconInfo *tcon;
|
||||
__u16 netfid;
|
||||
__u8 lockType = LOCKING_ANDX_LARGE_FILES;
|
||||
bool posix_locking;
|
||||
bool posix_locking = 0;
|
||||
|
||||
length = 1 + pfLock->fl_end - pfLock->fl_start;
|
||||
rc = -EACCES;
|
||||
@ -698,7 +698,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
cFYI(1, ("Unknown type of lock"));
|
||||
|
||||
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
|
||||
pTcon = cifs_sb->tcon;
|
||||
tcon = cifs_sb->tcon;
|
||||
|
||||
if (file->private_data == NULL) {
|
||||
FreeXid(xid);
|
||||
@ -706,9 +706,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
}
|
||||
netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
|
||||
|
||||
posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));
|
||||
|
||||
if ((tcon->ses->capabilities & CAP_UNIX) &&
|
||||
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
|
||||
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
|
||||
posix_locking = 1;
|
||||
/* BB add code here to normalize offset and length to
|
||||
account for negative length which we can not accept over the
|
||||
wire */
|
||||
@ -719,7 +720,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
posix_lock_type = CIFS_RDLCK;
|
||||
else
|
||||
posix_lock_type = CIFS_WRLCK;
|
||||
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,
|
||||
rc = CIFSSMBPosixLock(xid, tcon, netfid, 1 /* get */,
|
||||
length, pfLock,
|
||||
posix_lock_type, wait_flag);
|
||||
FreeXid(xid);
|
||||
@ -727,10 +728,10 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
}
|
||||
|
||||
/* BB we could chain these into one lock request BB */
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
|
||||
rc = CIFSSMBLock(xid, tcon, netfid, length, pfLock->fl_start,
|
||||
0, 1, lockType, 0 /* wait flag */ );
|
||||
if (rc == 0) {
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length,
|
||||
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||
pfLock->fl_start, 1 /* numUnlock */ ,
|
||||
0 /* numLock */ , lockType,
|
||||
0 /* wait flag */ );
|
||||
@ -767,7 +768,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
if (numUnlock == 1)
|
||||
posix_lock_type = CIFS_UNLCK;
|
||||
|
||||
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
|
||||
rc = CIFSSMBPosixLock(xid, tcon, netfid, 0 /* set */,
|
||||
length, pfLock,
|
||||
posix_lock_type, wait_flag);
|
||||
} else {
|
||||
@ -775,7 +776,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
(struct cifsFileInfo *)file->private_data;
|
||||
|
||||
if (numLock) {
|
||||
rc = CIFSSMBLock(xid, pTcon, netfid, length,
|
||||
rc = CIFSSMBLock(xid, tcon, netfid, length,
|
||||
pfLock->fl_start,
|
||||
0, numLock, lockType, wait_flag);
|
||||
|
||||
@ -796,7 +797,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
|
||||
if (pfLock->fl_start <= li->offset &&
|
||||
(pfLock->fl_start + length) >=
|
||||
(li->offset + li->length)) {
|
||||
stored_rc = CIFSSMBLock(xid, pTcon,
|
||||
stored_rc = CIFSSMBLock(xid, tcon,
|
||||
netfid,
|
||||
li->length, li->offset,
|
||||
1, 0, li->type, false);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* fs/cifs/inode.c
|
||||
*
|
||||
* Copyright (C) International Business Machines Corp., 2002,2007
|
||||
* Copyright (C) International Business Machines Corp., 2002,2008
|
||||
* Author(s): Steve French (sfrench@us.ibm.com)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
@ -621,6 +621,47 @@ static const struct inode_operations cifs_ipc_inode_ops = {
|
||||
.lookup = cifs_lookup,
|
||||
};
|
||||
|
||||
static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
int pplen = cifs_sb->prepathlen;
|
||||
int dfsplen;
|
||||
char *full_path = NULL;
|
||||
|
||||
/* if no prefix path, simply set path to the root of share to "" */
|
||||
if (pplen == 0) {
|
||||
full_path = kmalloc(1, GFP_KERNEL);
|
||||
if (full_path)
|
||||
full_path[0] = 0;
|
||||
return full_path;
|
||||
}
|
||||
|
||||
if (cifs_sb->tcon && (cifs_sb->tcon->Flags & SMB_SHARE_IS_IN_DFS))
|
||||
dfsplen = strnlen(cifs_sb->tcon->treeName, MAX_TREE_SIZE + 1);
|
||||
else
|
||||
dfsplen = 0;
|
||||
|
||||
full_path = kmalloc(dfsplen + pplen + 1, GFP_KERNEL);
|
||||
if (full_path == NULL)
|
||||
return full_path;
|
||||
|
||||
if (dfsplen) {
|
||||
strncpy(full_path, cifs_sb->tcon->treeName, dfsplen);
|
||||
/* switch slash direction in prepath depending on whether
|
||||
* windows or posix style path names
|
||||
*/
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) {
|
||||
int i;
|
||||
for (i = 0; i < dfsplen; i++) {
|
||||
if (full_path[i] == '\\')
|
||||
full_path[i] = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
strncpy(full_path + dfsplen, cifs_sb->prepath, pplen);
|
||||
full_path[dfsplen + pplen] = 0; /* add trailing null */
|
||||
return full_path;
|
||||
}
|
||||
|
||||
/* gets root inode */
|
||||
struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
{
|
||||
@ -628,6 +669,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct inode *inode;
|
||||
long rc;
|
||||
char *full_path;
|
||||
|
||||
inode = iget_locked(sb, ino);
|
||||
if (!inode)
|
||||
@ -636,13 +678,17 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
return inode;
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
xid = GetXid();
|
||||
full_path = build_path_to_root(cifs_sb);
|
||||
if (full_path == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
xid = GetXid();
|
||||
if (cifs_sb->tcon->unix_ext)
|
||||
rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
|
||||
rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb,
|
||||
xid);
|
||||
else
|
||||
rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid,
|
||||
NULL);
|
||||
rc = cifs_get_inode_info(&inode, full_path, NULL, inode->i_sb,
|
||||
xid, NULL);
|
||||
if (rc && cifs_sb->tcon->ipc) {
|
||||
cFYI(1, ("ipc connection - fake read inode"));
|
||||
inode->i_mode |= S_IFDIR;
|
||||
@ -652,6 +698,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_uid = cifs_sb->mnt_uid;
|
||||
inode->i_gid = cifs_sb->mnt_gid;
|
||||
} else if (rc) {
|
||||
kfree(full_path);
|
||||
_FreeXid(xid);
|
||||
iget_failed(inode);
|
||||
return ERR_PTR(rc);
|
||||
@ -659,6 +706,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
|
||||
|
||||
unlock_new_inode(inode);
|
||||
|
||||
kfree(full_path);
|
||||
/* can not call macro FreeXid here since in a void func
|
||||
* TODO: This is no longer true
|
||||
*/
|
||||
|
@ -97,7 +97,10 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
|
||||
kfree(buf_to_free->serverOS);
|
||||
kfree(buf_to_free->serverDomain);
|
||||
kfree(buf_to_free->serverNOS);
|
||||
kfree(buf_to_free->password);
|
||||
if (buf_to_free->password) {
|
||||
memset(buf_to_free->password, 0, strlen(buf_to_free->password));
|
||||
kfree(buf_to_free->password);
|
||||
}
|
||||
kfree(buf_to_free->domainName);
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
@ -129,6 +132,10 @@ tconInfoFree(struct cifsTconInfo *buf_to_free)
|
||||
}
|
||||
atomic_dec(&tconInfoAllocCount);
|
||||
kfree(buf_to_free->nativeFileSystem);
|
||||
if (buf_to_free->password) {
|
||||
memset(buf_to_free->password, 0, strlen(buf_to_free->password));
|
||||
kfree(buf_to_free->password);
|
||||
}
|
||||
kfree(buf_to_free);
|
||||
}
|
||||
|
||||
|
@ -417,7 +417,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
||||
/* BB calculate hash with password */
|
||||
/* and copy into bcc */
|
||||
|
||||
calc_lanman_hash(ses, lnm_session_key);
|
||||
calc_lanman_hash(ses->password, ses->server->cryptKey,
|
||||
ses->server->secMode & SECMODE_PW_ENCRYPT ?
|
||||
true : false, lnm_session_key);
|
||||
|
||||
ses->flags |= CIFS_SES_LANMAN;
|
||||
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
|
||||
bcc_ptr += CIFS_SESS_KEY_SIZE;
|
||||
|
@ -318,7 +318,8 @@ str_to_key(unsigned char *str, unsigned char *key)
|
||||
}
|
||||
|
||||
static void
|
||||
smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
|
||||
smbhash(unsigned char *out, const unsigned char *in, unsigned char *key,
|
||||
int forw)
|
||||
{
|
||||
int i;
|
||||
char *outb; /* outb[64] */
|
||||
@ -363,7 +364,7 @@ E_P16(unsigned char *p14, unsigned char *p16)
|
||||
}
|
||||
|
||||
void
|
||||
E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
|
||||
E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
smbhash(p24, c8, p21, 1);
|
||||
smbhash(p24 + 8, c8, p21 + 7, 1);
|
||||
|
@ -49,9 +49,10 @@
|
||||
|
||||
/*The following definitions come from libsmb/smbencrypt.c */
|
||||
|
||||
void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
|
||||
void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
|
||||
unsigned char *p24);
|
||||
void E_md4hash(const unsigned char *passwd, unsigned char *p16);
|
||||
static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
|
||||
static void SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
|
||||
unsigned char p24[24]);
|
||||
void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
|
||||
|
||||
@ -61,7 +62,7 @@ void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
|
||||
encrypted password into p24 */
|
||||
/* Note that password must be uppercased and null terminated */
|
||||
void
|
||||
SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
|
||||
SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24)
|
||||
{
|
||||
unsigned char p14[15], p21[21];
|
||||
|
||||
@ -212,7 +213,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
|
||||
|
||||
/* Does the des encryption from the NT or LM MD4 hash. */
|
||||
static void
|
||||
SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
|
||||
SMBOWFencrypt(unsigned char passwd[16], const unsigned char *c8,
|
||||
unsigned char p24[24])
|
||||
{
|
||||
unsigned char p21[21];
|
||||
|
@ -37,15 +37,11 @@ extern mempool_t *cifs_mid_poolp;
|
||||
extern struct kmem_cache *cifs_oplock_cachep;
|
||||
|
||||
static struct mid_q_entry *
|
||||
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
||||
AllocMidQEntry(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
|
||||
{
|
||||
struct mid_q_entry *temp;
|
||||
|
||||
if (ses == NULL) {
|
||||
cERROR(1, ("Null session passed in to AllocMidQEntry"));
|
||||
return NULL;
|
||||
}
|
||||
if (ses->server == NULL) {
|
||||
if (server == NULL) {
|
||||
cERROR(1, ("Null TCP session in AllocMidQEntry"));
|
||||
return NULL;
|
||||
}
|
||||
@ -62,12 +58,11 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
|
||||
/* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
|
||||
/* when mid allocated can be before when sent */
|
||||
temp->when_alloc = jiffies;
|
||||
temp->ses = ses;
|
||||
temp->tsk = current;
|
||||
}
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
|
||||
list_add_tail(&temp->qhead, &server->pending_mid_q);
|
||||
atomic_inc(&midCount);
|
||||
temp->midState = MID_REQUEST_ALLOCATED;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
@ -349,37 +344,38 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
|
||||
if (long_op == CIFS_ASYNC_OP) {
|
||||
/* oplock breaks must not be held up */
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
} else {
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
while (1) {
|
||||
if (atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* can not count locking commands against total
|
||||
as they are allowed to block on server */
|
||||
|
||||
/* update # of requests on the wire to server */
|
||||
if (long_op != CIFS_BLOCKING_OP)
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
while (1) {
|
||||
if (atomic_read(&ses->server->inFlight) >=
|
||||
cifs_max_pending){
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_inc(&ses->server->num_waiters);
|
||||
#endif
|
||||
wait_event(ses->server->request_q,
|
||||
atomic_read(&ses->server->inFlight)
|
||||
< cifs_max_pending);
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
atomic_dec(&ses->server->num_waiters);
|
||||
#endif
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
} else {
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
break;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* can not count locking commands against total
|
||||
as they are allowed to block on server */
|
||||
|
||||
/* update # of requests on the wire to server */
|
||||
if (long_op != CIFS_BLOCKING_OP)
|
||||
atomic_inc(&ses->server->inFlight);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -390,17 +386,21 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
|
||||
{
|
||||
if (ses->server->tcpStatus == CifsExiting) {
|
||||
return -ENOENT;
|
||||
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||
}
|
||||
|
||||
if (ses->server->tcpStatus == CifsNeedReconnect) {
|
||||
cFYI(1, ("tcp session dead - return to caller to retry"));
|
||||
return -EAGAIN;
|
||||
} else if (ses->status != CifsGood) {
|
||||
}
|
||||
|
||||
if (ses->status != CifsGood) {
|
||||
/* check if SMB session is bad because we are setting it up */
|
||||
if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
|
||||
(in_buf->Command != SMB_COM_NEGOTIATE))
|
||||
return -EAGAIN;
|
||||
/* else ok - we are setting up session */
|
||||
}
|
||||
*ppmidQ = AllocMidQEntry(in_buf, ses);
|
||||
*ppmidQ = AllocMidQEntry(in_buf, ses->server);
|
||||
if (*ppmidQ == NULL)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
@ -415,11 +415,8 @@ static int wait_for_response(struct cifsSesInfo *ses,
|
||||
|
||||
for (;;) {
|
||||
curr_timeout = timeout + jiffies;
|
||||
wait_event(ses->server->response_q,
|
||||
(!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
|
||||
time_after(jiffies, curr_timeout) ||
|
||||
((ses->server->tcpStatus != CifsGood) &&
|
||||
(ses->server->tcpStatus != CifsNew)));
|
||||
wait_event_timeout(ses->server->response_q,
|
||||
midQ->midState != MID_REQUEST_SUBMITTED, timeout);
|
||||
|
||||
if (time_after(jiffies, curr_timeout) &&
|
||||
(midQ->midState == MID_REQUEST_SUBMITTED) &&
|
||||
@ -521,11 +518,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
down(&ses->server->tcpSem);
|
||||
mutex_lock(&ses->server->srv_mutex);
|
||||
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
cifs_small_buf_release(in_buf);
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
@ -533,6 +530,11 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
return rc;
|
||||
}
|
||||
rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
cifs_small_buf_release(in_buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
@ -546,7 +548,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
cifs_small_buf_release(in_buf);
|
||||
|
||||
if (rc < 0)
|
||||
@ -581,10 +583,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
wait_for_response(ses, midQ, timeout, 10 * HZ);
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
} else {
|
||||
|
||||
if (midQ->resp_buf == NULL) {
|
||||
cERROR(1, ("No response to cmd %d mid %d",
|
||||
midQ->command, midQ->mid));
|
||||
if (midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
@ -612,53 +612,59 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
return rc;
|
||||
}
|
||||
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid));
|
||||
rc = -EIO;
|
||||
} else { /* rcvd frame is ok */
|
||||
if (midQ->resp_buf &&
|
||||
(midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
iov[0].iov_base = (char *)midQ->resp_buf;
|
||||
if (midQ->largeBuf)
|
||||
*pRespBufType = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
*pRespBufType = CIFS_SMALL_BUFFER;
|
||||
iov[0].iov_len = receive_len + 4;
|
||||
/* rcvd frame is ok */
|
||||
|
||||
dump_smb(midQ->resp_buf, 80);
|
||||
/* convert the length into a more usable form */
|
||||
if ((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(midQ->resp_buf,
|
||||
if (midQ->resp_buf &&
|
||||
(midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
|
||||
iov[0].iov_base = (char *)midQ->resp_buf;
|
||||
if (midQ->largeBuf)
|
||||
*pRespBufType = CIFS_LARGE_BUFFER;
|
||||
else
|
||||
*pRespBufType = CIFS_SMALL_BUFFER;
|
||||
iov[0].iov_len = receive_len + 4;
|
||||
|
||||
dump_smb(midQ->resp_buf, 80);
|
||||
/* convert the length into a more usable form */
|
||||
if ((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(midQ->resp_buf,
|
||||
&ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if (rc) {
|
||||
cERROR(1, ("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
if (rc) {
|
||||
cERROR(1, ("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(midQ->resp_buf,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(midQ->resp_buf) =
|
||||
le16_to_cpu(BCC_LE(midQ->resp_buf));
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL; /* mark it so buf will
|
||||
not be freed by
|
||||
DeleteMidQEntry */
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1, ("Bad MID state?"));
|
||||
}
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(midQ->resp_buf,
|
||||
flags & CIFS_LOG_ERROR);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(midQ->resp_buf) =
|
||||
le16_to_cpu(BCC_LE(midQ->resp_buf));
|
||||
if ((flags & CIFS_NO_RESP) == 0)
|
||||
midQ->resp_buf = NULL; /* mark it so buf will
|
||||
not be freed by
|
||||
DeleteMidQEntry */
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cFYI(1, ("Bad MID state?"));
|
||||
}
|
||||
|
||||
out:
|
||||
@ -695,6 +701,12 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = wait_for_free_request(ses, long_op);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -703,29 +715,22 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
down(&ses->server->tcpSem);
|
||||
mutex_lock(&ses->server->srv_mutex);
|
||||
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
DeleteMidQEntry(midQ);
|
||||
up(&ses->server->tcpSem);
|
||||
/* Update # of requests on wire to server */
|
||||
atomic_dec(&ses->server->inFlight);
|
||||
wake_up(&ses->server->request_q);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
goto out;
|
||||
}
|
||||
|
||||
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
@ -738,7 +743,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
@ -772,10 +777,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
wait_for_response(ses, midQ, timeout, 10 * HZ);
|
||||
|
||||
spin_lock(&GlobalMid_Lock);
|
||||
if (midQ->resp_buf) {
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
} else {
|
||||
if (midQ->resp_buf == NULL) {
|
||||
cERROR(1, ("No response for cmd %d mid %d",
|
||||
midQ->command, midQ->mid));
|
||||
if (midQ->midState == MID_REQUEST_SUBMITTED) {
|
||||
@ -803,47 +805,52 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
||||
return rc;
|
||||
}
|
||||
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
receive_len = midQ->resp_buf->smb_buf_length;
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid));
|
||||
rc = -EIO;
|
||||
} else { /* rcvd frame is ok */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (midQ->resp_buf && out_buf
|
||||
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
/* rcvd frame is ok */
|
||||
|
||||
dump_smb(out_buf, 92);
|
||||
/* convert the length into a more usable form */
|
||||
if ((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf,
|
||||
if (midQ->resp_buf && out_buf
|
||||
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
|
||||
dump_smb(out_buf, 92);
|
||||
/* convert the length into a more usable form */
|
||||
if ((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf,
|
||||
&ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if (rc) {
|
||||
cERROR(1, ("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
if (rc) {
|
||||
cERROR(1, ("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cERROR(1, ("Bad MID state?"));
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cERROR(1, ("Bad MID state?"));
|
||||
}
|
||||
|
||||
out:
|
||||
@ -866,16 +873,16 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
|
||||
|
||||
header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
|
||||
in_buf->Mid = mid;
|
||||
down(&ses->server->tcpSem);
|
||||
mutex_lock(&ses->server->srv_mutex);
|
||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
return rc;
|
||||
}
|
||||
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
|
||||
(struct sockaddr *) &(ses->server->addr.sockAddr),
|
||||
ses->server->noblocksnd);
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -933,6 +940,12 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
to the same server. We may make this configurable later or
|
||||
use ses->maxReq */
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = wait_for_free_request(ses, CIFS_BLOCKING_OP);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -941,23 +954,20 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
and avoid races inside tcp sendmsg code that could cause corruption
|
||||
of smb data */
|
||||
|
||||
down(&ses->server->tcpSem);
|
||||
mutex_lock(&ses->server->srv_mutex);
|
||||
|
||||
rc = allocate_mid(ses, in_buf, &midQ);
|
||||
if (rc) {
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
|
||||
up(&ses->server->tcpSem);
|
||||
cERROR(1, ("Illegal length, greater than maximum frame, %d",
|
||||
in_buf->smb_buf_length));
|
||||
DeleteMidQEntry(midQ);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
|
||||
if (rc) {
|
||||
DeleteMidQEntry(midQ);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
midQ->midState = MID_REQUEST_SUBMITTED;
|
||||
#ifdef CONFIG_CIFS_STATS2
|
||||
@ -970,7 +980,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
atomic_dec(&ses->server->inSend);
|
||||
midQ->when_sent = jiffies;
|
||||
#endif
|
||||
up(&ses->server->tcpSem);
|
||||
mutex_unlock(&ses->server->srv_mutex);
|
||||
|
||||
if (rc < 0) {
|
||||
DeleteMidQEntry(midQ);
|
||||
@ -1052,44 +1062,48 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
|
||||
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid));
|
||||
rc = -EIO;
|
||||
} else { /* rcvd frame is ok */
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (midQ->resp_buf && out_buf
|
||||
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
/* rcvd frame is ok */
|
||||
|
||||
dump_smb(out_buf, 92);
|
||||
/* convert the length into a more usable form */
|
||||
if ((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf,
|
||||
&ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if (rc) {
|
||||
cERROR(1, ("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
}
|
||||
if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
|
||||
rc = -EIO;
|
||||
cERROR(1, ("Bad MID state?"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
out_buf->smb_buf_length = receive_len;
|
||||
memcpy((char *)out_buf + 4,
|
||||
(char *)midQ->resp_buf + 4,
|
||||
receive_len);
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
|
||||
} else {
|
||||
rc = -EIO;
|
||||
cERROR(1, ("Bad MID state?"));
|
||||
dump_smb(out_buf, 92);
|
||||
/* convert the length into a more usable form */
|
||||
if ((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf,
|
||||
&ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if (rc) {
|
||||
cERROR(1, ("Unexpected SMB signature"));
|
||||
/* BB FIXME add code to kill session */
|
||||
}
|
||||
}
|
||||
|
||||
*pbytes_returned = out_buf->smb_buf_length;
|
||||
|
||||
/* BB special case reconnect tid and uid here? */
|
||||
rc = map_smb_to_linux_error(out_buf, 0 /* no log */ );
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
if (receive_len >= sizeof(struct smb_hdr) - 4
|
||||
/* do not count RFC1001 header */ +
|
||||
(2 * out_buf->WordCount) + 2 /* bcc */ )
|
||||
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
|
||||
|
||||
out:
|
||||
DeleteMidQEntry(midQ);
|
||||
if (rstart && rc == -EACCES)
|
||||
return -ERESTARTSYS;
|
||||
|
Loading…
Reference in New Issue
Block a user