Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 131643
b: refs/heads/master
c: eca6acf
h: refs/heads/master
i:
  131641: dd58702
  131639: 3213354
v: v3
  • Loading branch information
Steve French committed Feb 21, 2009
1 parent 02b7943 commit 5a42cf8
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c3b2a0c640bff7df85d79fb4f89674949a267ec2
refs/heads/master: eca6acf91552a9b2e997cc76339115c95eac0217
10 changes: 10 additions & 0 deletions trunk/fs/cifs/CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
Version 1.57
------------
Improve support for multiple security contexts to the same server. We
used to use the same "vcnumber" for all connections which could cause
the server to treat subsequent connections, especially those that
are authenticated as guest, as reconnections, invalidating the earlier
user's smb session. This fix allows cifs to mount multiple times to the
same server with different userids without risking invalidating earlier
established security contexts.

Version 1.56
------------
Add "forcemandatorylock" mount option to allow user to use mandatory
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,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.56"
#define CIFS_VERSION "1.57"
#endif /* _CIFSFS_H */
6 changes: 5 additions & 1 deletion trunk/fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,12 @@ struct TCP_Server_Info {
/* multiplexed reads or writes */
unsigned int maxBuf; /* maxBuf specifies the maximum */
/* message size the server can send or receive for non-raw SMBs */
unsigned int maxRw; /* maxRw specifies the maximum */
unsigned int max_rw; /* maxRw specifies the maximum */
/* message size the server can send or receive for */
/* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
unsigned int max_vcs; /* maximum number of smb sessions, at least
those that can be specified uniquely with
vcnumbers */
char sessid[4]; /* unique token id for this session */
/* (returned on Negotiate */
int capabilities; /* allow selective disabling of caps by smb sess */
Expand Down Expand Up @@ -210,6 +213,7 @@ struct cifsSesInfo {
unsigned overrideSecFlg; /* if non-zero override global sec flags */
__u16 ipc_tid; /* special tid for connection to IPC share */
__u16 flags;
__u16 vcnum;
char *serverOS; /* name of operating system underlying server */
char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */
Expand Down
7 changes: 4 additions & 3 deletions trunk/fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -528,14 +528,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
/* even though we do not use raw we might as well set this
accurately, in case we ever find a need for it */
if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
server->maxRw = 0xFF00;
server->max_rw = 0xFF00;
server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
} else {
server->maxRw = 0;/* we do not need to use raw anyway */
server->max_rw = 0;/* do not need to use raw anyway */
server->capabilities = CAP_MPX_MODE;
}
tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Expand Down Expand Up @@ -638,7 +639,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
/* probably no need to store and check maxvcs */
server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
(__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Expand Down
87 changes: 85 additions & 2 deletions trunk/fs/cifs/sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,99 @@
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);

/* Checks if this is the first smb session to be reconnected after
the socket has been reestablished (so we know whether to use vc 0).
Called while holding the cifs_tcp_ses_lock, so do not block */
static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
{
struct list_head *tmp;
struct cifsSesInfo *tmp_ses;

list_for_each(tmp, &ses->server->smb_ses_list) {
tmp_ses = list_entry(tmp, struct cifsSesInfo,
smb_ses_list);
if (tmp_ses->need_reconnect == false)
return false;
}
/* could not find a session that was already connected,
this must be the first one we are reconnecting */
return true;
}

/*
* vc number 0 is treated specially by some servers, and should be the
* first one we request. After that we can use vcnumbers up to maxvcs,
* one for each smb session (some Windows versions set maxvcs incorrectly
* so maxvc=1 can be ignored). If we have too many vcs, we can reuse
* any vc but zero (some servers reset the connection on vcnum zero)
*
*/
static __le16 get_next_vcnum(struct cifsSesInfo *ses)
{
__u16 vcnum = 0;
struct list_head *tmp;
struct cifsSesInfo *tmp_ses;
__u16 max_vcs = ses->server->max_vcs;
__u16 i;
int free_vc_found = 0;

/* Quoting the MS-SMB specification: "Windows-based SMB servers set this
field to one but do not enforce this limit, which allows an SMB client
to establish more virtual circuits than allowed by this value ... but
other server implementations can enforce this limit." */
if (max_vcs < 2)
max_vcs = 0xFFFF;

write_lock(&cifs_tcp_ses_lock);
if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
goto get_vc_num_exit; /* vcnum will be zero */
for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
if (i == 0) /* this is the only connection, use vc 0 */
break;

free_vc_found = 1;

list_for_each(tmp, &ses->server->smb_ses_list) {
tmp_ses = list_entry(tmp, struct cifsSesInfo,
smb_ses_list);
if (tmp_ses->vcnum == i) {
free_vc_found = 0;
break; /* found duplicate, try next vcnum */
}
}
if (free_vc_found)
break; /* we found a vcnumber that will work - use it */
}

if (i == 0)
vcnum = 0; /* for most common case, ie if one smb session, use
vc zero. Also for case when no free vcnum, zero
is safest to send (some clients only send zero) */
else if (free_vc_found == 0)
vcnum = 1; /* we can not reuse vc=0 safely, since some servers
reset all uids on that, but 1 is ok. */
else
vcnum = i;
ses->vcnum = vcnum;
get_vc_num_exit:
write_unlock(&cifs_tcp_ses_lock);

return le16_to_cpu(vcnum);
}

static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
{
__u32 capabilities = 0;

/* init fields common to all four types of SessSetup */
/* note that header is initialized to zero in header_assemble */
/* Note that offsets for first seven fields in req struct are same */
/* in CIFS Specs so does not matter which of 3 forms of struct */
/* that we use in next few lines */
/* Note that header is initialized to zero in header_assemble */
pSMB->req.AndXCommand = 0xFF;
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
pSMB->req.VcNumber = get_next_vcnum(ses);

/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */

Expand Down Expand Up @@ -71,7 +155,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
if (ses->capabilities & CAP_UNIX)
capabilities |= CAP_UNIX;

/* BB check whether to init vcnum BB */
return capabilities;
}

Expand Down

0 comments on commit 5a42cf8

Please sign in to comment.