diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
| -rw-r--r-- | fs/cifs/cifssmb.c | 425 |
1 files changed, 207 insertions, 218 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a58dc77cc443..a89c4cb4e6cf 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -367,6 +367,185 @@ vt2_err: | |||
| 367 | return -EINVAL; | 367 | return -EINVAL; |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | static int | ||
| 371 | decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr) | ||
| 372 | { | ||
| 373 | int rc = 0; | ||
| 374 | u16 count; | ||
| 375 | char *guid = pSMBr->u.extended_response.GUID; | ||
| 376 | struct TCP_Server_Info *server = ses->server; | ||
| 377 | |||
| 378 | count = get_bcc(&pSMBr->hdr); | ||
| 379 | if (count < SMB1_CLIENT_GUID_SIZE) | ||
| 380 | return -EIO; | ||
| 381 | |||
| 382 | spin_lock(&cifs_tcp_ses_lock); | ||
| 383 | if (server->srv_count > 1) { | ||
| 384 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 385 | if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) { | ||
| 386 | cifs_dbg(FYI, "server UID changed\n"); | ||
| 387 | memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); | ||
| 388 | } | ||
| 389 | } else { | ||
| 390 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 391 | memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE); | ||
| 392 | } | ||
| 393 | |||
| 394 | if (count == SMB1_CLIENT_GUID_SIZE) { | ||
| 395 | server->sec_ntlmssp = true; | ||
| 396 | } else { | ||
| 397 | count -= SMB1_CLIENT_GUID_SIZE; | ||
| 398 | rc = decode_negTokenInit( | ||
| 399 | pSMBr->u.extended_response.SecurityBlob, count, server); | ||
| 400 | if (rc != 1) | ||
| 401 | return -EINVAL; | ||
| 402 | } | ||
| 403 | |||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | int | ||
| 408 | cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) | ||
| 409 | { | ||
| 410 | bool srv_sign_required = server->sec_mode & server->vals->signing_required; | ||
| 411 | bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled; | ||
| 412 | bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN; | ||
| 413 | |||
| 414 | /* | ||
| 415 | * Is signing required by mnt options? If not then check | ||
| 416 | * global_secflags to see if it is there. | ||
| 417 | */ | ||
| 418 | if (!mnt_sign_required) | ||
| 419 | mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) == | ||
| 420 | CIFSSEC_MUST_SIGN); | ||
| 421 | |||
| 422 | /* | ||
| 423 | * If signing is required then it's automatically enabled too, | ||
| 424 | * otherwise, check to see if the secflags allow it. | ||
| 425 | */ | ||
| 426 | mnt_sign_enabled = mnt_sign_required ? mnt_sign_required : | ||
| 427 | (global_secflags & CIFSSEC_MAY_SIGN); | ||
| 428 | |||
| 429 | /* If server requires signing, does client allow it? */ | ||
| 430 | if (srv_sign_required) { | ||
| 431 | if (!mnt_sign_enabled) { | ||
| 432 | cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!"); | ||
| 433 | return -ENOTSUPP; | ||
| 434 | } | ||
| 435 | server->sign = true; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* If client requires signing, does server allow it? */ | ||
| 439 | if (mnt_sign_required) { | ||
| 440 | if (!srv_sign_enabled) { | ||
| 441 | cifs_dbg(VFS, "Server does not support signing!"); | ||
| 442 | return -ENOTSUPP; | ||
| 443 | } | ||
| 444 | server->sign = true; | ||
| 445 | } | ||
| 446 | |||
| 447 | return 0; | ||
| 448 | } | ||
| 449 | |||
| 450 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 451 | static int | ||
| 452 | decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) | ||
| 453 | { | ||
| 454 | __s16 tmp; | ||
| 455 | struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; | ||
| 456 | |||
| 457 | if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) | ||
| 458 | return -EOPNOTSUPP; | ||
| 459 | |||
| 460 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); | ||
| 461 | server->maxReq = min_t(unsigned int, | ||
| 462 | le16_to_cpu(rsp->MaxMpxCount), | ||
| 463 | cifs_max_pending); | ||
| 464 | set_credits(server, server->maxReq); | ||
| 465 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | ||
| 466 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | ||
| 467 | /* even though we do not use raw we might as well set this | ||
| 468 | accurately, in case we ever find a need for it */ | ||
| 469 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
| 470 | server->max_rw = 0xFF00; | ||
| 471 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
| 472 | } else { | ||
| 473 | server->max_rw = 0;/* do not need to use raw anyway */ | ||
| 474 | server->capabilities = CAP_MPX_MODE; | ||
| 475 | } | ||
| 476 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); | ||
| 477 | if (tmp == -1) { | ||
| 478 | /* OS/2 often does not set timezone therefore | ||
| 479 | * we must use server time to calc time zone. | ||
| 480 | * Could deviate slightly from the right zone. | ||
| 481 | * Smallest defined timezone difference is 15 minutes | ||
| 482 | * (i.e. Nepal). Rounding up/down is done to match | ||
| 483 | * this requirement. | ||
| 484 | */ | ||
| 485 | int val, seconds, remain, result; | ||
| 486 | struct timespec ts, utc; | ||
| 487 | utc = CURRENT_TIME; | ||
| 488 | ts = cnvrtDosUnixTm(rsp->SrvTime.Date, | ||
| 489 | rsp->SrvTime.Time, 0); | ||
| 490 | cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", | ||
| 491 | (int)ts.tv_sec, (int)utc.tv_sec, | ||
| 492 | (int)(utc.tv_sec - ts.tv_sec)); | ||
| 493 | val = (int)(utc.tv_sec - ts.tv_sec); | ||
| 494 | seconds = abs(val); | ||
| 495 | result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; | ||
| 496 | remain = seconds % MIN_TZ_ADJ; | ||
| 497 | if (remain >= (MIN_TZ_ADJ / 2)) | ||
| 498 | result += MIN_TZ_ADJ; | ||
| 499 | if (val < 0) | ||
| 500 | result = -result; | ||
| 501 | server->timeAdj = result; | ||
| 502 | } else { | ||
| 503 | server->timeAdj = (int)tmp; | ||
| 504 | server->timeAdj *= 60; /* also in seconds */ | ||
| 505 | } | ||
| 506 | cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); | ||
| 507 | |||
| 508 | |||
| 509 | /* BB get server time for time conversions and add | ||
| 510 | code to use it and timezone since this is not UTC */ | ||
| 511 | |||
| 512 | if (rsp->EncryptionKeyLength == | ||
| 513 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | ||
| 514 | memcpy(server->cryptkey, rsp->EncryptionKey, | ||
| 515 | CIFS_CRYPTO_KEY_SIZE); | ||
| 516 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | ||
| 517 | return -EIO; /* need cryptkey unless plain text */ | ||
| 518 | } | ||
| 519 | |||
| 520 | cifs_dbg(FYI, "LANMAN negotiated\n"); | ||
| 521 | return 0; | ||
| 522 | } | ||
| 523 | #else | ||
| 524 | static inline int | ||
| 525 | decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) | ||
| 526 | { | ||
| 527 | cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); | ||
| 528 | return -EOPNOTSUPP; | ||
| 529 | } | ||
| 530 | #endif | ||
| 531 | |||
| 532 | static bool | ||
| 533 | should_set_ext_sec_flag(enum securityEnum sectype) | ||
| 534 | { | ||
| 535 | switch (sectype) { | ||
| 536 | case RawNTLMSSP: | ||
| 537 | case Kerberos: | ||
| 538 | return true; | ||
| 539 | case Unspecified: | ||
| 540 | if (global_secflags & | ||
| 541 | (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)) | ||
| 542 | return true; | ||
| 543 | /* Fallthrough */ | ||
| 544 | default: | ||
| 545 | return false; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 370 | int | 549 | int |
| 371 | CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | 550 | CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) |
| 372 | { | 551 | { |
| @@ -375,41 +554,24 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | |||
| 375 | int rc = 0; | 554 | int rc = 0; |
| 376 | int bytes_returned; | 555 | int bytes_returned; |
| 377 | int i; | 556 | int i; |
| 378 | struct TCP_Server_Info *server; | 557 | struct TCP_Server_Info *server = ses->server; |
| 379 | u16 count; | 558 | u16 count; |
| 380 | unsigned int secFlags; | ||
| 381 | 559 | ||
| 382 | if (ses->server) | 560 | if (!server) { |
| 383 | server = ses->server; | 561 | WARN(1, "%s: server is NULL!\n", __func__); |
| 384 | else { | 562 | return -EIO; |
| 385 | rc = -EIO; | ||
| 386 | return rc; | ||
| 387 | } | 563 | } |
| 564 | |||
| 388 | rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , | 565 | rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , |
| 389 | (void **) &pSMB, (void **) &pSMBr); | 566 | (void **) &pSMB, (void **) &pSMBr); |
| 390 | if (rc) | 567 | if (rc) |
| 391 | return rc; | 568 | return rc; |
| 392 | 569 | ||
| 393 | /* if any of auth flags (ie not sign or seal) are overriden use them */ | ||
| 394 | if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
| 395 | secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */ | ||
| 396 | else /* if override flags set only sign/seal OR them with global auth */ | ||
| 397 | secFlags = global_secflags | ses->overrideSecFlg; | ||
| 398 | |||
| 399 | cifs_dbg(FYI, "secFlags 0x%x\n", secFlags); | ||
| 400 | |||
| 401 | pSMB->hdr.Mid = get_next_mid(server); | 570 | pSMB->hdr.Mid = get_next_mid(server); |
| 402 | pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); | 571 | pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); |
| 403 | 572 | ||
| 404 | if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) | 573 | if (should_set_ext_sec_flag(ses->sectype)) { |
| 405 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 574 | cifs_dbg(FYI, "Requesting extended security."); |
| 406 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { | ||
| 407 | cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n"); | ||
| 408 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 409 | } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) | ||
| 410 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
| 411 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { | ||
| 412 | cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n"); | ||
| 413 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 575 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 414 | } | 576 | } |
| 415 | 577 | ||
| @@ -436,127 +598,21 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | |||
| 436 | could not negotiate a common dialect */ | 598 | could not negotiate a common dialect */ |
| 437 | rc = -EOPNOTSUPP; | 599 | rc = -EOPNOTSUPP; |
| 438 | goto neg_err_exit; | 600 | goto neg_err_exit; |
| 439 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 440 | } else if ((pSMBr->hdr.WordCount == 13) | ||
| 441 | && ((server->dialect == LANMAN_PROT) | ||
| 442 | || (server->dialect == LANMAN2_PROT))) { | ||
| 443 | __s16 tmp; | ||
| 444 | struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; | ||
| 445 | |||
| 446 | if ((secFlags & CIFSSEC_MAY_LANMAN) || | ||
| 447 | (secFlags & CIFSSEC_MAY_PLNTXT)) | ||
| 448 | server->secType = LANMAN; | ||
| 449 | else { | ||
| 450 | cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n"); | ||
| 451 | rc = -EOPNOTSUPP; | ||
| 452 | goto neg_err_exit; | ||
| 453 | } | ||
| 454 | server->sec_mode = le16_to_cpu(rsp->SecurityMode); | ||
| 455 | server->maxReq = min_t(unsigned int, | ||
| 456 | le16_to_cpu(rsp->MaxMpxCount), | ||
| 457 | cifs_max_pending); | ||
| 458 | set_credits(server, server->maxReq); | ||
| 459 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | ||
| 460 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | ||
| 461 | /* even though we do not use raw we might as well set this | ||
| 462 | accurately, in case we ever find a need for it */ | ||
| 463 | if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
| 464 | server->max_rw = 0xFF00; | ||
| 465 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
| 466 | } else { | ||
| 467 | server->max_rw = 0;/* do not need to use raw anyway */ | ||
| 468 | server->capabilities = CAP_MPX_MODE; | ||
| 469 | } | ||
| 470 | tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); | ||
| 471 | if (tmp == -1) { | ||
| 472 | /* OS/2 often does not set timezone therefore | ||
| 473 | * we must use server time to calc time zone. | ||
| 474 | * Could deviate slightly from the right zone. | ||
| 475 | * Smallest defined timezone difference is 15 minutes | ||
| 476 | * (i.e. Nepal). Rounding up/down is done to match | ||
| 477 | * this requirement. | ||
| 478 | */ | ||
| 479 | int val, seconds, remain, result; | ||
| 480 | struct timespec ts, utc; | ||
| 481 | utc = CURRENT_TIME; | ||
| 482 | ts = cnvrtDosUnixTm(rsp->SrvTime.Date, | ||
| 483 | rsp->SrvTime.Time, 0); | ||
| 484 | cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n", | ||
| 485 | (int)ts.tv_sec, (int)utc.tv_sec, | ||
| 486 | (int)(utc.tv_sec - ts.tv_sec)); | ||
| 487 | val = (int)(utc.tv_sec - ts.tv_sec); | ||
| 488 | seconds = abs(val); | ||
| 489 | result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; | ||
| 490 | remain = seconds % MIN_TZ_ADJ; | ||
| 491 | if (remain >= (MIN_TZ_ADJ / 2)) | ||
| 492 | result += MIN_TZ_ADJ; | ||
| 493 | if (val < 0) | ||
| 494 | result = -result; | ||
| 495 | server->timeAdj = result; | ||
| 496 | } else { | ||
| 497 | server->timeAdj = (int)tmp; | ||
| 498 | server->timeAdj *= 60; /* also in seconds */ | ||
| 499 | } | ||
| 500 | cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); | ||
| 501 | |||
| 502 | |||
| 503 | /* BB get server time for time conversions and add | ||
| 504 | code to use it and timezone since this is not UTC */ | ||
| 505 | |||
| 506 | if (rsp->EncryptionKeyLength == | ||
| 507 | cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { | ||
| 508 | memcpy(ses->server->cryptkey, rsp->EncryptionKey, | ||
| 509 | CIFS_CRYPTO_KEY_SIZE); | ||
| 510 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | ||
| 511 | rc = -EIO; /* need cryptkey unless plain text */ | ||
| 512 | goto neg_err_exit; | ||
| 513 | } | ||
| 514 | |||
| 515 | cifs_dbg(FYI, "LANMAN negotiated\n"); | ||
| 516 | /* we will not end up setting signing flags - as no signing | ||
| 517 | was in LANMAN and server did not return the flags on */ | ||
| 518 | goto signing_check; | ||
| 519 | #else /* weak security disabled */ | ||
| 520 | } else if (pSMBr->hdr.WordCount == 13) { | 601 | } else if (pSMBr->hdr.WordCount == 13) { |
| 521 | cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); | 602 | server->negflavor = CIFS_NEGFLAVOR_LANMAN; |
| 522 | rc = -EOPNOTSUPP; | 603 | rc = decode_lanman_negprot_rsp(server, pSMBr); |
| 523 | #endif /* WEAK_PW_HASH */ | 604 | goto signing_check; |
| 524 | goto neg_err_exit; | ||
| 525 | } else if (pSMBr->hdr.WordCount != 17) { | 605 | } else if (pSMBr->hdr.WordCount != 17) { |
| 526 | /* unknown wct */ | 606 | /* unknown wct */ |
| 527 | rc = -EOPNOTSUPP; | 607 | rc = -EOPNOTSUPP; |
| 528 | goto neg_err_exit; | 608 | goto neg_err_exit; |
| 529 | } | 609 | } |
| 530 | /* else wct == 17 NTLM */ | 610 | /* else wct == 17, NTLM or better */ |
| 611 | |||
| 531 | server->sec_mode = pSMBr->SecurityMode; | 612 | server->sec_mode = pSMBr->SecurityMode; |
| 532 | if ((server->sec_mode & SECMODE_USER) == 0) | 613 | if ((server->sec_mode & SECMODE_USER) == 0) |
| 533 | cifs_dbg(FYI, "share mode security\n"); | 614 | cifs_dbg(FYI, "share mode security\n"); |
| 534 | 615 | ||
| 535 | if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0) | ||
| 536 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 537 | if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) | ||
| 538 | #endif /* CIFS_WEAK_PW_HASH */ | ||
| 539 | cifs_dbg(VFS, "Server requests plain text password but client support disabled\n"); | ||
| 540 | |||
| 541 | if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) | ||
| 542 | server->secType = NTLMv2; | ||
| 543 | else if (secFlags & CIFSSEC_MAY_NTLM) | ||
| 544 | server->secType = NTLM; | ||
| 545 | else if (secFlags & CIFSSEC_MAY_NTLMV2) | ||
| 546 | server->secType = NTLMv2; | ||
| 547 | else if (secFlags & CIFSSEC_MAY_KRB5) | ||
| 548 | server->secType = Kerberos; | ||
| 549 | else if (secFlags & CIFSSEC_MAY_NTLMSSP) | ||
| 550 | server->secType = RawNTLMSSP; | ||
| 551 | else if (secFlags & CIFSSEC_MAY_LANMAN) | ||
| 552 | server->secType = LANMAN; | ||
| 553 | else { | ||
| 554 | rc = -EOPNOTSUPP; | ||
| 555 | cifs_dbg(VFS, "Invalid security type\n"); | ||
| 556 | goto neg_err_exit; | ||
| 557 | } | ||
| 558 | /* else ... any others ...? */ | ||
| 559 | |||
| 560 | /* one byte, so no need to convert this or EncryptionKeyLen from | 616 | /* one byte, so no need to convert this or EncryptionKeyLen from |
| 561 | little endian */ | 617 | little endian */ |
| 562 | server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), | 618 | server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), |
| @@ -569,90 +625,26 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) | |||
| 569 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 625 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
| 570 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); | 626 | server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); |
| 571 | server->timeAdj *= 60; | 627 | server->timeAdj *= 60; |
| 628 | |||
| 572 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 629 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
| 630 | server->negflavor = CIFS_NEGFLAVOR_UNENCAP; | ||
| 573 | memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, | 631 | memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey, |
| 574 | CIFS_CRYPTO_KEY_SIZE); | 632 | CIFS_CRYPTO_KEY_SIZE); |
| 575 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || | 633 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC || |
| 576 | server->capabilities & CAP_EXTENDED_SECURITY) && | 634 | server->capabilities & CAP_EXTENDED_SECURITY) && |
| 577 | (pSMBr->EncryptionKeyLength == 0)) { | 635 | (pSMBr->EncryptionKeyLength == 0)) { |
| 578 | /* decode security blob */ | 636 | server->negflavor = CIFS_NEGFLAVOR_EXTENDED; |
| 579 | count = get_bcc(&pSMBr->hdr); | 637 | rc = decode_ext_sec_blob(ses, pSMBr); |
| 580 | if (count < 16) { | ||
| 581 | rc = -EIO; | ||
| 582 | goto neg_err_exit; | ||
| 583 | } | ||
| 584 | spin_lock(&cifs_tcp_ses_lock); | ||
| 585 | if (server->srv_count > 1) { | ||
| 586 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 587 | if (memcmp(server->server_GUID, | ||
| 588 | pSMBr->u.extended_response. | ||
| 589 | GUID, 16) != 0) { | ||
| 590 | cifs_dbg(FYI, "server UID changed\n"); | ||
| 591 | memcpy(server->server_GUID, | ||
| 592 | pSMBr->u.extended_response.GUID, | ||
| 593 | 16); | ||
| 594 | } | ||
| 595 | } else { | ||
| 596 | spin_unlock(&cifs_tcp_ses_lock); | ||
| 597 | memcpy(server->server_GUID, | ||
| 598 | pSMBr->u.extended_response.GUID, 16); | ||
| 599 | } | ||
| 600 | |||
| 601 | if (count == 16) { | ||
| 602 | server->secType = RawNTLMSSP; | ||
| 603 | } else { | ||
| 604 | rc = decode_negTokenInit(pSMBr->u.extended_response. | ||
| 605 | SecurityBlob, count - 16, | ||
| 606 | server); | ||
| 607 | if (rc == 1) | ||
| 608 | rc = 0; | ||
| 609 | else | ||
| 610 | rc = -EINVAL; | ||
| 611 | if (server->secType == Kerberos) { | ||
| 612 | if (!server->sec_kerberos && | ||
| 613 | !server->sec_mskerberos) | ||
| 614 | rc = -EOPNOTSUPP; | ||
| 615 | } else if (server->secType == RawNTLMSSP) { | ||
| 616 | if (!server->sec_ntlmssp) | ||
| 617 | rc = -EOPNOTSUPP; | ||
| 618 | } else | ||
| 619 | rc = -EOPNOTSUPP; | ||
| 620 | } | ||
| 621 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { | 638 | } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { |
| 622 | rc = -EIO; /* no crypt key only if plain text pwd */ | 639 | rc = -EIO; /* no crypt key only if plain text pwd */ |
| 623 | goto neg_err_exit; | ||
| 624 | } else | ||
| 625 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
| 626 | |||
| 627 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
| 628 | signing_check: | ||
| 629 | #endif | ||
| 630 | if ((secFlags & CIFSSEC_MAY_SIGN) == 0) { | ||
| 631 | /* MUST_SIGN already includes the MAY_SIGN FLAG | ||
| 632 | so if this is zero it means that signing is disabled */ | ||
| 633 | cifs_dbg(FYI, "Signing disabled\n"); | ||
| 634 | if (server->sec_mode & SECMODE_SIGN_REQUIRED) { | ||
| 635 | cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n"); | ||
| 636 | rc = -EOPNOTSUPP; | ||
| 637 | } | ||
| 638 | server->sec_mode &= | ||
| 639 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
| 640 | } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { | ||
| 641 | /* signing required */ | ||
| 642 | cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags); | ||
| 643 | if ((server->sec_mode & | ||
| 644 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { | ||
| 645 | cifs_dbg(VFS, "signing required but server lacks support\n"); | ||
| 646 | rc = -EOPNOTSUPP; | ||
| 647 | } else | ||
| 648 | server->sec_mode |= SECMODE_SIGN_REQUIRED; | ||
| 649 | } else { | 640 | } else { |
| 650 | /* signing optional ie CIFSSEC_MAY_SIGN */ | 641 | server->negflavor = CIFS_NEGFLAVOR_UNENCAP; |
| 651 | if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0) | 642 | server->capabilities &= ~CAP_EXTENDED_SECURITY; |
| 652 | server->sec_mode &= | ||
| 653 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
| 654 | } | 643 | } |
| 655 | 644 | ||
| 645 | signing_check: | ||
| 646 | if (!rc) | ||
| 647 | rc = cifs_enable_signing(server, ses->sign); | ||
| 656 | neg_err_exit: | 648 | neg_err_exit: |
| 657 | cifs_buf_release(pSMB); | 649 | cifs_buf_release(pSMB); |
| 658 | 650 | ||
| @@ -777,9 +769,8 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses) | |||
| 777 | 769 | ||
| 778 | pSMB->hdr.Mid = get_next_mid(ses->server); | 770 | pSMB->hdr.Mid = get_next_mid(ses->server); |
| 779 | 771 | ||
| 780 | if (ses->server->sec_mode & | 772 | if (ses->server->sign) |
| 781 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 773 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
| 782 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 783 | 774 | ||
| 784 | pSMB->hdr.Uid = ses->Suid; | 775 | pSMB->hdr.Uid = ses->Suid; |
| 785 | 776 | ||
| @@ -1540,8 +1531,7 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
| 1540 | switch (mid->mid_state) { | 1531 | switch (mid->mid_state) { |
| 1541 | case MID_RESPONSE_RECEIVED: | 1532 | case MID_RESPONSE_RECEIVED: |
| 1542 | /* result already set, check signature */ | 1533 | /* result already set, check signature */ |
| 1543 | if (server->sec_mode & | 1534 | if (server->sign) { |
| 1544 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | ||
| 1545 | int rc = 0; | 1535 | int rc = 0; |
| 1546 | 1536 | ||
| 1547 | rc = cifs_verify_signature(&rqst, server, | 1537 | rc = cifs_verify_signature(&rqst, server, |
| @@ -3940,6 +3930,7 @@ QFileInfoRetry: | |||
| 3940 | pSMB->Pad = 0; | 3930 | pSMB->Pad = 0; |
| 3941 | pSMB->Fid = netfid; | 3931 | pSMB->Fid = netfid; |
| 3942 | inc_rfc1001_len(pSMB, byte_count); | 3932 | inc_rfc1001_len(pSMB, byte_count); |
| 3933 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); | ||
| 3943 | 3934 | ||
| 3944 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3935 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 3945 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3936 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| @@ -4108,6 +4099,7 @@ UnixQFileInfoRetry: | |||
| 4108 | pSMB->Pad = 0; | 4099 | pSMB->Pad = 0; |
| 4109 | pSMB->Fid = netfid; | 4100 | pSMB->Fid = netfid; |
| 4110 | inc_rfc1001_len(pSMB, byte_count); | 4101 | inc_rfc1001_len(pSMB, byte_count); |
| 4102 | pSMB->t2.ByteCount = cpu_to_le16(byte_count); | ||
| 4111 | 4103 | ||
| 4112 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 4104 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 4113 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 4105 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| @@ -4794,11 +4786,8 @@ getDFSRetry: | |||
| 4794 | strncpy(pSMB->RequestFileName, search_name, name_len); | 4786 | strncpy(pSMB->RequestFileName, search_name, name_len); |
| 4795 | } | 4787 | } |
| 4796 | 4788 | ||
| 4797 | if (ses->server) { | 4789 | if (ses->server && ses->server->sign) |
| 4798 | if (ses->server->sec_mode & | 4790 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
| 4799 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 4800 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
| 4801 | } | ||
| 4802 | 4791 | ||
| 4803 | pSMB->hdr.Uid = ses->Suid; | 4792 | pSMB->hdr.Uid = ses->Suid; |
| 4804 | 4793 | ||
