aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-09-18 23:02:18 -0400
committerSteve French <sfrench@us.ibm.com>2010-09-29 15:04:29 -0400
commit2b149f11978b44199954710d32c0eecf6c9efd9c (patch)
treeefd48d4b64fc07a244890d1fced9c767ae4f369b
parent5f98ca9afb9c004f8948c0d40920503de447918a (diff)
cifs NTLMv2/NTLMSSP ntlmv2 within ntlmssp autentication code
Attribue Value (AV) pairs or Target Info (TI) pairs are part of ntlmv2 authentication. Structure ntlmv2_resp had only definition for two av pairs. So removed it, and now allocation of av pairs is dynamic. For servers like Windows 7/2008, av pairs sent by server in challege packet (type 2 in the ntlmssp exchange/negotiation) can vary. Server sends them during ntlmssp negotiation. So when ntlmssp is used as an authentication mechanism, type 2 challenge packet from server has this information. Pluck it and use the entire blob for authenticaiton purpose. If user has not specified, extract (netbios) domain name from the av pairs which is used to calculate ntlmv2 hash. Servers like Windows 7 are particular about the AV pair blob. Servers like Windows 2003, are not very strict about the contents of av pair blob used during ntlmv2 authentication. So when security mechanism such as ntlmv2 is used (not ntlmv2 in ntlmssp), there is no negotiation and so genereate a minimal blob that gets used in ntlmv2 authentication as well as gets sent. Fields tilen and tilbob are session specific. AV pair values are defined. To calculate ntlmv2 response we need ti/av pair blob. For sec mech like ntlmssp, the blob is plucked from type 2 response from the server. From this blob, netbios name of the domain is retrieved, if user has not already provided, to be included in the Target String as part of ntlmv2 hash calculations. For sec mech like ntlmv2, create a minimal, two av pair blob. The allocated blob is freed in case of error. In case there is no error, this blob is used in calculating ntlmv2 response (in CalcNTLMv2_response) and is also copied on the response to the server, and then freed. The type 3 ntlmssp response is prepared on a buffer, 5 * sizeof of struct _AUTHENTICATE_MESSAGE, an empirical value large enough to hold _AUTHENTICATE_MESSAGE plus a blob with max possible 10 values as part of ntlmv2 response and lmv2 keys and domain, user, workstation names etc. Also, kerberos gets selected as a default mechanism if server supports it, over the other security mechanisms. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/cifsencrypt.c121
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/cifspdu.h1
-rw-r--r--fs/cifs/cifsproto.h2
-rw-r--r--fs/cifs/cifssmb.c16
-rw-r--r--fs/cifs/connect.c2
-rw-r--r--fs/cifs/ntlmssp.h15
-rw-r--r--fs/cifs/sess.c119
8 files changed, 225 insertions, 53 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index eed70cae127..730038a1298 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -27,6 +27,7 @@
27#include "md5.h" 27#include "md5.h"
28#include "cifs_unicode.h" 28#include "cifs_unicode.h"
29#include "cifsproto.h" 29#include "cifsproto.h"
30#include "ntlmssp.h"
30#include <linux/ctype.h> 31#include <linux/ctype.h>
31#include <linux/random.h> 32#include <linux/random.h>
32 33
@@ -262,6 +263,87 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
262} 263}
263#endif /* CIFS_WEAK_PW_HASH */ 264#endif /* CIFS_WEAK_PW_HASH */
264 265
266/* This is just a filler for ntlmv2 type of security mechanisms.
267 * Older servers are not very particular about the contents of av pairs
268 * in the blob and for sec mechs like ntlmv2, there is no negotiation
269 * as in ntlmssp, so unless domain and server netbios and dns names
270 * are specified, there is no way to obtain name. In case of ntlmssp,
271 * server provides that info in type 2 challenge packet
272 */
273static int
274build_avpair_blob(struct cifsSesInfo *ses)
275{
276 struct ntlmssp2_name *attrptr;
277
278 ses->tilen = 2 * sizeof(struct ntlmssp2_name);
279 ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL);
280 if (!ses->tiblob) {
281 ses->tilen = 0;
282 cERROR(1, "Challenge target info allocation failure");
283 return -ENOMEM;
284 }
285 attrptr = (struct ntlmssp2_name *) ses->tiblob;
286 attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
287
288 return 0;
289}
290
291/* Server has provided av pairs/target info in the type 2 challenge
292 * packet and we have plucked it and stored within smb session.
293 * We parse that blob here to find netbios domain name to be used
294 * as part of ntlmv2 authentication (in Target String), if not already
295 * specified on the command line.
296 * If this function returns without any error but without fetching
297 * domain name, authentication may fail against some server but
298 * may not fail against other (those who are not very particular
299 * about target string i.e. for some, just user name might suffice.
300 */
301static int
302find_domain_name(struct cifsSesInfo *ses)
303{
304 unsigned int attrsize;
305 unsigned int type;
306 unsigned int onesize = sizeof(struct ntlmssp2_name);
307 unsigned char *blobptr;
308 unsigned char *blobend;
309 struct ntlmssp2_name *attrptr;
310
311 if (!ses->tilen || !ses->tiblob)
312 return 0;
313
314 blobptr = ses->tiblob;
315 blobend = ses->tiblob + ses->tilen;
316
317 while (blobptr + onesize < blobend) {
318 attrptr = (struct ntlmssp2_name *) blobptr;
319 type = le16_to_cpu(attrptr->type);
320 if (type == NTLMSSP_AV_EOL)
321 break;
322 blobptr += 2; /* advance attr type */
323 attrsize = le16_to_cpu(attrptr->length);
324 blobptr += 2; /* advance attr size */
325 if (blobptr + attrsize > blobend)
326 break;
327 if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
328 if (!attrsize)
329 break;
330 if (!ses->domainName) {
331 ses->domainName =
332 kmalloc(attrsize + 1, GFP_KERNEL);
333 if (!ses->domainName)
334 return -ENOMEM;
335 cifs_from_ucs2(ses->domainName,
336 (__le16 *)blobptr, attrsize, attrsize,
337 load_nls_default(), false);
338 break;
339 }
340 }
341 blobptr += attrsize; /* advance attr value */
342 }
343
344 return 0;
345}
346
265static int calc_ntlmv2_hash(struct cifsSesInfo *ses, 347static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
266 const struct nls_table *nls_cp) 348 const struct nls_table *nls_cp)
267{ 349{
@@ -321,7 +403,8 @@ calc_exit_2:
321 return rc; 403 return rc;
322} 404}
323 405
324void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, 406int
407setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
325 const struct nls_table *nls_cp) 408 const struct nls_table *nls_cp)
326{ 409{
327 int rc; 410 int rc;
@@ -333,15 +416,29 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
333 buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); 416 buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
334 get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); 417 get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
335 buf->reserved2 = 0; 418 buf->reserved2 = 0;
336 buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); 419
337 buf->names[0].length = 0; 420 if (ses->server->secType == RawNTLMSSP) {
338 buf->names[1].type = 0; 421 if (!ses->domainName) {
339 buf->names[1].length = 0; 422 rc = find_domain_name(ses);
423 if (rc) {
424 cERROR(1, "error %d finding domain name", rc);
425 goto setup_ntlmv2_rsp_ret;
426 }
427 }
428 } else {
429 rc = build_avpair_blob(ses);
430 if (rc) {
431 cERROR(1, "error %d building av pair blob", rc);
432 return rc;
433 }
434 }
340 435
341 /* calculate buf->ntlmv2_hash */ 436 /* calculate buf->ntlmv2_hash */
342 rc = calc_ntlmv2_hash(ses, nls_cp); 437 rc = calc_ntlmv2_hash(ses, nls_cp);
343 if (rc) 438 if (rc) {
344 cERROR(1, "could not get v2 hash rc %d", rc); 439 cERROR(1, "could not get v2 hash rc %d", rc);
440 goto setup_ntlmv2_rsp_ret;
441 }
345 CalcNTLMv2_response(ses, resp_buf); 442 CalcNTLMv2_response(ses, resp_buf);
346 443
347 /* now calculate the MAC key for NTLMv2 */ 444 /* now calculate the MAC key for NTLMv2 */
@@ -352,6 +449,15 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
352 memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, 449 memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
353 sizeof(struct ntlmv2_resp)); 450 sizeof(struct ntlmv2_resp));
354 ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); 451 ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);
452
453 return 0;
454
455setup_ntlmv2_rsp_ret:
456 kfree(ses->tiblob);
457 ses->tiblob = NULL;
458 ses->tilen = 0;
459
460 return rc;
355} 461}
356 462
357void CalcNTLMv2_response(const struct cifsSesInfo *ses, 463void CalcNTLMv2_response(const struct cifsSesInfo *ses,
@@ -365,6 +471,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
365 hmac_md5_update(v2_session_response+8, 471 hmac_md5_update(v2_session_response+8,
366 sizeof(struct ntlmv2_resp) - 8, &context); 472 sizeof(struct ntlmv2_resp) - 8, &context);
367 473
474 if (ses->tilen)
475 hmac_md5_update(ses->tiblob, ses->tilen, &context);
476
368 hmac_md5_final(v2_session_response, &context); 477 hmac_md5_final(v2_session_response, &context);
369/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ 478/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
370} 479}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 14dfa9a067e..c68f31cf455 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -222,6 +222,8 @@ struct cifsSesInfo {
222 char userName[MAX_USERNAME_SIZE + 1]; 222 char userName[MAX_USERNAME_SIZE + 1];
223 char *domainName; 223 char *domainName;
224 char *password; 224 char *password;
225 unsigned int tilen; /* length of the target info blob */
226 unsigned char *tiblob; /* target info blob in challenge response */
225 bool need_reconnect:1; /* connection reset, uid now invalid */ 227 bool need_reconnect:1; /* connection reset, uid now invalid */
226}; 228};
227/* no more than one of the following three session flags may be set */ 229/* no more than one of the following three session flags may be set */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 14d036d8db1..b0f4b5656d4 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -663,7 +663,6 @@ struct ntlmv2_resp {
663 __le64 time; 663 __le64 time;
664 __u64 client_chal; /* random */ 664 __u64 client_chal; /* random */
665 __u32 reserved2; 665 __u32 reserved2;
666 struct ntlmssp2_name names[2];
667 /* array of name entries could follow ending in minimum 4 byte struct */ 666 /* array of name entries could follow ending in minimum 4 byte struct */
668} __attribute__((packed)); 667} __attribute__((packed));
669 668
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 099fd6173e0..58861286745 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -368,7 +368,7 @@ extern int cifs_verify_signature(struct smb_hdr *,
368extern int cifs_calculate_session_key(struct session_key *key, const char *rn, 368extern int cifs_calculate_session_key(struct session_key *key, const char *rn,
369 const char *pass); 369 const char *pass);
370extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *); 370extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
371extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, 371extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
372 const struct nls_table *); 372 const struct nls_table *);
373#ifdef CONFIG_CIFS_WEAK_PW_HASH 373#ifdef CONFIG_CIFS_WEAK_PW_HASH
374extern void calc_lanman_hash(const char *password, const char *cryptkey, 374extern void calc_lanman_hash(const char *password, const char *cryptkey,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c65c3419dd3..13c854e4107 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -603,13 +603,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
603 rc = 0; 603 rc = 0;
604 else 604 else
605 rc = -EINVAL; 605 rc = -EINVAL;
606 606 if (server->secType == Kerberos) {
607 if (server->sec_kerberos || server->sec_mskerberos) 607 if (!server->sec_kerberos &&
608 server->secType = Kerberos; 608 !server->sec_mskerberos)
609 else if (server->sec_ntlmssp) 609 rc = -EOPNOTSUPP;
610 server->secType = RawNTLMSSP; 610 } else if (server->secType == RawNTLMSSP) {
611 else 611 if (!server->sec_ntlmssp)
612 rc = -EOPNOTSUPP; 612 rc = -EOPNOTSUPP;
613 } else
614 rc = -EOPNOTSUPP;
613 } 615 }
614 } else 616 } else
615 server->capabilities &= ~CAP_EXTENDED_SECURITY; 617 server->capabilities &= ~CAP_EXTENDED_SECURITY;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 88c84a38bcc..c99760a523b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1740,6 +1740,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
1740 if (ses == NULL) 1740 if (ses == NULL)
1741 goto get_ses_fail; 1741 goto get_ses_fail;
1742 1742
1743 ses->tilen = 0;
1744 ses->tiblob = NULL;
1743 /* new SMB session uses our server ref */ 1745 /* new SMB session uses our server ref */
1744 ses->server = server; 1746 ses->server = server;
1745 if (server->addr.sockAddr6.sin6_family == AF_INET6) 1747 if (server->addr.sockAddr6.sin6_family == AF_INET6)
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index 49c9a4e7531..5d52e4a3b1e 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -61,6 +61,21 @@
61#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 61#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
62#define NTLMSSP_NEGOTIATE_56 0x80000000 62#define NTLMSSP_NEGOTIATE_56 0x80000000
63 63
64/* Define AV Pair Field IDs */
65enum av_field_type {
66 NTLMSSP_AV_EOL = 0,
67 NTLMSSP_AV_NB_COMPUTER_NAME,
68 NTLMSSP_AV_NB_DOMAIN_NAME,
69 NTLMSSP_AV_DNS_COMPUTER_NAME,
70 NTLMSSP_AV_DNS_DOMAIN_NAME,
71 NTLMSSP_AV_DNS_TREE_NAME,
72 NTLMSSP_AV_FLAGS,
73 NTLMSSP_AV_TIMESTAMP,
74 NTLMSSP_AV_RESTRICTION,
75 NTLMSSP_AV_TARGET_NAME,
76 NTLMSSP_AV_CHANNEL_BINDINGS
77};
78
64/* Although typedefs are not commonly used for structure definitions */ 79/* Although typedefs are not commonly used for structure definitions */
65/* in the Linux kernel, in this particular case they are useful */ 80/* in the Linux kernel, in this particular case they are useful */
66/* to more closely match the standards document for NTLMSSP from */ 81/* to more closely match the standards document for NTLMSSP from */
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 88820127650..af18a500f7e 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -383,6 +383,9 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft,
383static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, 383static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
384 struct cifsSesInfo *ses) 384 struct cifsSesInfo *ses)
385{ 385{
386 unsigned int tioffset; /* challenge message target info area */
387 unsigned int tilen; /* challenge message target info area length */
388
386 CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr; 389 CHALLENGE_MESSAGE *pblob = (CHALLENGE_MESSAGE *)bcc_ptr;
387 390
388 if (blob_len < sizeof(CHALLENGE_MESSAGE)) { 391 if (blob_len < sizeof(CHALLENGE_MESSAGE)) {
@@ -405,6 +408,19 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
405 /* BB spec says that if AvId field of MsvAvTimestamp is populated then 408 /* BB spec says that if AvId field of MsvAvTimestamp is populated then
406 we must set the MIC field of the AUTHENTICATE_MESSAGE */ 409 we must set the MIC field of the AUTHENTICATE_MESSAGE */
407 410
411 tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
412 tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
413 ses->tilen = tilen;
414 if (ses->tilen) {
415 ses->tiblob = kmalloc(tilen, GFP_KERNEL);
416 if (!ses->tiblob) {
417 cERROR(1, "Challenge target info allocation failure");
418 ses->tilen = 0;
419 return -ENOMEM;
420 }
421 memcpy(ses->tiblob, bcc_ptr + tioffset, ses->tilen);
422 }
423
408 return 0; 424 return 0;
409} 425}
410 426
@@ -425,7 +441,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
425 /* BB is NTLMV2 session security format easier to use here? */ 441 /* BB is NTLMV2 session security format easier to use here? */
426 flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | 442 flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET |
427 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | 443 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
428 NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; 444 NTLMSSP_NEGOTIATE_NTLM;
429 if (ses->server->secMode & 445 if (ses->server->secMode &
430 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 446 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
431 flags |= NTLMSSP_NEGOTIATE_SIGN; 447 flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -449,12 +465,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
449 This function returns the length of the data in the blob */ 465 This function returns the length of the data in the blob */
450static int build_ntlmssp_auth_blob(unsigned char *pbuffer, 466static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
451 struct cifsSesInfo *ses, 467 struct cifsSesInfo *ses,
452 const struct nls_table *nls_cp, bool first) 468 const struct nls_table *nls_cp)
453{ 469{
470 int rc;
471 unsigned int size;
454 AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer; 472 AUTHENTICATE_MESSAGE *sec_blob = (AUTHENTICATE_MESSAGE *)pbuffer;
455 __u32 flags; 473 __u32 flags;
456 unsigned char *tmp; 474 unsigned char *tmp;
457 char ntlm_session_key[CIFS_SESS_KEY_SIZE]; 475 struct ntlmv2_resp ntlmv2_response = {};
458 476
459 memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); 477 memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8);
460 sec_blob->MessageType = NtLmAuthenticate; 478 sec_blob->MessageType = NtLmAuthenticate;
@@ -462,7 +480,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
462 flags = NTLMSSP_NEGOTIATE_56 | 480 flags = NTLMSSP_NEGOTIATE_56 |
463 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | 481 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
464 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | 482 NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
465 NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; 483 NTLMSSP_NEGOTIATE_NTLM;
466 if (ses->server->secMode & 484 if (ses->server->secMode &
467 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 485 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
468 flags |= NTLMSSP_NEGOTIATE_SIGN; 486 flags |= NTLMSSP_NEGOTIATE_SIGN;
@@ -477,19 +495,26 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
477 sec_blob->LmChallengeResponse.Length = 0; 495 sec_blob->LmChallengeResponse.Length = 0;
478 sec_blob->LmChallengeResponse.MaximumLength = 0; 496 sec_blob->LmChallengeResponse.MaximumLength = 0;
479 497
480 /* calculate session key, BB what about adding similar ntlmv2 path? */
481 SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key);
482 if (first)
483 cifs_calculate_session_key(&ses->server->session_key,
484 ntlm_session_key, ses->password);
485
486 memcpy(tmp, ntlm_session_key, CIFS_SESS_KEY_SIZE);
487 sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer); 498 sec_blob->NtChallengeResponse.BufferOffset = cpu_to_le32(tmp - pbuffer);
488 sec_blob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); 499 rc = setup_ntlmv2_rsp(ses, (char *)&ntlmv2_response, nls_cp);
489 sec_blob->NtChallengeResponse.MaximumLength = 500 if (rc) {
490 cpu_to_le16(CIFS_SESS_KEY_SIZE); 501 cERROR(1, "Error %d during NTLMSSP authentication", rc);
502 goto setup_ntlmv2_ret;
503 }
504 size = sizeof(struct ntlmv2_resp);
505 memcpy(tmp, (char *)&ntlmv2_response, size);
506 tmp += size;
507 if (ses->tilen > 0) {
508 memcpy(tmp, ses->tiblob, ses->tilen);
509 tmp += ses->tilen;
510 }
491 511
492 tmp += CIFS_SESS_KEY_SIZE; 512 sec_blob->NtChallengeResponse.Length = cpu_to_le16(size + ses->tilen);
513 sec_blob->NtChallengeResponse.MaximumLength =
514 cpu_to_le16(size + ses->tilen);
515 kfree(ses->tiblob);
516 ses->tiblob = NULL;
517 ses->tilen = 0;
493 518
494 if (ses->domainName == NULL) { 519 if (ses->domainName == NULL) {
495 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); 520 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
@@ -501,7 +526,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
501 len = cifs_strtoUCS((__le16 *)tmp, ses->domainName, 526 len = cifs_strtoUCS((__le16 *)tmp, ses->domainName,
502 MAX_USERNAME_SIZE, nls_cp); 527 MAX_USERNAME_SIZE, nls_cp);
503 len *= 2; /* unicode is 2 bytes each */ 528 len *= 2; /* unicode is 2 bytes each */
504 len += 2; /* trailing null */
505 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer); 529 sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
506 sec_blob->DomainName.Length = cpu_to_le16(len); 530 sec_blob->DomainName.Length = cpu_to_le16(len);
507 sec_blob->DomainName.MaximumLength = cpu_to_le16(len); 531 sec_blob->DomainName.MaximumLength = cpu_to_le16(len);
@@ -518,7 +542,6 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
518 len = cifs_strtoUCS((__le16 *)tmp, ses->userName, 542 len = cifs_strtoUCS((__le16 *)tmp, ses->userName,
519 MAX_USERNAME_SIZE, nls_cp); 543 MAX_USERNAME_SIZE, nls_cp);
520 len *= 2; /* unicode is 2 bytes each */ 544 len *= 2; /* unicode is 2 bytes each */
521 len += 2; /* trailing null */
522 sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer); 545 sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
523 sec_blob->UserName.Length = cpu_to_le16(len); 546 sec_blob->UserName.Length = cpu_to_le16(len);
524 sec_blob->UserName.MaximumLength = cpu_to_le16(len); 547 sec_blob->UserName.MaximumLength = cpu_to_le16(len);
@@ -533,6 +556,8 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
533 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); 556 sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
534 sec_blob->SessionKey.Length = 0; 557 sec_blob->SessionKey.Length = 0;
535 sec_blob->SessionKey.MaximumLength = 0; 558 sec_blob->SessionKey.MaximumLength = 0;
559
560setup_ntlmv2_ret:
536 return tmp - pbuffer; 561 return tmp - pbuffer;
537} 562}
538 563
@@ -545,19 +570,6 @@ static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB,
545 570
546 return; 571 return;
547} 572}
548
549static int setup_ntlmssp_auth_req(SESSION_SETUP_ANDX *pSMB,
550 struct cifsSesInfo *ses,
551 const struct nls_table *nls, bool first_time)
552{
553 int bloblen;
554
555 bloblen = build_ntlmssp_auth_blob(&pSMB->req.SecurityBlob[0], ses, nls,
556 first_time);
557 pSMB->req.SecurityBlobLength = cpu_to_le16(bloblen);
558
559 return bloblen;
560}
561#endif 573#endif
562 574
563int 575int
@@ -580,6 +592,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
580 struct key *spnego_key = NULL; 592 struct key *spnego_key = NULL;
581 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */ 593 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
582 bool first_time; 594 bool first_time;
595 int blob_len;
596 char *ntlmsspblob = NULL;
583 597
584 if (ses == NULL) 598 if (ses == NULL)
585 return -EINVAL; 599 return -EINVAL;
@@ -729,12 +743,24 @@ ssetup_ntlmssp_authenticate:
729 cpu_to_le16(sizeof(struct ntlmv2_resp)); 743 cpu_to_le16(sizeof(struct ntlmv2_resp));
730 744
731 /* calculate session key */ 745 /* calculate session key */
732 setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); 746 rc = setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
733 /* FIXME: calculate MAC key */ 747 if (rc) {
748 cERROR(1, "Error %d during NTLMv2 authentication", rc);
749 kfree(v2_sess_key);
750 goto ssetup_exit;
751 }
734 memcpy(bcc_ptr, (char *)v2_sess_key, 752 memcpy(bcc_ptr, (char *)v2_sess_key,
735 sizeof(struct ntlmv2_resp)); 753 sizeof(struct ntlmv2_resp));
736 bcc_ptr += sizeof(struct ntlmv2_resp); 754 bcc_ptr += sizeof(struct ntlmv2_resp);
737 kfree(v2_sess_key); 755 kfree(v2_sess_key);
756 if (ses->tilen > 0) {
757 memcpy(bcc_ptr, ses->tiblob, ses->tilen);
758 bcc_ptr += ses->tilen;
759 /* we never did allocate ses->domainName to free */
760 kfree(ses->tiblob);
761 ses->tiblob = NULL;
762 ses->tilen = 0;
763 }
738 if (ses->capabilities & CAP_UNICODE) { 764 if (ses->capabilities & CAP_UNICODE) {
739 if (iov[0].iov_len % 2) { 765 if (iov[0].iov_len % 2) {
740 *bcc_ptr = 0; 766 *bcc_ptr = 0;
@@ -815,12 +841,28 @@ ssetup_ntlmssp_authenticate:
815 if (phase == NtLmNegotiate) { 841 if (phase == NtLmNegotiate) {
816 setup_ntlmssp_neg_req(pSMB, ses); 842 setup_ntlmssp_neg_req(pSMB, ses);
817 iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); 843 iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
844 iov[1].iov_base = &pSMB->req.SecurityBlob[0];
818 } else if (phase == NtLmAuthenticate) { 845 } else if (phase == NtLmAuthenticate) {
819 int blob_len; 846 /* 5 is an empirical value, large enought to
820 blob_len = setup_ntlmssp_auth_req(pSMB, ses, 847 * hold authenticate message, max 10 of
821 nls_cp, 848 * av paris, doamin,user,workstation mames,
822 first_time); 849 * flags etc..
850 */
851 ntlmsspblob = kmalloc(
852 5*sizeof(struct _AUTHENTICATE_MESSAGE),
853 GFP_KERNEL);
854 if (!ntlmsspblob) {
855 cERROR(1, "Can't allocate NTLMSSP");
856 rc = -ENOMEM;
857 goto ssetup_exit;
858 }
859
860 blob_len = build_ntlmssp_auth_blob(ntlmsspblob,
861 ses, nls_cp);
823 iov[1].iov_len = blob_len; 862 iov[1].iov_len = blob_len;
863 iov[1].iov_base = ntlmsspblob;
864 pSMB->req.SecurityBlobLength =
865 cpu_to_le16(blob_len);
824 /* Make sure that we tell the server that we 866 /* Make sure that we tell the server that we
825 are using the uid that it just gave us back 867 are using the uid that it just gave us back
826 on the response (challenge) */ 868 on the response (challenge) */
@@ -830,7 +872,6 @@ ssetup_ntlmssp_authenticate:
830 rc = -ENOSYS; 872 rc = -ENOSYS;
831 goto ssetup_exit; 873 goto ssetup_exit;
832 } 874 }
833 iov[1].iov_base = &pSMB->req.SecurityBlob[0];
834 /* unicode strings must be word aligned */ 875 /* unicode strings must be word aligned */
835 if ((iov[0].iov_len + iov[1].iov_len) % 2) { 876 if ((iov[0].iov_len + iov[1].iov_len) % 2) {
836 *bcc_ptr = 0; 877 *bcc_ptr = 0;
@@ -931,6 +972,8 @@ ssetup_exit:
931 key_put(spnego_key); 972 key_put(spnego_key);
932 } 973 }
933 kfree(str_area); 974 kfree(str_area);
975 kfree(ntlmsspblob);
976 ntlmsspblob = NULL;
934 if (resp_buf_type == CIFS_SMALL_BUFFER) { 977 if (resp_buf_type == CIFS_SMALL_BUFFER) {
935 cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base); 978 cFYI(1, "ssetup freeing small buf %p", iov[0].iov_base);
936 cifs_small_buf_release(iov[0].iov_base); 979 cifs_small_buf_release(iov[0].iov_base);