aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifssmb.c185
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
421static int
422decode_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
501static inline int
502decode_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
420int 510int
421CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) 511CIFSSMBNegotiate(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
638signing_check: 648signing_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 */