diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 273 |
1 files changed, 192 insertions, 81 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 925881e00ff2..271a037a386f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -44,8 +44,11 @@ static struct { | |||
44 | int index; | 44 | int index; |
45 | char *name; | 45 | char *name; |
46 | } protocols[] = { | 46 | } protocols[] = { |
47 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
48 | {LANMAN_PROT, "\2LM1.2X002"}, | ||
49 | #endif /* weak password hashing for legacy clients */ | ||
47 | {CIFS_PROT, "\2NT LM 0.12"}, | 50 | {CIFS_PROT, "\2NT LM 0.12"}, |
48 | {CIFS_PROT, "\2POSIX 2"}, | 51 | {POSIX_PROT, "\2POSIX 2"}, |
49 | {BAD_PROT, "\2"} | 52 | {BAD_PROT, "\2"} |
50 | }; | 53 | }; |
51 | #else | 54 | #else |
@@ -53,11 +56,29 @@ static struct { | |||
53 | int index; | 56 | int index; |
54 | char *name; | 57 | char *name; |
55 | } protocols[] = { | 58 | } protocols[] = { |
59 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
60 | {LANMAN_PROT, "\2LM1.2X002"}, | ||
61 | #endif /* weak password hashing for legacy clients */ | ||
56 | {CIFS_PROT, "\2NT LM 0.12"}, | 62 | {CIFS_PROT, "\2NT LM 0.12"}, |
57 | {BAD_PROT, "\2"} | 63 | {BAD_PROT, "\2"} |
58 | }; | 64 | }; |
59 | #endif | 65 | #endif |
60 | 66 | ||
67 | /* define the number of elements in the cifs dialect array */ | ||
68 | #ifdef CONFIG_CIFS_POSIX | ||
69 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
70 | #define CIFS_NUM_PROT 3 | ||
71 | #else | ||
72 | #define CIFS_NUM_PROT 2 | ||
73 | #endif /* CIFS_WEAK_PW_HASH */ | ||
74 | #else /* not posix */ | ||
75 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
76 | #define CIFS_NUM_PROT 2 | ||
77 | #else | ||
78 | #define CIFS_NUM_PROT 1 | ||
79 | #endif /* CONFIG_CIFS_WEAK_PW_HASH */ | ||
80 | #endif /* CIFS_POSIX */ | ||
81 | |||
61 | 82 | ||
62 | /* Mark as invalid, all open files on tree connections since they | 83 | /* Mark as invalid, all open files on tree connections since they |
63 | were closed when session to server was lost */ | 84 | were closed when session to server was lost */ |
@@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
322 | /* potential retries of smb operations it turns out we can determine */ | 343 | /* potential retries of smb operations it turns out we can determine */ |
323 | /* from the mid flags when the request buffer can be resent without */ | 344 | /* from the mid flags when the request buffer can be resent without */ |
324 | /* having to use a second distinct buffer for the response */ | 345 | /* having to use a second distinct buffer for the response */ |
325 | *response_buf = *request_buf; | 346 | if(response_buf) |
347 | *response_buf = *request_buf; | ||
326 | 348 | ||
327 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 349 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
328 | wct /*wct */ ); | 350 | wct /*wct */ ); |
@@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
373 | NEGOTIATE_RSP *pSMBr; | 395 | NEGOTIATE_RSP *pSMBr; |
374 | int rc = 0; | 396 | int rc = 0; |
375 | int bytes_returned; | 397 | int bytes_returned; |
398 | int i; | ||
376 | struct TCP_Server_Info * server; | 399 | struct TCP_Server_Info * server; |
377 | u16 count; | 400 | u16 count; |
378 | 401 | ||
@@ -388,99 +411,187 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
388 | return rc; | 411 | return rc; |
389 | pSMB->hdr.Mid = GetNextMid(server); | 412 | pSMB->hdr.Mid = GetNextMid(server); |
390 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 413 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
391 | if (extended_security) | 414 | if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) |
392 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 415 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
393 | 416 | ||
394 | count = strlen(protocols[0].name) + 1; | 417 | count = 0; |
395 | strncpy(pSMB->DialectsArray, protocols[0].name, 30); | 418 | for(i=0;i<CIFS_NUM_PROT;i++) { |
396 | /* null guaranteed to be at end of source and target buffers anyway */ | 419 | strncpy(pSMB->DialectsArray+count, protocols[i].name, 16); |
397 | 420 | count += strlen(protocols[i].name) + 1; | |
421 | /* null at end of source and target buffers anyway */ | ||
422 | } | ||
398 | pSMB->hdr.smb_buf_length += count; | 423 | pSMB->hdr.smb_buf_length += count; |
399 | pSMB->ByteCount = cpu_to_le16(count); | 424 | pSMB->ByteCount = cpu_to_le16(count); |
400 | 425 | ||
401 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 426 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
402 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 427 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
403 | if (rc == 0) { | 428 | if (rc != 0) |
404 | server->secMode = pSMBr->SecurityMode; | 429 | goto neg_err_exit; |
405 | if((server->secMode & SECMODE_USER) == 0) | 430 | |
406 | cFYI(1,("share mode security")); | 431 | cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); |
407 | server->secType = NTLM; /* BB override default for | 432 | /* Check wct = 1 error case */ |
408 | NTLMv2 or kerberos v5 */ | 433 | if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { |
409 | /* one byte - no need to convert this or EncryptionKeyLen | 434 | /* core returns wct = 1, but we do not ask for core - otherwise |
410 | from little endian */ | 435 | small wct just comes when dialect index is -1 indicating we |
411 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | 436 | could not negotiate a common dialect */ |
412 | /* probably no need to store and check maxvcs */ | 437 | rc = -EOPNOTSUPP; |
413 | server->maxBuf = | 438 | goto neg_err_exit; |
414 | min(le32_to_cpu(pSMBr->MaxBufferSize), | 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")); | ||
450 | rc = -EOPNOTSUPP; | ||
451 | goto neg_err_exit; | ||
452 | } | ||
453 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); | ||
454 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | ||
455 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | ||
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); | ||
468 | |||
469 | /* BB get server time for time conversions and add | ||
470 | code to use it and timezone since this is not UTC */ | ||
471 | |||
472 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | ||
473 | memcpy(server->cryptKey, rsp->EncryptionKey, | ||
474 | CIFS_CRYPTO_KEY_SIZE); | ||
475 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | ||
476 | rc = -EIO; /* need cryptkey unless plain text */ | ||
477 | goto neg_err_exit; | ||
478 | } | ||
479 | |||
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; | ||
484 | #else /* weak security disabled */ | ||
485 | } else if(pSMBr->hdr.WordCount == 13) { | ||
486 | cERROR(1,("mount failed, cifs module not built " | ||
487 | "with CIFS_WEAK_PW_HASH support")); | ||
488 | rc = -EOPNOTSUPP; | ||
489 | #endif /* WEAK_PW_HASH */ | ||
490 | goto neg_err_exit; | ||
491 | } else if(pSMBr->hdr.WordCount != 17) { | ||
492 | /* unknown wct */ | ||
493 | rc = -EOPNOTSUPP; | ||
494 | goto neg_err_exit; | ||
495 | } | ||
496 | /* else wct == 17 NTLM */ | ||
497 | server->secMode = pSMBr->SecurityMode; | ||
498 | if((server->secMode & SECMODE_USER) == 0) | ||
499 | cFYI(1,("share mode security")); | ||
500 | |||
501 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) | ||
502 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
503 | if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) | ||
504 | #endif /* CIFS_WEAK_PW_HASH */ | ||
505 | cERROR(1,("Server requests plain text password" | ||
506 | " but client support disabled")); | ||
507 | |||
508 | if(extended_security & CIFSSEC_MUST_NTLMV2) | ||
509 | server->secType = NTLMv2; | ||
510 | else | ||
511 | server->secType = NTLM; | ||
512 | /* else krb5 ... */ | ||
513 | |||
514 | /* one byte, so no need to convert this or EncryptionKeyLen from | ||
515 | little endian */ | ||
516 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | ||
517 | /* probably no need to store and check maxvcs */ | ||
518 | server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), | ||
415 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 519 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
416 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | 520 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); |
417 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); | 521 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); |
418 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | 522 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); |
419 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 523 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
420 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); | 524 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); |
421 | /* BB with UTC do we ever need to be using srvr timezone? */ | 525 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
422 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 526 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, |
423 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, | 527 | CIFS_CRYPTO_KEY_SIZE); |
424 | CIFS_CRYPTO_KEY_SIZE); | 528 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) |
425 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | 529 | && (pSMBr->EncryptionKeyLength == 0)) { |
426 | && (pSMBr->EncryptionKeyLength == 0)) { | 530 | /* decode security blob */ |
427 | /* decode security blob */ | 531 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
428 | } else | 532 | rc = -EIO; /* no crypt key only if plain text pwd */ |
429 | rc = -EIO; | 533 | goto neg_err_exit; |
534 | } | ||
430 | 535 | ||
431 | /* 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 */ |
432 | 537 | ||
433 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && | 538 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && |
434 | (server->capabilities & CAP_EXTENDED_SECURITY)) { | 539 | (server->capabilities & CAP_EXTENDED_SECURITY)) { |
435 | count = pSMBr->ByteCount; | 540 | count = pSMBr->ByteCount; |
436 | if (count < 16) | 541 | if (count < 16) |
437 | rc = -EIO; | 542 | rc = -EIO; |
438 | else if (count == 16) { | 543 | else if (count == 16) { |
439 | server->secType = RawNTLMSSP; | 544 | server->secType = RawNTLMSSP; |
440 | if (server->socketUseCount.counter > 1) { | 545 | if (server->socketUseCount.counter > 1) { |
441 | if (memcmp | 546 | if (memcmp(server->server_GUID, |
442 | (server->server_GUID, | 547 | pSMBr->u.extended_response. |
443 | pSMBr->u.extended_response. | 548 | GUID, 16) != 0) { |
444 | GUID, 16) != 0) { | 549 | cFYI(1, ("server UID changed")); |
445 | cFYI(1, ("server UID changed")); | ||
446 | memcpy(server-> | ||
447 | server_GUID, | ||
448 | pSMBr->u. | ||
449 | extended_response. | ||
450 | GUID, 16); | ||
451 | } | ||
452 | } else | ||
453 | memcpy(server->server_GUID, | 550 | memcpy(server->server_GUID, |
454 | pSMBr->u.extended_response. | 551 | pSMBr->u.extended_response.GUID, |
455 | GUID, 16); | 552 | 16); |
456 | } else { | ||
457 | rc = decode_negTokenInit(pSMBr->u. | ||
458 | extended_response. | ||
459 | SecurityBlob, | ||
460 | count - 16, | ||
461 | &server->secType); | ||
462 | if(rc == 1) { | ||
463 | /* BB Need to fill struct for sessetup here */ | ||
464 | rc = -EOPNOTSUPP; | ||
465 | } else { | ||
466 | rc = -EINVAL; | ||
467 | } | 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; | ||
468 | } | 567 | } |
469 | } else | ||
470 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
471 | if(sign_CIFS_PDUs == FALSE) { | ||
472 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
473 | cERROR(1, | ||
474 | ("Server requires /proc/fs/cifs/PacketSigningEnabled")); | ||
475 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
476 | } else if(sign_CIFS_PDUs == 1) { | ||
477 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
478 | server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
479 | } | 568 | } |
480 | 569 | } else | |
570 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
571 | |||
572 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
573 | signing_check: | ||
574 | #endif | ||
575 | if(sign_CIFS_PDUs == FALSE) { | ||
576 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
577 | cERROR(1,("Server requires " | ||
578 | "/proc/fs/cifs/PacketSigningEnabled to be on")); | ||
579 | server->secMode &= | ||
580 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
581 | } else if(sign_CIFS_PDUs == 1) { | ||
582 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
583 | server->secMode &= | ||
584 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
585 | } else if(sign_CIFS_PDUs == 2) { | ||
586 | if((server->secMode & | ||
587 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { | ||
588 | cERROR(1,("signing required but server lacks support")); | ||
589 | } | ||
481 | } | 590 | } |
482 | 591 | neg_err_exit: | |
483 | cifs_buf_release(pSMB); | 592 | cifs_buf_release(pSMB); |
593 | |||
594 | cFYI(1,("negprot rc %d",rc)); | ||
484 | return rc; | 595 | return rc; |
485 | } | 596 | } |
486 | 597 | ||
@@ -2239,7 +2350,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
2239 | } | 2350 | } |
2240 | symlinkinfo[buflen] = 0; /* just in case so the caller | 2351 | symlinkinfo[buflen] = 0; /* just in case so the caller |
2241 | does not go off the end of the buffer */ | 2352 | does not go off the end of the buffer */ |
2242 | cFYI(1,("readlink result - %s ",symlinkinfo)); | 2353 | cFYI(1,("readlink result - %s",symlinkinfo)); |
2243 | } | 2354 | } |
2244 | } | 2355 | } |
2245 | qreparse_out: | 2356 | qreparse_out: |