Commit ad009ac9 authored by Steve French's avatar Steve French Committed by Linus Torvalds

[PATCH] cifs: Fix multiuser packet signing to use the right sequence number and mac session key

Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c67593a0
...@@ -5,7 +5,8 @@ transact response for an SMB request and search entry split across two frames. ...@@ -5,7 +5,8 @@ transact response for an SMB request and search entry split across two frames.
Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
as new protocol extensions. Do not send Get/Set calls for POSIX ACLs as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
unless server explicitly claims to support them in CIFS Unix extensions unless server explicitly claims to support them in CIFS Unix extensions
POSIX ACL capability bit. POSIX ACL capability bit. Fix packet signing when multiuser mounting with
different users from the same client to the same server.
Version 1.31 Version 1.31
------------ ------------
......
...@@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char ...@@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char
return 0; return 0;
} }
int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
__u32 * pexpected_response_sequence_number) __u32 * pexpected_response_sequence_number)
{ {
int rc = 0; int rc = 0;
...@@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, ...@@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
/* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
/* BB remember to add code to save expected sequence number in midQ entry BB */ /* BB remember to add code to save expected sequence number in midQ entry BB */
if((cifs_pdu == NULL) || (ses == NULL)) if((cifs_pdu == NULL) || (server == NULL))
return -EINVAL; return -EINVAL;
if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc; return rc;
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0; cifs_pdu->Signature.Sequence.Reserved = 0;
*pexpected_response_sequence_number = ses->sequence_number++; *pexpected_response_sequence_number = server->sequence_number++;
ses->sequence_number++; server->sequence_number++;
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
if(rc) if(rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8); memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else else
...@@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ ...@@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
hmac_md5_update((const unsigned char *) unicode_buf, hmac_md5_update((const unsigned char *) unicode_buf,
(user_name_len+dom_name_len)*2,&ctx); (user_name_len+dom_name_len)*2,&ctx);
hmac_md5_final(ses->mac_signing_key,&ctx); hmac_md5_final(ses->server->mac_signing_key,&ctx);
kfree(ucase_buf); kfree(ucase_buf);
kfree(unicode_buf); kfree(unicode_buf);
return 0; return 0;
...@@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon ...@@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon
struct HMACMD5Context context; struct HMACMD5Context context;
memcpy(v2_session_response + 8, ses->server->cryptKey,8); memcpy(v2_session_response + 8, ses->server->cryptKey,8);
/* gen_blob(v2_session_response + 16); */ /* gen_blob(v2_session_response + 16); */
hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
hmac_md5_update(ses->server->cryptKey,8,&context); hmac_md5_update(ses->server->cryptKey,8,&context);
/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
......
...@@ -149,6 +149,8 @@ struct TCP_Server_Info { ...@@ -149,6 +149,8 @@ struct TCP_Server_Info {
__u16 timeZone; __u16 timeZone;
char cryptKey[CIFS_CRYPTO_KEY_SIZE]; char cryptKey[CIFS_CRYPTO_KEY_SIZE];
char workstation_RFC1001_name[16]; /* 16th byte is always zero */ char workstation_RFC1001_name[16]; /* 16th byte is always zero */
__u32 sequence_number; /* needed for CIFS PDU signature */
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
}; };
/* /*
...@@ -174,17 +176,16 @@ struct cifsSesInfo { ...@@ -174,17 +176,16 @@ struct cifsSesInfo {
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
atomic_t inUse; /* # of mounts (tree connections) on this ses */ atomic_t inUse; /* # of mounts (tree connections) on this ses */
enum statusEnum status; enum statusEnum status;
__u32 sequence_number; /* needed for CIFS PDU signature */
__u16 ipc_tid; /* special tid for connection to IPC share */ __u16 ipc_tid; /* special tid for connection to IPC share */
__u16 flags; __u16 flags;
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; char *serverOS; /* name of operating system underlying server */
char *serverOS; /* name of operating system underlying the server */ char *serverNOS; /* name of network operating system of server */
char *serverNOS; /* name of network operating system that the server is running */
char *serverDomain; /* security realm of server */ char *serverDomain; /* security realm of server */
int Suid; /* remote smb uid */ int Suid; /* remote smb uid */
uid_t linux_uid; /* local Linux uid */ uid_t linux_uid; /* local Linux uid */
int capabilities; int capabilities;
char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */
char userName[MAX_USERNAME_SIZE + 1]; char userName[MAX_USERNAME_SIZE + 1];
char domainName[MAX_USERNAME_SIZE + 1]; char domainName[MAX_USERNAME_SIZE + 1];
char * password; char * password;
......
...@@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *); ...@@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *);
extern int cifs_reconnect(struct TCP_Server_Info *server); extern int cifs_reconnect(struct TCP_Server_Info *server);
extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
__u32 expected_sequence_number); __u32 expected_sequence_number);
extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
......
...@@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server) ...@@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_lock(&GlobalMid_Lock); spin_lock(&GlobalMid_Lock);
if(server->tcpStatus != CifsExiting) if(server->tcpStatus != CifsExiting)
server->tcpStatus = CifsGood; server->tcpStatus = CifsGood;
spin_unlock(&GlobalMid_Lock); server->sequence_number = 0;
spin_unlock(&GlobalMid_Lock);
/* atomic_set(&server->inFlight,0);*/ /* atomic_set(&server->inFlight,0);*/
wake_up(&server->response_q); wake_up(&server->response_q);
} }
...@@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ...@@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
} else } else
rc = 0; rc = 0;
memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
srvTcp->sequence_number = 0;
} }
} }
...@@ -2959,6 +2961,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -2959,6 +2961,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
int rc = 0; int rc = 0;
char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
int ntlmv2_flag = FALSE; int ntlmv2_flag = FALSE;
int first_time = 0;
/* what if server changes its buffer size after dropping the session? */ /* what if server changes its buffer size after dropping the session? */
if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
...@@ -2977,12 +2980,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -2977,12 +2980,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
spin_unlock(&GlobalMid_Lock); spin_unlock(&GlobalMid_Lock);
} }
first_time = 1;
} }
if (!rc) { if (!rc) {
pSesInfo->capabilities = pSesInfo->server->capabilities; pSesInfo->capabilities = pSesInfo->server->capabilities;
if(linuxExtEnabled == 0) if(linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX); pSesInfo->capabilities &= (~CAP_UNIX);
pSesInfo->sequence_number = 0; /* pSesInfo->sequence_number = 0;*/
cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
pSesInfo->server->secMode, pSesInfo->server->secMode,
pSesInfo->server->capabilities, pSesInfo->server->capabilities,
...@@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
if(v2_response) { if(v2_response) {
CalcNTLMv2_response(pSesInfo,v2_response); CalcNTLMv2_response(pSesInfo,v2_response);
/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ /* if(first_time)
cifs_calculate_ntlmv2_mac_key(
pSesInfo->server->mac_signing_key,
response, ntlm_session_key, */
kfree(v2_response); kfree(v2_response);
/* BB Put dummy sig in SessSetup PDU? */ /* BB Put dummy sig in SessSetup PDU? */
} else { } else {
...@@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey, pSesInfo->server->cryptKey,
ntlm_session_key); ntlm_session_key);
cifs_calculate_mac_key(pSesInfo->mac_signing_key, if(first_time)
ntlm_session_key, cifs_calculate_mac_key(
pSesInfo->password); pSesInfo->server->mac_signing_key,
ntlm_session_key,
pSesInfo->password);
} }
/* for better security the weaker lanman hash not sent /* for better security the weaker lanman hash not sent
in AuthSessSetup so we no longer calculate it */ in AuthSessSetup so we no longer calculate it */
...@@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ...@@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey, pSesInfo->server->cryptKey,
ntlm_session_key); ntlm_session_key);
cifs_calculate_mac_key(pSesInfo->mac_signing_key, if(first_time)
ntlm_session_key, pSesInfo->password); cifs_calculate_mac_key(
pSesInfo->server->mac_signing_key,
ntlm_session_key, pSesInfo->password);
rc = CIFSSessSetup(xid, pSesInfo, rc = CIFSSessSetup(xid, pSesInfo,
ntlm_session_key, nls_info); ntlm_session_key, nls_info);
} }
......
...@@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
} }
/* BB can we sign efficiently in this path? */ /* BB can we sign efficiently in this path? */
rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED; midQ->midState = MID_REQUEST_SUBMITTED;
/* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec, /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
...@@ -475,7 +475,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -475,7 +475,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return -EIO; return -EIO;
} }
rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED; midQ->midState = MID_REQUEST_SUBMITTED;
rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
...@@ -559,8 +559,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -559,8 +559,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
} }
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, cERROR(1, ("Frame too large received. Length: %d Xid: %d",
("Frame too large received. Length: %d Xid: %d",
receive_len, xid)); receive_len, xid));
rc = -EIO; rc = -EIO;
} else { /* rcvd frame is ok */ } else { /* rcvd frame is ok */
...@@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ...@@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
dump_smb(out_buf, 92); dump_smb(out_buf, 92);
/* convert the length into a more usable form */ /* convert the length into a more usable form */
if((receive_len > 24) && if((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ SECMODE_SIGN_ENABLED))) {
if(rc) rc = cifs_verify_signature(out_buf,
cFYI(1,("Unexpected signature received from server")); ses->server->mac_signing_key,
midQ->sequence_number+1);
if(rc) {
cERROR(1,("Unexpected packet signature received from server"));
/* BB FIXME - add code to kill session here */
}
} }
*pbytes_returned = out_buf->smb_buf_length; *pbytes_returned = out_buf->smb_buf_length;
/* BB special case reconnect tid and reconnect uid here? */ /* BB special case reconnect tid and uid here? */
rc = map_smb_to_linux_error(out_buf); rc = map_smb_to_linux_error(out_buf);
/* convert ByteCount if necessary */ /* convert ByteCount if necessary */
......
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