[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: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
c67593a031
commit
ad009ac965
6 changed files with 50 additions and 32 deletions
|
@ -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)
|
||||
as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
|
||||
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
|
||||
------------
|
||||
|
|
|
@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char
|
|||
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)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -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 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;
|
||||
|
||||
if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
|
||||
return rc;
|
||||
|
||||
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;
|
||||
|
||||
*pexpected_response_sequence_number = ses->sequence_number++;
|
||||
ses->sequence_number++;
|
||||
*pexpected_response_sequence_number = server->sequence_number++;
|
||||
server->sequence_number++;
|
||||
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)
|
||||
memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
|
||||
else
|
||||
|
@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
|
|||
hmac_md5_update((const unsigned char *) unicode_buf,
|
||||
(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(unicode_buf);
|
||||
return 0;
|
||||
|
@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon
|
|||
struct HMACMD5Context context;
|
||||
memcpy(v2_session_response + 8, ses->server->cryptKey,8);
|
||||
/* 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(v2_session_response+16)client thing,8,&context); */ /* BB fix */
|
||||
|
|
|
@ -149,6 +149,8 @@ struct TCP_Server_Info {
|
|||
__u16 timeZone;
|
||||
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
|
||||
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 {
|
|||
struct TCP_Server_Info *server; /* pointer to server info */
|
||||
atomic_t inUse; /* # of mounts (tree connections) on this ses */
|
||||
enum statusEnum status;
|
||||
__u32 sequence_number; /* needed for CIFS PDU signature */
|
||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||
__u16 flags;
|
||||
char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
|
||||
char *serverOS; /* name of operating system underlying the server */
|
||||
char *serverNOS; /* name of network operating system that the server is running */
|
||||
char *serverOS; /* name of operating system underlying server */
|
||||
char *serverNOS; /* name of network operating system of server */
|
||||
char *serverDomain; /* security realm of server */
|
||||
int Suid; /* remote smb uid */
|
||||
uid_t linux_uid; /* local Linux uid */
|
||||
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 domainName[MAX_USERNAME_SIZE + 1];
|
||||
char * password;
|
||||
|
|
|
@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *);
|
|||
|
||||
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,
|
||||
__u32 expected_sequence_number);
|
||||
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)
|
|||
spin_lock(&GlobalMid_Lock);
|
||||
if(server->tcpStatus != CifsExiting)
|
||||
server->tcpStatus = CifsGood;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
server->sequence_number = 0;
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
/* atomic_set(&server->inFlight,0);*/
|
||||
wake_up(&server->response_q);
|
||||
}
|
||||
|
@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
|
|||
} else
|
||||
rc = 0;
|
||||
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,
|
|||
int rc = 0;
|
||||
char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
|
||||
int ntlmv2_flag = FALSE;
|
||||
int first_time = 0;
|
||||
|
||||
/* what if server changes its buffer size after dropping the session? */
|
||||
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,
|
|||
spin_unlock(&GlobalMid_Lock);
|
||||
|
||||
}
|
||||
first_time = 1;
|
||||
}
|
||||
if (!rc) {
|
||||
pSesInfo->capabilities = pSesInfo->server->capabilities;
|
||||
if(linuxExtEnabled == 0)
|
||||
pSesInfo->capabilities &= (~CAP_UNIX);
|
||||
pSesInfo->sequence_number = 0;
|
||||
/* pSesInfo->sequence_number = 0;*/
|
||||
cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
|
||||
pSesInfo->server->secMode,
|
||||
pSesInfo->server->capabilities,
|
||||
|
@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
|||
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
|
||||
if(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);
|
||||
/* BB Put dummy sig in SessSetup PDU? */
|
||||
} else {
|
||||
|
@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
|||
pSesInfo->server->cryptKey,
|
||||
ntlm_session_key);
|
||||
|
||||
cifs_calculate_mac_key(pSesInfo->mac_signing_key,
|
||||
ntlm_session_key,
|
||||
pSesInfo->password);
|
||||
if(first_time)
|
||||
cifs_calculate_mac_key(
|
||||
pSesInfo->server->mac_signing_key,
|
||||
ntlm_session_key,
|
||||
pSesInfo->password);
|
||||
}
|
||||
/* for better security the weaker lanman hash not sent
|
||||
in AuthSessSetup so we no longer calculate it */
|
||||
|
@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
|
|||
pSesInfo->server->cryptKey,
|
||||
ntlm_session_key);
|
||||
|
||||
cifs_calculate_mac_key(pSesInfo->mac_signing_key,
|
||||
ntlm_session_key, pSesInfo->password);
|
||||
if(first_time)
|
||||
cifs_calculate_mac_key(
|
||||
pSesInfo->server->mac_signing_key,
|
||||
ntlm_session_key, pSesInfo->password);
|
||||
|
||||
rc = CIFSSessSetup(xid, pSesInfo,
|
||||
ntlm_session_key, nls_info);
|
||||
}
|
||||
|
|
|
@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
}
|
||||
|
||||
/* 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;
|
||||
/* 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,
|
|||
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;
|
||||
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,
|
|||
}
|
||||
|
||||
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
|
||||
cERROR(1,
|
||||
("Frame too large received. Length: %d Xid: %d",
|
||||
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
|
||||
receive_len, xid));
|
||||
rc = -EIO;
|
||||
} else { /* rcvd frame is ok */
|
||||
|
@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
|
|||
dump_smb(out_buf, 92);
|
||||
/* convert the length into a more usable form */
|
||||
if((receive_len > 24) &&
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
|
||||
if(rc)
|
||||
cFYI(1,("Unexpected signature received from server"));
|
||||
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
|
||||
SECMODE_SIGN_ENABLED))) {
|
||||
rc = cifs_verify_signature(out_buf,
|
||||
ses->server->mac_signing_key,
|
||||
midQ->sequence_number+1);
|
||||
if(rc) {
|
||||
cERROR(1,("Unexpected packet signature received from server"));
|
||||
/* BB FIXME - add code to kill session here */
|
||||
}
|
||||
}
|
||||
|
||||
*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);
|
||||
|
||||
/* convert ByteCount if necessary */
|
||||
|
|
Loading…
Reference in a new issue