diff options
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r-- | fs/cifs/cifsencrypt.c | 122 |
1 files changed, 64 insertions, 58 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 860dc49ba79c..be012a17278a 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -39,7 +39,7 @@ 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 struct mac_key *key, char *signature) | 44 | const struct mac_key *key, char *signature) |
45 | { | 45 | { |
@@ -69,10 +69,10 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
69 | return rc; | 69 | return rc; |
70 | 70 | ||
71 | spin_lock(&GlobalMid_Lock); | 71 | spin_lock(&GlobalMid_Lock); |
72 | cifs_pdu->Signature.Sequence.SequenceNumber = | 72 | cifs_pdu->Signature.Sequence.SequenceNumber = |
73 | cpu_to_le32(server->sequence_number); | 73 | cpu_to_le32(server->sequence_number); |
74 | cifs_pdu->Signature.Sequence.Reserved = 0; | 74 | cifs_pdu->Signature.Sequence.Reserved = 0; |
75 | 75 | ||
76 | *pexpected_response_sequence_number = server->sequence_number++; | 76 | *pexpected_response_sequence_number = server->sequence_number++; |
77 | server->sequence_number++; | 77 | server->sequence_number++; |
78 | spin_unlock(&GlobalMid_Lock); | 78 | spin_unlock(&GlobalMid_Lock); |
@@ -98,9 +98,9 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
98 | 98 | ||
99 | MD5Init(&context); | 99 | MD5Init(&context); |
100 | MD5Update(&context, (char *)&key->data, key->len); | 100 | MD5Update(&context, (char *)&key->data, key->len); |
101 | for (i=0;i<n_vec;i++) { | 101 | for (i = 0; i < n_vec; i++) { |
102 | if (iov[i].iov_base == NULL) { | 102 | if (iov[i].iov_base == NULL) { |
103 | cERROR(1 ,("null iovec entry")); | 103 | cERROR(1, ("null iovec entry")); |
104 | return -EIO; | 104 | return -EIO; |
105 | } else if (iov[i].iov_len == 0) | 105 | } else if (iov[i].iov_len == 0) |
106 | break; /* bail out if we are sent nothing to sign */ | 106 | break; /* bail out if we are sent nothing to sign */ |
@@ -167,36 +167,38 @@ int cifs_verify_signature(struct smb_hdr *cifs_pdu, | |||
167 | return 0; | 167 | return 0; |
168 | 168 | ||
169 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { | 169 | if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { |
170 | struct smb_com_lock_req * pSMB = | 170 | struct smb_com_lock_req *pSMB = |
171 | (struct smb_com_lock_req *)cifs_pdu; | 171 | (struct smb_com_lock_req *)cifs_pdu; |
172 | if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) | 172 | if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) |
173 | return 0; | 173 | return 0; |
174 | } | 174 | } |
175 | 175 | ||
176 | /* BB what if signatures are supposed to be on for session but server does not | 176 | /* BB what if signatures are supposed to be on for session but |
177 | send one? BB */ | 177 | server does not send one? BB */ |
178 | 178 | ||
179 | /* Do not need to verify session setups with signature "BSRSPYL " */ | 179 | /* Do not need to verify session setups with signature "BSRSPYL " */ |
180 | if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) | 180 | if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0) |
181 | cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); | 181 | cFYI(1, ("dummy signature received for smb command 0x%x", |
182 | cifs_pdu->Command)); | ||
182 | 183 | ||
183 | /* save off the origiginal signature so we can modify the smb and check | 184 | /* save off the origiginal signature so we can modify the smb and check |
184 | its signature against what the server sent */ | 185 | its signature against what the server sent */ |
185 | memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); | 186 | memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8); |
186 | 187 | ||
187 | cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number); | 188 | cifs_pdu->Signature.Sequence.SequenceNumber = |
189 | cpu_to_le32(expected_sequence_number); | ||
188 | cifs_pdu->Signature.Sequence.Reserved = 0; | 190 | cifs_pdu->Signature.Sequence.Reserved = 0; |
189 | 191 | ||
190 | rc = cifs_calculate_signature(cifs_pdu, mac_key, | 192 | rc = cifs_calculate_signature(cifs_pdu, mac_key, |
191 | what_we_think_sig_should_be); | 193 | what_we_think_sig_should_be); |
192 | 194 | ||
193 | if(rc) | 195 | if (rc) |
194 | return rc; | 196 | return rc; |
195 | 197 | ||
196 | 198 | /* cifs_dump_mem("what we think it should be: ", | |
197 | /* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ | 199 | what_we_think_sig_should_be, 16); */ |
198 | 200 | ||
199 | if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) | 201 | if (memcmp(server_response_sig, what_we_think_sig_should_be, 8)) |
200 | return -EACCES; | 202 | return -EACCES; |
201 | else | 203 | else |
202 | return 0; | 204 | return 0; |
@@ -218,30 +220,30 @@ int cifs_calculate_mac_key(struct mac_key *key, const char *rn, | |||
218 | return 0; | 220 | return 0; |
219 | } | 221 | } |
220 | 222 | ||
221 | int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, | 223 | int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses, |
222 | const struct nls_table * nls_info) | 224 | const struct nls_table *nls_info) |
223 | { | 225 | { |
224 | char temp_hash[16]; | 226 | char temp_hash[16]; |
225 | struct HMACMD5Context ctx; | 227 | struct HMACMD5Context ctx; |
226 | char * ucase_buf; | 228 | char *ucase_buf; |
227 | __le16 * unicode_buf; | 229 | __le16 *unicode_buf; |
228 | unsigned int i,user_name_len,dom_name_len; | 230 | unsigned int i, user_name_len, dom_name_len; |
229 | 231 | ||
230 | if(ses == NULL) | 232 | if (ses == NULL) |
231 | return -EINVAL; | 233 | return -EINVAL; |
232 | 234 | ||
233 | E_md4hash(ses->password, temp_hash); | 235 | E_md4hash(ses->password, temp_hash); |
234 | 236 | ||
235 | hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); | 237 | hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); |
236 | user_name_len = strlen(ses->userName); | 238 | user_name_len = strlen(ses->userName); |
237 | if(user_name_len > MAX_USERNAME_SIZE) | 239 | if (user_name_len > MAX_USERNAME_SIZE) |
238 | return -EINVAL; | 240 | return -EINVAL; |
239 | if(ses->domainName == NULL) | 241 | if (ses->domainName == NULL) |
240 | return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ | 242 | return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ |
241 | dom_name_len = strlen(ses->domainName); | 243 | dom_name_len = strlen(ses->domainName); |
242 | if (dom_name_len > MAX_USERNAME_SIZE) | 244 | if (dom_name_len > MAX_USERNAME_SIZE) |
243 | return -EINVAL; | 245 | return -EINVAL; |
244 | 246 | ||
245 | ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); | 247 | ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); |
246 | if (ucase_buf == NULL) | 248 | if (ucase_buf == NULL) |
247 | return -ENOMEM; | 249 | return -ENOMEM; |
@@ -250,18 +252,20 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, | |||
250 | kfree(ucase_buf); | 252 | kfree(ucase_buf); |
251 | return -ENOMEM; | 253 | return -ENOMEM; |
252 | } | 254 | } |
253 | 255 | ||
254 | for (i = 0;i < user_name_len; i++) | 256 | for (i = 0; i < user_name_len; i++) |
255 | ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; | 257 | ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; |
256 | ucase_buf[i] = 0; | 258 | ucase_buf[i] = 0; |
257 | user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); | 259 | user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, |
260 | MAX_USERNAME_SIZE*2, nls_info); | ||
258 | unicode_buf[user_name_len] = 0; | 261 | unicode_buf[user_name_len] = 0; |
259 | user_name_len++; | 262 | user_name_len++; |
260 | 263 | ||
261 | for (i = 0; i < dom_name_len; i++) | 264 | for (i = 0; i < dom_name_len; i++) |
262 | ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; | 265 | ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; |
263 | ucase_buf[i] = 0; | 266 | ucase_buf[i] = 0; |
264 | dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); | 267 | dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, |
268 | MAX_USERNAME_SIZE*2, nls_info); | ||
265 | 269 | ||
266 | unicode_buf[user_name_len + dom_name_len] = 0; | 270 | unicode_buf[user_name_len + dom_name_len] = 0; |
267 | hmac_md5_update((const unsigned char *) unicode_buf, | 271 | hmac_md5_update((const unsigned char *) unicode_buf, |
@@ -274,21 +278,22 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, | |||
274 | } | 278 | } |
275 | 279 | ||
276 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 280 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
277 | void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) | 281 | void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key) |
278 | { | 282 | { |
279 | int i; | 283 | int i; |
280 | char password_with_pad[CIFS_ENCPWD_SIZE]; | 284 | char password_with_pad[CIFS_ENCPWD_SIZE]; |
281 | 285 | ||
282 | if(ses->server == NULL) | 286 | if (ses->server == NULL) |
283 | return; | 287 | return; |
284 | 288 | ||
285 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); | 289 | memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); |
286 | if(ses->password) | 290 | if (ses->password) |
287 | strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); | 291 | strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); |
288 | 292 | ||
289 | if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) | 293 | if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) |
290 | if(extended_security & CIFSSEC_MAY_PLNTXT) { | 294 | if (extended_security & CIFSSEC_MAY_PLNTXT) { |
291 | memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); | 295 | memcpy(lnm_session_key, password_with_pad, |
296 | CIFS_ENCPWD_SIZE); | ||
292 | return; | 297 | return; |
293 | } | 298 | } |
294 | 299 | ||
@@ -303,7 +308,7 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) | |||
303 | utf8 and other multibyte codepages each need their own strupper | 308 | utf8 and other multibyte codepages each need their own strupper |
304 | function since a byte at a time will ont work. */ | 309 | function since a byte at a time will ont work. */ |
305 | 310 | ||
306 | for(i = 0; i < CIFS_ENCPWD_SIZE; i++) { | 311 | for (i = 0; i < CIFS_ENCPWD_SIZE; i++) { |
307 | password_with_pad[i] = toupper(password_with_pad[i]); | 312 | password_with_pad[i] = toupper(password_with_pad[i]); |
308 | } | 313 | } |
309 | 314 | ||
@@ -313,19 +318,19 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) | |||
313 | } | 318 | } |
314 | #endif /* CIFS_WEAK_PW_HASH */ | 319 | #endif /* CIFS_WEAK_PW_HASH */ |
315 | 320 | ||
316 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | 321 | static int calc_ntlmv2_hash(struct cifsSesInfo *ses, |
317 | const struct nls_table * nls_cp) | 322 | const struct nls_table *nls_cp) |
318 | { | 323 | { |
319 | int rc = 0; | 324 | int rc = 0; |
320 | int len; | 325 | int len; |
321 | char nt_hash[16]; | 326 | char nt_hash[16]; |
322 | struct HMACMD5Context * pctxt; | 327 | struct HMACMD5Context *pctxt; |
323 | wchar_t * user; | 328 | wchar_t *user; |
324 | wchar_t * domain; | 329 | wchar_t *domain; |
325 | 330 | ||
326 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); | 331 | pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); |
327 | 332 | ||
328 | if(pctxt == NULL) | 333 | if (pctxt == NULL) |
329 | return -ENOMEM; | 334 | return -ENOMEM; |
330 | 335 | ||
331 | /* calculate md4 hash of password */ | 336 | /* calculate md4 hash of password */ |
@@ -337,18 +342,18 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | |||
337 | /* convert ses->userName to unicode and uppercase */ | 342 | /* convert ses->userName to unicode and uppercase */ |
338 | len = strlen(ses->userName); | 343 | len = strlen(ses->userName); |
339 | user = kmalloc(2 + (len * 2), GFP_KERNEL); | 344 | user = kmalloc(2 + (len * 2), GFP_KERNEL); |
340 | if(user == NULL) | 345 | if (user == NULL) |
341 | goto calc_exit_2; | 346 | goto calc_exit_2; |
342 | len = cifs_strtoUCS(user, ses->userName, len, nls_cp); | 347 | len = cifs_strtoUCS(user, ses->userName, len, nls_cp); |
343 | UniStrupr(user); | 348 | UniStrupr(user); |
344 | hmac_md5_update((char *)user, 2*len, pctxt); | 349 | hmac_md5_update((char *)user, 2*len, pctxt); |
345 | 350 | ||
346 | /* convert ses->domainName to unicode and uppercase */ | 351 | /* convert ses->domainName to unicode and uppercase */ |
347 | if(ses->domainName) { | 352 | if (ses->domainName) { |
348 | len = strlen(ses->domainName); | 353 | len = strlen(ses->domainName); |
349 | 354 | ||
350 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); | 355 | domain = kmalloc(2 + (len * 2), GFP_KERNEL); |
351 | if(domain == NULL) | 356 | if (domain == NULL) |
352 | goto calc_exit_1; | 357 | goto calc_exit_1; |
353 | len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); | 358 | len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); |
354 | /* the following line was removed since it didn't work well | 359 | /* the following line was removed since it didn't work well |
@@ -357,24 +362,24 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, | |||
357 | /* UniStrupr(domain); */ | 362 | /* UniStrupr(domain); */ |
358 | 363 | ||
359 | hmac_md5_update((char *)domain, 2*len, pctxt); | 364 | hmac_md5_update((char *)domain, 2*len, pctxt); |
360 | 365 | ||
361 | kfree(domain); | 366 | kfree(domain); |
362 | } | 367 | } |
363 | calc_exit_1: | 368 | calc_exit_1: |
364 | kfree(user); | 369 | kfree(user); |
365 | calc_exit_2: | 370 | calc_exit_2: |
366 | /* BB FIXME what about bytes 24 through 40 of the signing key? | 371 | /* BB FIXME what about bytes 24 through 40 of the signing key? |
367 | compare with the NTLM example */ | 372 | compare with the NTLM example */ |
368 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); | 373 | hmac_md5_final(ses->server->ntlmv2_hash, pctxt); |
369 | 374 | ||
370 | return rc; | 375 | return rc; |
371 | } | 376 | } |
372 | 377 | ||
373 | void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, | 378 | void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, |
374 | const struct nls_table * nls_cp) | 379 | const struct nls_table *nls_cp) |
375 | { | 380 | { |
376 | int rc; | 381 | int rc; |
377 | struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; | 382 | struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf; |
378 | struct HMACMD5Context context; | 383 | struct HMACMD5Context context; |
379 | 384 | ||
380 | buf->blob_signature = cpu_to_le32(0x00000101); | 385 | buf->blob_signature = cpu_to_le32(0x00000101); |
@@ -389,8 +394,8 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, | |||
389 | 394 | ||
390 | /* calculate buf->ntlmv2_hash */ | 395 | /* calculate buf->ntlmv2_hash */ |
391 | rc = calc_ntlmv2_hash(ses, nls_cp); | 396 | rc = calc_ntlmv2_hash(ses, nls_cp); |
392 | if(rc) | 397 | if (rc) |
393 | cERROR(1,("could not get v2 hash rc %d",rc)); | 398 | cERROR(1, ("could not get v2 hash rc %d", rc)); |
394 | CalcNTLMv2_response(ses, resp_buf); | 399 | CalcNTLMv2_response(ses, resp_buf); |
395 | 400 | ||
396 | /* now calculate the MAC key for NTLMv2 */ | 401 | /* now calculate the MAC key for NTLMv2 */ |
@@ -403,16 +408,17 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, | |||
403 | ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); | 408 | ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp); |
404 | } | 409 | } |
405 | 410 | ||
406 | void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) | 411 | void CalcNTLMv2_response(const struct cifsSesInfo *ses, |
412 | char *v2_session_response) | ||
407 | { | 413 | { |
408 | struct HMACMD5Context context; | 414 | struct HMACMD5Context context; |
409 | /* rest of v2 struct already generated */ | 415 | /* rest of v2 struct already generated */ |
410 | memcpy(v2_session_response + 8, ses->server->cryptKey,8); | 416 | memcpy(v2_session_response + 8, ses->server->cryptKey, 8); |
411 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); | 417 | hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context); |
412 | 418 | ||
413 | hmac_md5_update(v2_session_response+8, | 419 | hmac_md5_update(v2_session_response+8, |
414 | sizeof(struct ntlmv2_resp) - 8, &context); | 420 | sizeof(struct ntlmv2_resp) - 8, &context); |
415 | 421 | ||
416 | hmac_md5_final(v2_session_response,&context); | 422 | hmac_md5_final(v2_session_response, &context); |
417 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ | 423 | /* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ |
418 | } | 424 | } |