diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 279 |
1 files changed, 144 insertions, 135 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 77cca3809467..0442c3b36799 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -411,8 +411,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
411 | return rc; | 411 | return rc; |
412 | pSMB->hdr.Mid = GetNextMid(server); | 412 | pSMB->hdr.Mid = GetNextMid(server); |
413 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 413 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
414 | /* if (extended_security) | 414 | if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) |
415 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/ | 415 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
416 | 416 | ||
417 | count = 0; | 417 | count = 0; |
418 | for(i=0;i<CIFS_NUM_PROT;i++) { | 418 | for(i=0;i<CIFS_NUM_PROT;i++) { |
@@ -425,162 +425,171 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
425 | 425 | ||
426 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 426 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
427 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 427 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
428 | if (rc == 0) { | 428 | if (rc != 0) |
429 | cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); | 429 | goto neg_err_exit; |
430 | /* Check wct = 1 error case */ | 430 | |
431 | if((pSMBr->hdr.WordCount < 13) | 431 | cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); |
432 | || (pSMBr->DialectIndex == BAD_PROT)) { | 432 | /* Check wct = 1 error case */ |
433 | /* core returns wct = 1, but we do not ask for | 433 | if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { |
434 | core - otherwise it just comes when dialect | 434 | /* core returns wct = 1, but we do not ask for core - otherwise |
435 | index is -1 indicating we could not negotiate | 435 | small wct just comes when dialect index is -1 indicating we |
436 | a common dialect */ | 436 | could not negotiate a common dialect */ |
437 | rc = -EOPNOTSUPP; | ||
438 | goto neg_err_exit; | ||
439 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
440 | } else if((pSMBr->hdr.WordCount == 13) | ||
441 | && (pSMBr->DialectIndex == LANMAN_PROT)) { | ||
442 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; | ||
443 | |||
444 | if((extended_security & CIFSSEC_MAY_LANMAN) || | ||
445 | (extended_security & CIFSSEC_MAY_PLNTXT)) | ||
446 | server->secType = LANMAN; | ||
447 | else { | ||
448 | cERROR(1, ("mount failed weak security disabled" | ||
449 | " in /proc/fs/cifs/SecurityFlags")); | ||
437 | rc = -EOPNOTSUPP; | 450 | rc = -EOPNOTSUPP; |
438 | goto neg_err_exit; | 451 | goto neg_err_exit; |
439 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 452 | } |
440 | } else if((pSMBr->hdr.WordCount == 13) | 453 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); |
441 | && (pSMBr->DialectIndex == LANMAN_PROT)) { | 454 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); |
442 | struct lanman_neg_rsp * rsp = | 455 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), |
443 | (struct lanman_neg_rsp *)pSMBr; | ||
444 | |||
445 | if((extended_security & CIFSSEC_MAY_LANMAN) || | ||
446 | (extended_security & CIFSSEC_MAY_PLNTXT)) | ||
447 | server->secType = LANMAN; | ||
448 | else { | ||
449 | cERROR(1, ("mount failed weak security disabled" | ||
450 | " in /proc/fs/cifs/SecurityFlags")); | ||
451 | rc = -EOPNOTSUPP; | ||
452 | goto neg_err_exit; | ||
453 | } | ||
454 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); | ||
455 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | ||
456 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | ||
457 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 456 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
457 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
458 | /* even though we do not use raw we might as well set this | ||
459 | accurately, in case we ever find a need for it */ | ||
460 | if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
461 | server->maxRw = 0xFF00; | ||
462 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
463 | } else { | ||
464 | server->maxRw = 0;/* we do not need to use raw anyway */ | ||
465 | server->capabilities = CAP_MPX_MODE; | ||
466 | } | ||
467 | server->timeZone = le16_to_cpu(rsp->ServerTimeZone); | ||
458 | 468 | ||
459 | /* BB what do we do with raw mode? BB */ | 469 | /* BB get server time for time conversions and add |
460 | server->timeZone = le16_to_cpu(rsp->ServerTimeZone); | 470 | code to use it and timezone since this is not UTC */ |
461 | /* Do we have to set signing flags? no signing | ||
462 | was available LANMAN - default should be ok */ | ||
463 | |||
464 | /* BB FIXME set default dummy capabilities since | ||
465 | they are not returned by the server in this dialect */ | ||
466 | |||
467 | /* get server time for time conversions and add | ||
468 | code to use it and timezone since this is not UTC */ | ||
469 | 471 | ||
470 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 472 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
471 | memcpy(server->cryptKey, rsp->EncryptionKey, | 473 | memcpy(server->cryptKey, rsp->EncryptionKey, |
472 | CIFS_CRYPTO_KEY_SIZE); | 474 | CIFS_CRYPTO_KEY_SIZE); |
473 | } else { | 475 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
474 | rc = -EIO; | 476 | rc = -EIO; /* need cryptkey unless plain text */ |
475 | goto neg_err_exit; | 477 | goto neg_err_exit; |
476 | } | 478 | } |
477 | 479 | ||
478 | cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ | 480 | cFYI(1,("LANMAN negotiated")); |
481 | /* we will not end up setting signing flags - as no signing | ||
482 | was in LANMAN and server did not return the flags on */ | ||
483 | goto signing_check; | ||
479 | #else /* weak security disabled */ | 484 | #else /* weak security disabled */ |
480 | } else if(pSMBr->hdr.WordCount == 13) { | 485 | } else if(pSMBr->hdr.WordCount == 13) { |
481 | cERROR(1,("mount failed, cifs module not built " | 486 | cERROR(1,("mount failed, cifs module not built " |
482 | "with CIFS_WEAK_PW_HASH support")); | 487 | "with CIFS_WEAK_PW_HASH support")); |
483 | rc = -EOPNOTSUPP; | 488 | rc = -EOPNOTSUPP; |
484 | #endif /* WEAK_PW_HASH */ | 489 | #endif /* WEAK_PW_HASH */ |
485 | goto neg_err_exit; | 490 | goto neg_err_exit; |
486 | } else if(pSMBr->hdr.WordCount != 17) { | 491 | } else if(pSMBr->hdr.WordCount != 17) { |
487 | /* unknown wct */ | 492 | /* unknown wct */ |
488 | rc = -EOPNOTSUPP; | 493 | rc = -EOPNOTSUPP; |
489 | goto neg_err_exit; | 494 | goto neg_err_exit; |
490 | } | 495 | } |
491 | 496 | /* else wct == 17 NTLM */ | |
492 | server->secMode = pSMBr->SecurityMode; | 497 | server->secMode = pSMBr->SecurityMode; |
493 | if((server->secMode & SECMODE_USER) == 0) | 498 | if((server->secMode & SECMODE_USER) == 0) |
494 | cFYI(1,("share mode security")); | 499 | cFYI(1,("share mode security")); |
495 | 500 | ||
496 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) | 501 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) |
497 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 502 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
498 | if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) | 503 | if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) |
499 | #endif /* CIFS_WEAK_PW_HASH */ | 504 | #endif /* CIFS_WEAK_PW_HASH */ |
500 | cERROR(1,("Server requests plain text password" | 505 | cERROR(1,("Server requests plain text password" |
501 | " but client support disabled")); | 506 | " but client support disabled")); |
502 | 507 | ||
503 | if(extended_security & CIFSSEC_MUST_NTLMV2) | 508 | if(extended_security & CIFSSEC_MUST_NTLMV2) |
504 | server->secType = NTLMv2; | 509 | server->secType = NTLMv2; |
505 | else | 510 | else |
506 | server->secType = NTLM; | 511 | server->secType = NTLM; |
507 | /* else krb5 ... */ | 512 | /* else krb5 ... */ |
508 | 513 | ||
509 | /* one byte - no need to convert this or EncryptionKeyLen | 514 | /* one byte, so no need to convert this or EncryptionKeyLen from |
510 | from little endian */ | 515 | little endian */ |
511 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | 516 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); |
512 | /* probably no need to store and check maxvcs */ | 517 | /* probably no need to store and check maxvcs */ |
513 | server->maxBuf = | 518 | server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), |
514 | min(le32_to_cpu(pSMBr->MaxBufferSize), | ||
515 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 519 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
516 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | 520 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); |
517 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); | 521 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); |
518 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | 522 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); |
519 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 523 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
520 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); | 524 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); |
521 | /* BB with UTC do we ever need to be using srvr timezone? */ | 525 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
522 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 526 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, |
523 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, | 527 | CIFS_CRYPTO_KEY_SIZE); |
524 | CIFS_CRYPTO_KEY_SIZE); | 528 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) |
525 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | 529 | && (pSMBr->EncryptionKeyLength == 0)) { |
526 | && (pSMBr->EncryptionKeyLength == 0)) { | 530 | /* decode security blob */ |
527 | /* decode security blob */ | 531 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
528 | } else | 532 | rc = -EIO; /* no crypt key only if plain text pwd */ |
529 | rc = -EIO; | 533 | goto neg_err_exit; |
534 | } | ||
530 | 535 | ||
531 | /* BB might be helpful to save off the domain of server here */ | 536 | /* BB might be helpful to save off the domain of server here */ |
532 | 537 | ||
533 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && | 538 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && |
534 | (server->capabilities & CAP_EXTENDED_SECURITY)) { | 539 | (server->capabilities & CAP_EXTENDED_SECURITY)) { |
535 | count = pSMBr->ByteCount; | 540 | count = pSMBr->ByteCount; |
536 | if (count < 16) | 541 | if (count < 16) |
537 | rc = -EIO; | 542 | rc = -EIO; |
538 | else if (count == 16) { | 543 | else if (count == 16) { |
539 | server->secType = RawNTLMSSP; | 544 | server->secType = RawNTLMSSP; |
540 | if (server->socketUseCount.counter > 1) { | 545 | if (server->socketUseCount.counter > 1) { |
541 | if (memcmp | 546 | if (memcmp(server->server_GUID, |
542 | (server->server_GUID, | 547 | pSMBr->u.extended_response. |
543 | pSMBr->u.extended_response. | 548 | GUID, 16) != 0) { |
544 | GUID, 16) != 0) { | 549 | cFYI(1, ("server UID changed")); |
545 | cFYI(1, ("server UID changed")); | ||
546 | memcpy(server-> | ||
547 | server_GUID, | ||
548 | pSMBr->u. | ||
549 | extended_response. | ||
550 | GUID, 16); | ||
551 | } | ||
552 | } else | ||
553 | memcpy(server->server_GUID, | 550 | memcpy(server->server_GUID, |
554 | pSMBr->u.extended_response. | 551 | pSMBr->u.extended_response.GUID, |
555 | GUID, 16); | 552 | 16); |
556 | } else { | ||
557 | rc = decode_negTokenInit(pSMBr->u. | ||
558 | extended_response. | ||
559 | SecurityBlob, | ||
560 | count - 16, | ||
561 | &server->secType); | ||
562 | if(rc == 1) { | ||
563 | /* BB Need to fill struct for sessetup here */ | ||
564 | rc = -EOPNOTSUPP; | ||
565 | } else { | ||
566 | rc = -EINVAL; | ||
567 | } | 553 | } |
554 | } else | ||
555 | memcpy(server->server_GUID, | ||
556 | pSMBr->u.extended_response.GUID, 16); | ||
557 | } else { | ||
558 | rc = decode_negTokenInit(pSMBr->u.extended_response. | ||
559 | SecurityBlob, | ||
560 | count - 16, | ||
561 | &server->secType); | ||
562 | if(rc == 1) { | ||
563 | /* BB Need to fill struct for sessetup here */ | ||
564 | rc = -EOPNOTSUPP; | ||
565 | } else { | ||
566 | rc = -EINVAL; | ||
568 | } | 567 | } |
569 | } else | ||
570 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
571 | if(sign_CIFS_PDUs == FALSE) { | ||
572 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
573 | cERROR(1, | ||
574 | ("Server requires /proc/fs/cifs/PacketSigningEnabled")); | ||
575 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
576 | } else if(sign_CIFS_PDUs == 1) { | ||
577 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
578 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
579 | } | 568 | } |
580 | 569 | } else | |
570 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
571 | |||
572 | signing_check: | ||
573 | if(sign_CIFS_PDUs == FALSE) { | ||
574 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
575 | cERROR(1,("Server requires " | ||
576 | "/proc/fs/cifs/PacketSigningEnabled to be on")); | ||
577 | server->secMode &= | ||
578 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
579 | } else if(sign_CIFS_PDUs == 1) { | ||
580 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
581 | server->secMode &= | ||
582 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
583 | } else if(sign_CIFS_PDUs == 2) { | ||
584 | if((server->secMode & | ||
585 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { | ||
586 | cERROR(1,("signing required but server lacks support")); | ||
587 | } | ||
581 | } | 588 | } |
582 | neg_err_exit: | 589 | neg_err_exit: |
583 | cifs_buf_release(pSMB); | 590 | cifs_buf_release(pSMB); |
591 | |||
592 | cFYI(1,("negprot rc %d",rc)); | ||
584 | return rc; | 593 | return rc; |
585 | } | 594 | } |
586 | 595 | ||