diff options
-rw-r--r-- | fs/cifs/cifssmb.c | 185 |
1 files changed, 97 insertions, 88 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9b4aea85b15c..5dd4f8a51e0c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -417,6 +417,96 @@ decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) | |||
417 | return 0; | 417 | return 0; |
418 | } | 418 | } |
419 | 419 | ||
420 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
421 | static int | ||
422 | decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr, | ||
423 | unsigned int secFlags) | ||
424 | { | ||
425 | __s16 tmp; | ||
426 | struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; | ||
427 | |||
428 | if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) | ||
429 | return -EOPNOTSUPP; | ||
430 | |||
431 | if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT)) | ||
432 | server->secType = LANMAN; | ||
433 | else { | ||
434 | cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n"); | ||
435 | return -EOPNOTSUPP; | ||
436 | } | ||
437 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); | ||
438 | server->maxReq = min_t(unsigned int, | ||
439 | le16_to_cpu(rsp->MaxMpxCount), | ||
440 | cifs_max_pending); | ||
441 | set_credits(server, server->maxReq); | ||
442 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | ||
443 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | ||
444 | /* even though we do not use raw we might as well set this | ||
445 | accurately, in case we ever find a need for it */ | ||
446 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
447 | server->max_rw = 0xFF00; | ||
448 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
449 | } else { | ||
450 | server->max_rw = 0;/* do not need to use raw anyway */ | ||
451 | server->capabilities = CAP_MPX_MODE; | ||
452 | } | ||
453 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); | ||
454 | if (tmp == -1) { | ||
455 | /* OS/2 often does not set timezone therefore | ||
456 | * we must use server time to calc time zone. | ||
457 | * Could deviate slightly from the right zone. | ||
458 | * Smallest defined timezone difference is 15 minutes | ||
459 | * (i.e. Nepal). Rounding up/down is done to match | ||
460 | * this requirement. | ||
461 | */ | ||
462 | int val, seconds, remain, result; | ||
463 | struct timespec ts, utc; | ||
464 | utc = CURRENT_TIME; | ||
465 | ts = cnvrtDosUnixTm(rsp->SrvTime.Date, | ||
466 | rsp->SrvTime.Time, 0); | ||
467 | cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", | ||
468 | (int)ts.tv_sec, (int)utc.tv_sec, | ||
469 | (int)(utc.tv_sec - ts.tv_sec)); | ||
470 | val = (int)(utc.tv_sec - ts.tv_sec); | ||
471 | seconds = abs(val); | ||
472 | result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; | ||
473 | remain = seconds % MIN_TZ_ADJ; | ||
474 | if (remain >= (MIN_TZ_ADJ / 2)) | ||
475 | result += MIN_TZ_ADJ; | ||
476 | if (val < 0) | ||
477 | result = -result; | ||
478 | server->timeAdj = result; | ||
479 | } else { | ||
480 | server->timeAdj = (int)tmp; | ||
481 | server->timeAdj *= 60; /* also in seconds */ | ||
482 | } | ||
483 | cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); | ||
484 | |||
485 | |||
486 | /* BB get server time for time conversions and add | ||
487 | code to use it and timezone since this is not UTC */ | ||
488 | |||
489 | if (rsp->EncryptionKeyLength == | ||
490 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | ||
491 | memcpy(server->cryptkey, rsp->EncryptionKey, | ||
492 | CIFS_CRYPTO_KEY_SIZE); | ||
493 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | ||
494 | return -EIO; /* need cryptkey unless plain text */ | ||
495 | } | ||
496 | |||
497 | cifs_dbg(FYI, "LANMAN negotiated\n"); | ||
498 | return 0; | ||
499 | } | ||
500 | #else | ||
501 | static inline int | ||
502 | decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr, | ||
503 | unsigned int secFlags) | ||
504 | { | ||
505 | cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); | ||
506 | return -EOPNOTSUPP; | ||
507 | } | ||
508 | #endif | ||
509 | |||
420 | int | 510 | int |
421 | CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | 511 | CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) |
422 | { | 512 | { |
@@ -485,98 +575,19 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | |||
485 | could not negotiate a common dialect */ | 575 | could not negotiate a common dialect */ |
486 | rc = -EOPNOTSUPP; | 576 | rc = -EOPNOTSUPP; |
487 | goto neg_err_exit; | 577 | goto neg_err_exit; |
488 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
489 | } else if ((pSMBr->hdr.WordCount == 13) | ||
490 | && ((server->dialect == LANMAN_PROT) | ||
491 | || (server->dialect == LANMAN2_PROT))) { | ||
492 | __s16 tmp; | ||
493 | struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; | ||
494 | |||
495 | if ((secFlags & CIFSSEC_MAY_LANMAN) || | ||
496 | (secFlags & CIFSSEC_MAY_PLNTXT)) | ||
497 | server->secType = LANMAN; | ||
498 | else { | ||
499 | cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n"); | ||
500 | rc = -EOPNOTSUPP; | ||
501 | goto neg_err_exit; | ||
502 | } | ||
503 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); | ||
504 | server->maxReq = min_t(unsigned int, | ||
505 | le16_to_cpu(rsp->MaxMpxCount), | ||
506 | cifs_max_pending); | ||
507 | set_credits(server, server->maxReq); | ||
508 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | ||
509 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | ||
510 | /* even though we do not use raw we might as well set this | ||
511 | accurately, in case we ever find a need for it */ | ||
512 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
513 | server->max_rw = 0xFF00; | ||
514 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
515 | } else { | ||
516 | server->max_rw = 0;/* do not need to use raw anyway */ | ||
517 | server->capabilities = CAP_MPX_MODE; | ||
518 | } | ||
519 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); | ||
520 | if (tmp == -1) { | ||
521 | /* OS/2 often does not set timezone therefore | ||
522 | * we must use server time to calc time zone. | ||
523 | * Could deviate slightly from the right zone. | ||
524 | * Smallest defined timezone difference is 15 minutes | ||
525 | * (i.e. Nepal). Rounding up/down is done to match | ||
526 | * this requirement. | ||
527 | */ | ||
528 | int val, seconds, remain, result; | ||
529 | struct timespec ts, utc; | ||
530 | utc = CURRENT_TIME; | ||
531 | ts = cnvrtDosUnixTm(rsp->SrvTime.Date, | ||
532 | rsp->SrvTime.Time, 0); | ||
533 | cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", | ||
534 | (int)ts.tv_sec, (int)utc.tv_sec, | ||
535 | (int)(utc.tv_sec - ts.tv_sec)); | ||
536 | val = (int)(utc.tv_sec - ts.tv_sec); | ||
537 | seconds = abs(val); | ||
538 | result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; | ||
539 | remain = seconds % MIN_TZ_ADJ; | ||
540 | if (remain >= (MIN_TZ_ADJ / 2)) | ||
541 | result += MIN_TZ_ADJ; | ||
542 | if (val < 0) | ||
543 | result = -result; | ||
544 | server->timeAdj = result; | ||
545 | } else { | ||
546 | server->timeAdj = (int)tmp; | ||
547 | server->timeAdj *= 60; /* also in seconds */ | ||
548 | } | ||
549 | cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); | ||
550 | |||
551 | |||
552 | /* BB get server time for time conversions and add | ||
553 | code to use it and timezone since this is not UTC */ | ||
554 | |||
555 | if (rsp->EncryptionKeyLength == | ||
556 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | ||
557 | memcpy(ses->server->cryptkey, rsp->EncryptionKey, | ||
558 | CIFS_CRYPTO_KEY_SIZE); | ||
559 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | ||
560 | rc = -EIO; /* need cryptkey unless plain text */ | ||
561 | goto neg_err_exit; | ||
562 | } | ||
563 | |||
564 | cifs_dbg(FYI, "LANMAN negotiated\n"); | ||
565 | /* we will not end up setting signing flags - as no signing | ||
566 | was in LANMAN and server did not return the flags on */ | ||
567 | goto signing_check; | ||
568 | #else /* weak security disabled */ | ||
569 | } else if (pSMBr->hdr.WordCount == 13) { | 578 | } else if (pSMBr->hdr.WordCount == 13) { |
570 | cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); | 579 | rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags); |
571 | rc = -EOPNOTSUPP; | 580 | if (!rc) |
572 | #endif /* WEAK_PW_HASH */ | 581 | goto signing_check; |
573 | goto neg_err_exit; | 582 | else |
583 | goto neg_err_exit; | ||
574 | } else if (pSMBr->hdr.WordCount != 17) { | 584 | } else if (pSMBr->hdr.WordCount != 17) { |
575 | /* unknown wct */ | 585 | /* unknown wct */ |
576 | rc = -EOPNOTSUPP; | 586 | rc = -EOPNOTSUPP; |
577 | goto neg_err_exit; | 587 | goto neg_err_exit; |
578 | } | 588 | } |
579 | /* else wct == 17 NTLM */ | 589 | /* else wct == 17, NTLM or better */ |
590 | |||
580 | server->sec_mode = pSMBr->SecurityMode; | 591 | server->sec_mode = pSMBr->SecurityMode; |
581 | if ((server->sec_mode & SECMODE_USER) == 0) | 592 | if ((server->sec_mode & SECMODE_USER) == 0) |
582 | cifs_dbg(FYI, "share mode security\n"); | 593 | cifs_dbg(FYI, "share mode security\n"); |
@@ -634,9 +645,7 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | |||
634 | if (rc) | 645 | if (rc) |
635 | goto neg_err_exit; | 646 | goto neg_err_exit; |
636 | 647 | ||
637 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
638 | signing_check: | 648 | signing_check: |
639 | #endif | ||
640 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0) { | 649 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0) { |
641 | /* MUST_SIGN already includes the MAY_SIGN FLAG | 650 | /* MUST_SIGN already includes the MAY_SIGN FLAG |
642 | so if this is zero it means that signing is disabled */ | 651 | so if this is zero it means that signing is disabled */ |