diff options
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
| -rw-r--r-- | fs/cifs/cifsencrypt.c | 104 |
1 files changed, 53 insertions, 51 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index fdeda519eace..8422df81b994 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
| 23 | #include "cifspdu.h" | 23 | #include "cifspdu.h" |
| 24 | #include "cifsglob.h" | 24 | #include "cifsglob.h" |
| 25 | #include "cifs_debug.h" | 25 | #include "cifs_debug.h" |
| 26 | #include "md5.h" | 26 | #include "md5.h" |
| 27 | #include "cifs_unicode.h" | 27 | #include "cifs_unicode.h" |
| @@ -29,54 +29,56 @@ | |||
| 29 | #include <linux/ctype.h> | 29 | #include <linux/ctype.h> |
| 30 | #include <linux/random.h> | 30 | #include <linux/random.h> |
| 31 | 31 | ||
| 32 | /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ | 32 | /* Calculate and return the CIFS signature based on the mac key and SMB PDU */ |
| 33 | /* the 16 byte signature must be allocated by the caller */ | 33 | /* the 16 byte signature must be allocated by the caller */ |
| 34 | /* Note we only use the 1st eight bytes */ | 34 | /* Note we only use the 1st eight bytes */ |
| 35 | /* Note that the smb header signature field on input contains the | 35 | /* Note that the smb header signature field on input contains the |
| 36 | sequence number before this function is called */ | 36 | sequence number before this function is called */ |
| 37 | 37 | ||
| 38 | extern void mdfour(unsigned char *out, unsigned char *in, int n); | 38 | extern void mdfour(unsigned char *out, unsigned char *in, int n); |
| 39 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); | 39 | extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); |
| 40 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | 40 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, |
| 41 | unsigned char *p24); | 41 | unsigned char *p24); |
| 42 | 42 | ||
| 43 | static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, | 43 | static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, |
| 44 | const char * key, char * signature) | 44 | const char *key, char *signature) |
| 45 | { | 45 | { |
| 46 | struct MD5Context context; | 46 | struct MD5Context context; |
| 47 | 47 | ||
| 48 | if((cifs_pdu == NULL) || (signature == NULL)) | 48 | if ((cifs_pdu == NULL) || (signature == NULL)) |
| 49 | return -EINVAL; | 49 | return -EINVAL; |
| 50 | 50 | ||
| 51 | MD5Init(&context); | 51 | MD5Init(&context); |
| 52 | MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); | 52 | MD5Update(&context, key, CIFS_SESS_KEY_SIZE+16); |
| 53 | MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); | 53 | MD5Update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length); |
| 54 | MD5Final(signature,&context); | 54 | MD5Final(signature, &context); |
| 55 | return 0; | 55 | return 0; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, | 58 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, |
| 59 | __u32 * pexpected_response_sequence_number) | 59 | __u32 *pexpected_response_sequence_number) |
| 60 | { | 60 | { |
| 61 | int rc = 0; | 61 | int rc = 0; |
| 62 | char smb_signature[20]; | 62 | char smb_signature[20]; |
| 63 | 63 | ||
| 64 | if((cifs_pdu == NULL) || (server == NULL)) | 64 | if ((cifs_pdu == NULL) || (server == NULL)) |
| 65 | return -EINVAL; | 65 | return -EINVAL; |
| 66 | 66 | ||
| 67 | if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 67 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
| 68 | return rc; | 68 | return rc; |
| 69 | 69 | ||
| 70 | spin_lock(&GlobalMid_Lock); | 70 | spin_lock(&GlobalMid_Lock); |
| 71 | cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number); | 71 | cifs_pdu->Signature.Sequence.SequenceNumber = |
| 72 | cpu_to_le32(server->sequence_number); | ||
| 72 | cifs_pdu->Signature.Sequence.Reserved = 0; | 73 | cifs_pdu->Signature.Sequence.Reserved = 0; |
| 73 | 74 | ||
| 74 | *pexpected_response_sequence_number = server->sequence_number++; | 75 | *pexpected_response_sequence_number = server->sequence_number++; |
| 75 | server->sequence_number++; | 76 | server->sequence_number++; |
| 76 | spin_unlock(&GlobalMid_Lock); | 77 | spin_unlock(&GlobalMid_Lock); |
| 77 | 78 | ||
| 78 | rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature); | 79 | rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key, |
| 79 | if(rc) | 80 | smb_signature); |
| 81 | if (rc) | ||
| 80 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 82 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
| 81 | else | 83 | else |
| 82 | memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); | 84 | memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); |
| @@ -84,88 +86,88 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, | |||
| 84 | return rc; | 86 | return rc; |
| 85 | } | 87 | } |
| 86 | 88 | ||
| 87 | static int cifs_calc_signature2(const struct kvec * iov, int n_vec, | 89 | static int cifs_calc_signature2(const struct kvec *iov, int n_vec, |
| 88 | const char * key, char * signature) | 90 | const char *key, char *signature) |
| 89 | { | 91 | { |
| 90 | struct MD5Context context; | 92 | struct MD5Context context; |
| 91 | int i; | 93 | int i; |
| 92 | 94 | ||
| 93 | if((iov == NULL) || (signature == NULL)) | 95 | if ((iov == NULL) || (signature == NULL)) |
| 94 | return -EINVAL; | 96 | return -EINVAL; |
| 95 | 97 | ||
| 96 | MD5Init(&context); | 98 | MD5Init(&context); |
| 97 | MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); | 99 | MD5Update(&context, key, CIFS_SESS_KEY_SIZE+16); |
| 98 | for(i=0;i<n_vec;i++) { | 100 | for (i=0;i<n_vec;i++) { |
| 99 | if(iov[i].iov_base == NULL) { | 101 | if (iov[i].iov_base == NULL) { |
| 100 | cERROR(1,("null iovec entry")); | 102 | cERROR(1 ,("null iovec entry")); |
| 101 | return -EIO; | 103 | return -EIO; |
| 102 | } else if(iov[i].iov_len == 0) | 104 | } else if (iov[i].iov_len == 0) |
| 103 | break; /* bail out if we are sent nothing to sign */ | 105 | break; /* bail out if we are sent nothing to sign */ |
| 104 | /* The first entry includes a length field (which does not get | 106 | /* The first entry includes a length field (which does not get |
| 105 | signed that occupies the first 4 bytes before the header */ | 107 | signed that occupies the first 4 bytes before the header */ |
| 106 | if(i==0) { | 108 | if (i == 0) { |
| 107 | if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */ | 109 | if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */ |
| 108 | break; /* nothing to sign or corrupt header */ | 110 | break; /* nothing to sign or corrupt header */ |
| 109 | MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4); | 111 | MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4); |
| 110 | } else | 112 | } else |
| 111 | MD5Update(&context,iov[i].iov_base, iov[i].iov_len); | 113 | MD5Update(&context, iov[i].iov_base, iov[i].iov_len); |
| 112 | } | 114 | } |
| 113 | 115 | ||
| 114 | MD5Final(signature,&context); | 116 | MD5Final(signature, &context); |
| 115 | 117 | ||
| 116 | return 0; | 118 | return 0; |
| 117 | } | 119 | } |
| 118 | 120 | ||
| 119 | 121 | ||
| 120 | int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server, | 122 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
| 121 | __u32 * pexpected_response_sequence_number) | 123 | __u32 * pexpected_response_sequence_number) |
| 122 | { | 124 | { |
| 123 | int rc = 0; | 125 | int rc = 0; |
| 124 | char smb_signature[20]; | 126 | char smb_signature[20]; |
| 125 | struct smb_hdr * cifs_pdu = iov[0].iov_base; | 127 | struct smb_hdr *cifs_pdu = iov[0].iov_base; |
| 126 | 128 | ||
| 127 | if((cifs_pdu == NULL) || (server == NULL)) | 129 | if ((cifs_pdu == NULL) || (server == NULL)) |
| 128 | return -EINVAL; | 130 | return -EINVAL; |
| 129 | 131 | ||
| 130 | if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 132 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
| 131 | return rc; | 133 | return rc; |
| 132 | 134 | ||
| 133 | spin_lock(&GlobalMid_Lock); | 135 | spin_lock(&GlobalMid_Lock); |
| 134 | cifs_pdu->Signature.Sequence.SequenceNumber = | 136 | cifs_pdu->Signature.Sequence.SequenceNumber = |
| 135 | cpu_to_le32(server->sequence_number); | 137 | cpu_to_le32(server->sequence_number); |
| 136 | cifs_pdu->Signature.Sequence.Reserved = 0; | 138 | cifs_pdu->Signature.Sequence.Reserved = 0; |
| 137 | 139 | ||
| 138 | *pexpected_response_sequence_number = server->sequence_number++; | 140 | *pexpected_response_sequence_number = server->sequence_number++; |
| 139 | server->sequence_number++; | 141 | server->sequence_number++; |
| 140 | spin_unlock(&GlobalMid_Lock); | 142 | spin_unlock(&GlobalMid_Lock); |
| 141 | 143 | ||
| 142 | rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, | 144 | rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, |
| 143 | smb_signature); | 145 | smb_signature); |
| 144 | if(rc) | 146 | if (rc) |
| 145 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | 147 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); |
| 146 | else | 148 | else |
| 147 | memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); | 149 | memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); |
| 148 | |||
| 149 | return rc; | ||
| 150 | 150 | ||
| 151 | return rc; | ||
| 151 | } | 152 | } |
| 152 | 153 | ||
| 153 | int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, | 154 | int cifs_verify_signature(struct smb_hdr *cifs_pdu, const char *mac_key, |
| 154 | __u32 expected_sequence_number) | 155 | __u32 expected_sequence_number) |
| 155 | { | 156 | { |
| 156 | unsigned int rc; | 157 | unsigned int rc; |
| 157 | char server_response_sig[8]; | 158 | char server_response_sig[8]; |
| 158 | char what_we_think_sig_should_be[20]; | 159 | char what_we_think_sig_should_be[20]; |
| 159 | 160 | ||
| 160 | if((cifs_pdu == NULL) || (mac_key == NULL)) | 161 | if ((cifs_pdu == NULL) || (mac_key == NULL)) |
| 161 | return -EINVAL; | 162 | return -EINVAL; |
| 162 | 163 | ||
| 163 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) | 164 | if (cifs_pdu->Command == SMB_COM_NEGOTIATE) |
| 164 | return 0; | 165 | return 0; |
| 165 | 166 | ||
| 166 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { | 167 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { |
| 167 | struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; | 168 | struct smb_com_lock_req * pSMB = |
| 168 | if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) | 169 | (struct smb_com_lock_req *)cifs_pdu; |
| 170 | if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) | ||
| 169 | return 0; | 171 | return 0; |
| 170 | } | 172 | } |
| 171 | 173 | ||
