Commit 54a696bd authored by Linus Torvalds's avatar Linus Torvalds

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.
parents 1d248b25 359d67d6
......@@ -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
-------------------------------------
......
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);
......
......@@ -31,6 +31,7 @@
#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_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,20 +280,17 @@ 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) {
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);
......@@ -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 */
......
......@@ -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,
......
......@@ -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;
......@@ -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,17 +102,10 @@ 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);
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
......@@ -119,7 +113,6 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
* 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 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
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);
}
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,
/* 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,
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);
}
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);
/* get a reference to a tcp session */
srvTcp = cifs_get_tcp_session(volume_info);
if (IS_ERR(srvTcp)) {
rc = PTR_ERR(srvTcp);
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);
}
}
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 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
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 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
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"));
......@@ -3488,11 +3545,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
#ifdef CONFIG_CIFS_WEAK_PW_HASH
if ((extended_security & CIFSSEC_MAY_LANMAN) &&
(ses->server->secType == LANMAN))
calc_lanman_hash(ses, bcc_ptr);
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);
......
/*
* 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);
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,7 +344,9 @@ 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 {
return 0;
}
spin_lock(&GlobalMid_Lock);
while (1) {
if (atomic_read(&ses->server->inFlight) >=
......@@ -381,7 +378,6 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
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,11 +612,18 @@ 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 */
goto out;
}
/* rcvd frame is ok */
if (midQ->resp_buf &&
(midQ->midState == MID_RESPONSE_RECEIVED)) {
......@@ -659,7 +666,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
rc = -EIO;
cFYI(1, ("Bad MID state?"));
}
}
out:
DeleteMidQEntry(midQ);
......@@ -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,11 +805,17 @@ 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;
}
/* rcvd frame is ok */
if (midQ->resp_buf && out_buf
&& (midQ->midState == MID_RESPONSE_RECEIVED)) {
......@@ -844,7 +852,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
rc = -EIO;
cERROR(1, ("Bad MID state?"));
}
}
out:
DeleteMidQEntry(midQ);
......@@ -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,24 +954,21 @@ 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));
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
if (rc) {
DeleteMidQEntry(midQ);
return -EIO;
mutex_unlock(&ses->server->srv_mutex);
return rc;
}
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
atomic_inc(&ses->server->inSend);
......@@ -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,10 +1062,17 @@ 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;
}
/* rcvd frame is ok */
if ((out_buf == NULL) || (midQ->midState != MID_RESPONSE_RECEIVED)) {
rc = -EIO;
cERROR(1, ("Bad MID state?"));
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,
......@@ -1085,11 +1102,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
/* 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:
DeleteMidQEntry(midQ);
if (rstart && rc == -EACCES)
return -ERESTARTSYS;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment