diff options
author | Steve French <smfrench@austin.rr.com> | 2005-04-29 01:41:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-29 01:41:05 -0400 |
commit | ad009ac96509e005d9978d0ae9e9ec4d63ad2990 (patch) | |
tree | eb15ee8333fd7b5816f8fe3d02250ff99601eba0 | |
parent | c67593a03129967eae8939c4899767182eb6d6cd (diff) |
[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>
-rw-r--r-- | fs/cifs/CHANGES | 3 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 16 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 11 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/connect.c | 28 | ||||
-rw-r--r-- | fs/cifs/transport.c | 22 |
6 files changed, 50 insertions, 32 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7fd02697b12e..43b3119a16ed 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -5,7 +5,8 @@ transact response for an SMB request and search entry split across two frames. | |||
5 | Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) | 5 | Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server) |
6 | as new protocol extensions. Do not send Get/Set calls for POSIX ACLs | 6 | as new protocol extensions. Do not send Get/Set calls for POSIX ACLs |
7 | unless server explicitly claims to support them in CIFS Unix extensions | 7 | unless server explicitly claims to support them in CIFS Unix extensions |
8 | POSIX ACL capability bit. | 8 | POSIX ACL capability bit. Fix packet signing when multiuser mounting with |
9 | different users from the same client to the same server. | ||
9 | 10 | ||
10 | Version 1.31 | 11 | Version 1.31 |
11 | ------------ | 12 | ------------ |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 78829e7d8cd0..1959c7c4b185 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char | |||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
53 | int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, | 53 | int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, |
54 | __u32 * pexpected_response_sequence_number) | 54 | __u32 * pexpected_response_sequence_number) |
55 | { | 55 | { |
56 | int rc = 0; | 56 | int rc = 0; |
@@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, | |||
59 | /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ | 59 | /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ |
60 | /* BB remember to add code to save expected sequence number in midQ entry BB */ | 60 | /* BB remember to add code to save expected sequence number in midQ entry BB */ |
61 | 61 | ||
62 | if((cifs_pdu == NULL) || (ses == NULL)) | 62 | if((cifs_pdu == NULL) || (server == NULL)) |
63 | return -EINVAL; | 63 | return -EINVAL; |
64 | 64 | ||
65 | if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 65 | if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
66 | return rc; | 66 | return rc; |
67 | 67 | ||
68 | spin_lock(&GlobalMid_Lock); | 68 | spin_lock(&GlobalMid_Lock); |
69 | cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); | 69 | cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number); |
70 | cifs_pdu->Signature.Sequence.Reserved = 0; | 70 | cifs_pdu->Signature.Sequence.Reserved = 0; |
71 | 71 | ||
72 | *pexpected_response_sequence_number = ses->sequence_number++; | 72 | *pexpected_response_sequence_number = server->sequence_number++; |
73 | ses->sequence_number++; | 73 | server->sequence_number++; |
74 | spin_unlock(&GlobalMid_Lock); | 74 | spin_unlock(&GlobalMid_Lock); |
75 | 75 | ||
76 | rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); | 76 | rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature); |
77 | if(rc) | 77 | if(rc) |
78 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 78 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
79 | else | 79 | else |
@@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ | |||
190 | hmac_md5_update((const unsigned char *) unicode_buf, | 190 | hmac_md5_update((const unsigned char *) unicode_buf, |
191 | (user_name_len+dom_name_len)*2,&ctx); | 191 | (user_name_len+dom_name_len)*2,&ctx); |
192 | 192 | ||
193 | hmac_md5_final(ses->mac_signing_key,&ctx); | 193 | hmac_md5_final(ses->server->mac_signing_key,&ctx); |
194 | kfree(ucase_buf); | 194 | kfree(ucase_buf); |
195 | kfree(unicode_buf); | 195 | kfree(unicode_buf); |
196 | return 0; | 196 | return 0; |
@@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon | |||
200 | struct HMACMD5Context context; | 200 | struct HMACMD5Context context; |
201 | memcpy(v2_session_response + 8, ses->server->cryptKey,8); | 201 | memcpy(v2_session_response + 8, ses->server->cryptKey,8); |
202 | /* gen_blob(v2_session_response + 16); */ | 202 | /* gen_blob(v2_session_response + 16); */ |
203 | hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); | 203 | hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); |
204 | 204 | ||
205 | hmac_md5_update(ses->server->cryptKey,8,&context); | 205 | hmac_md5_update(ses->server->cryptKey,8,&context); |
206 | /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ | 206 | /* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 69aff1a7da9b..1b3082d79379 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -149,6 +149,8 @@ struct TCP_Server_Info { | |||
149 | __u16 timeZone; | 149 | __u16 timeZone; |
150 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | 150 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; |
151 | char workstation_RFC1001_name[16]; /* 16th byte is always zero */ | 151 | char workstation_RFC1001_name[16]; /* 16th byte is always zero */ |
152 | __u32 sequence_number; /* needed for CIFS PDU signature */ | ||
153 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | ||
152 | }; | 154 | }; |
153 | 155 | ||
154 | /* | 156 | /* |
@@ -174,17 +176,16 @@ struct cifsSesInfo { | |||
174 | struct TCP_Server_Info *server; /* pointer to server info */ | 176 | struct TCP_Server_Info *server; /* pointer to server info */ |
175 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ | 177 | atomic_t inUse; /* # of mounts (tree connections) on this ses */ |
176 | enum statusEnum status; | 178 | enum statusEnum status; |
177 | __u32 sequence_number; /* needed for CIFS PDU signature */ | ||
178 | __u16 ipc_tid; /* special tid for connection to IPC share */ | 179 | __u16 ipc_tid; /* special tid for connection to IPC share */ |
179 | __u16 flags; | 180 | __u16 flags; |
180 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | 181 | char *serverOS; /* name of operating system underlying server */ |
181 | char *serverOS; /* name of operating system underlying the server */ | 182 | char *serverNOS; /* name of network operating system of server */ |
182 | char *serverNOS; /* name of network operating system that the server is running */ | ||
183 | char *serverDomain; /* security realm of server */ | 183 | char *serverDomain; /* security realm of server */ |
184 | int Suid; /* remote smb uid */ | 184 | int Suid; /* remote smb uid */ |
185 | uid_t linux_uid; /* local Linux uid */ | 185 | uid_t linux_uid; /* local Linux uid */ |
186 | int capabilities; | 186 | int capabilities; |
187 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ | 187 | char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for |
188 | TCP names - will ipv6 and sctp addresses fit? */ | ||
188 | char userName[MAX_USERNAME_SIZE + 1]; | 189 | char userName[MAX_USERNAME_SIZE + 1]; |
189 | char domainName[MAX_USERNAME_SIZE + 1]; | 190 | char domainName[MAX_USERNAME_SIZE + 1]; |
190 | char * password; | 191 | char * password; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1b0070dfc51c..dd95c2bcbc25 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *); | |||
230 | 230 | ||
231 | extern int cifs_reconnect(struct TCP_Server_Info *server); | 231 | extern int cifs_reconnect(struct TCP_Server_Info *server); |
232 | 232 | ||
233 | extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); | 233 | extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); |
234 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, | 234 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, |
235 | __u32 expected_sequence_number); | 235 | __u32 expected_sequence_number); |
236 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); | 236 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 40470b9d5477..814e709ca0ca 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
182 | spin_lock(&GlobalMid_Lock); | 182 | spin_lock(&GlobalMid_Lock); |
183 | if(server->tcpStatus != CifsExiting) | 183 | if(server->tcpStatus != CifsExiting) |
184 | server->tcpStatus = CifsGood; | 184 | server->tcpStatus = CifsGood; |
185 | spin_unlock(&GlobalMid_Lock); | 185 | server->sequence_number = 0; |
186 | spin_unlock(&GlobalMid_Lock); | ||
186 | /* atomic_set(&server->inFlight,0);*/ | 187 | /* atomic_set(&server->inFlight,0);*/ |
187 | wake_up(&server->response_q); | 188 | wake_up(&server->response_q); |
188 | } | 189 | } |
@@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1352 | } else | 1353 | } else |
1353 | rc = 0; | 1354 | rc = 0; |
1354 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); | 1355 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); |
1356 | srvTcp->sequence_number = 0; | ||
1355 | } | 1357 | } |
1356 | } | 1358 | } |
1357 | 1359 | ||
@@ -2959,6 +2961,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
2959 | int rc = 0; | 2961 | int rc = 0; |
2960 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; | 2962 | char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; |
2961 | int ntlmv2_flag = FALSE; | 2963 | int ntlmv2_flag = FALSE; |
2964 | int first_time = 0; | ||
2962 | 2965 | ||
2963 | /* what if server changes its buffer size after dropping the session? */ | 2966 | /* what if server changes its buffer size after dropping the session? */ |
2964 | if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { | 2967 | 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 | spin_unlock(&GlobalMid_Lock); | 2980 | spin_unlock(&GlobalMid_Lock); |
2978 | 2981 | ||
2979 | } | 2982 | } |
2983 | first_time = 1; | ||
2980 | } | 2984 | } |
2981 | if (!rc) { | 2985 | if (!rc) { |
2982 | pSesInfo->capabilities = pSesInfo->server->capabilities; | 2986 | pSesInfo->capabilities = pSesInfo->server->capabilities; |
2983 | if(linuxExtEnabled == 0) | 2987 | if(linuxExtEnabled == 0) |
2984 | pSesInfo->capabilities &= (~CAP_UNIX); | 2988 | pSesInfo->capabilities &= (~CAP_UNIX); |
2985 | pSesInfo->sequence_number = 0; | 2989 | /* pSesInfo->sequence_number = 0;*/ |
2986 | cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", | 2990 | cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", |
2987 | pSesInfo->server->secMode, | 2991 | pSesInfo->server->secMode, |
2988 | pSesInfo->server->capabilities, | 2992 | pSesInfo->server->capabilities, |
@@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3015 | v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); | 3019 | v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); |
3016 | if(v2_response) { | 3020 | if(v2_response) { |
3017 | CalcNTLMv2_response(pSesInfo,v2_response); | 3021 | CalcNTLMv2_response(pSesInfo,v2_response); |
3018 | /* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ | 3022 | /* if(first_time) |
3023 | cifs_calculate_ntlmv2_mac_key( | ||
3024 | pSesInfo->server->mac_signing_key, | ||
3025 | response, ntlm_session_key, */ | ||
3019 | kfree(v2_response); | 3026 | kfree(v2_response); |
3020 | /* BB Put dummy sig in SessSetup PDU? */ | 3027 | /* BB Put dummy sig in SessSetup PDU? */ |
3021 | } else { | 3028 | } else { |
@@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3028 | pSesInfo->server->cryptKey, | 3035 | pSesInfo->server->cryptKey, |
3029 | ntlm_session_key); | 3036 | ntlm_session_key); |
3030 | 3037 | ||
3031 | cifs_calculate_mac_key(pSesInfo->mac_signing_key, | 3038 | if(first_time) |
3032 | ntlm_session_key, | 3039 | cifs_calculate_mac_key( |
3033 | pSesInfo->password); | 3040 | pSesInfo->server->mac_signing_key, |
3041 | ntlm_session_key, | ||
3042 | pSesInfo->password); | ||
3034 | } | 3043 | } |
3035 | /* for better security the weaker lanman hash not sent | 3044 | /* for better security the weaker lanman hash not sent |
3036 | in AuthSessSetup so we no longer calculate it */ | 3045 | in AuthSessSetup so we no longer calculate it */ |
@@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3046 | pSesInfo->server->cryptKey, | 3055 | pSesInfo->server->cryptKey, |
3047 | ntlm_session_key); | 3056 | ntlm_session_key); |
3048 | 3057 | ||
3049 | cifs_calculate_mac_key(pSesInfo->mac_signing_key, | 3058 | if(first_time) |
3050 | ntlm_session_key, pSesInfo->password); | 3059 | cifs_calculate_mac_key( |
3060 | pSesInfo->server->mac_signing_key, | ||
3061 | ntlm_session_key, pSesInfo->password); | ||
3062 | |||
3051 | rc = CIFSSessSetup(xid, pSesInfo, | 3063 | rc = CIFSSessSetup(xid, pSesInfo, |
3052 | ntlm_session_key, nls_info); | 3064 | ntlm_session_key, nls_info); |
3053 | } | 3065 | } |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index af13e526b150..a9e4f989b7f7 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
346 | } | 346 | } |
347 | 347 | ||
348 | /* BB can we sign efficiently in this path? */ | 348 | /* BB can we sign efficiently in this path? */ |
349 | rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); | 349 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
350 | 350 | ||
351 | midQ->midState = MID_REQUEST_SUBMITTED; | 351 | midQ->midState = MID_REQUEST_SUBMITTED; |
352 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec, | 352 | /* 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 | return -EIO; | 475 | return -EIO; |
476 | } | 476 | } |
477 | 477 | ||
478 | rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); | 478 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
479 | 479 | ||
480 | midQ->midState = MID_REQUEST_SUBMITTED; | 480 | midQ->midState = MID_REQUEST_SUBMITTED; |
481 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 481 | 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 | } | 559 | } |
560 | 560 | ||
561 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { | 561 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
562 | cERROR(1, | 562 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
563 | ("Frame too large received. Length: %d Xid: %d", | ||
564 | receive_len, xid)); | 563 | receive_len, xid)); |
565 | rc = -EIO; | 564 | rc = -EIO; |
566 | } else { /* rcvd frame is ok */ | 565 | } else { /* rcvd frame is ok */ |
@@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
575 | dump_smb(out_buf, 92); | 574 | dump_smb(out_buf, 92); |
576 | /* convert the length into a more usable form */ | 575 | /* convert the length into a more usable form */ |
577 | if((receive_len > 24) && | 576 | if((receive_len > 24) && |
578 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { | 577 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
579 | rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ | 578 | SECMODE_SIGN_ENABLED))) { |
580 | if(rc) | 579 | rc = cifs_verify_signature(out_buf, |
581 | cFYI(1,("Unexpected signature received from server")); | 580 | ses->server->mac_signing_key, |
581 | midQ->sequence_number+1); | ||
582 | if(rc) { | ||
583 | cERROR(1,("Unexpected packet signature received from server")); | ||
584 | /* BB FIXME - add code to kill session here */ | ||
585 | } | ||
582 | } | 586 | } |
583 | 587 | ||
584 | *pbytes_returned = out_buf->smb_buf_length; | 588 | *pbytes_returned = out_buf->smb_buf_length; |
585 | 589 | ||
586 | /* BB special case reconnect tid and reconnect uid here? */ | 590 | /* BB special case reconnect tid and uid here? */ |
587 | rc = map_smb_to_linux_error(out_buf); | 591 | rc = map_smb_to_linux_error(out_buf); |
588 | 592 | ||
589 | /* convert ByteCount if necessary */ | 593 | /* convert ByteCount if necessary */ |