diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 287 |
1 files changed, 204 insertions, 83 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 925881e00ff2..19678c575dfc 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 */ |
@@ -188,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
188 | return rc; | 209 | return rc; |
189 | } | 210 | } |
190 | 211 | ||
191 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
192 | int | 212 | int |
193 | small_smb_init_no_tc(const int smb_command, const int wct, | 213 | small_smb_init_no_tc(const int smb_command, const int wct, |
194 | struct cifsSesInfo *ses, void **request_buf) | 214 | struct cifsSesInfo *ses, void **request_buf) |
@@ -214,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct, | |||
214 | 234 | ||
215 | return rc; | 235 | return rc; |
216 | } | 236 | } |
217 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
218 | 237 | ||
219 | /* If the return code is zero, this function must fill in request_buf pointer */ | 238 | /* If the return code is zero, this function must fill in request_buf pointer */ |
220 | static int | 239 | static int |
@@ -322,7 +341,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
322 | /* potential retries of smb operations it turns out we can determine */ | 341 | /* potential retries of smb operations it turns out we can determine */ |
323 | /* from the mid flags when the request buffer can be resent without */ | 342 | /* from the mid flags when the request buffer can be resent without */ |
324 | /* having to use a second distinct buffer for the response */ | 343 | /* having to use a second distinct buffer for the response */ |
325 | *response_buf = *request_buf; | 344 | if(response_buf) |
345 | *response_buf = *request_buf; | ||
326 | 346 | ||
327 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 347 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
328 | wct /*wct */ ); | 348 | wct /*wct */ ); |
@@ -373,8 +393,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
373 | NEGOTIATE_RSP *pSMBr; | 393 | NEGOTIATE_RSP *pSMBr; |
374 | int rc = 0; | 394 | int rc = 0; |
375 | int bytes_returned; | 395 | int bytes_returned; |
396 | int i; | ||
376 | struct TCP_Server_Info * server; | 397 | struct TCP_Server_Info * server; |
377 | u16 count; | 398 | u16 count; |
399 | unsigned int secFlags; | ||
378 | 400 | ||
379 | if(ses->server) | 401 | if(ses->server) |
380 | server = ses->server; | 402 | server = ses->server; |
@@ -386,101 +408,200 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
386 | (void **) &pSMB, (void **) &pSMBr); | 408 | (void **) &pSMB, (void **) &pSMBr); |
387 | if (rc) | 409 | if (rc) |
388 | return rc; | 410 | return rc; |
411 | |||
412 | /* if any of auth flags (ie not sign or seal) are overriden use them */ | ||
413 | if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) | ||
414 | secFlags = ses->overrideSecFlg; | ||
415 | else /* if override flags set only sign/seal OR them with global auth */ | ||
416 | secFlags = extended_security | ses->overrideSecFlg; | ||
417 | |||
418 | cFYI(1,("secFlags 0x%x",secFlags)); | ||
419 | |||
389 | pSMB->hdr.Mid = GetNextMid(server); | 420 | pSMB->hdr.Mid = GetNextMid(server); |
390 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 421 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
391 | if (extended_security) | 422 | if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) |
392 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 423 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
393 | 424 | ||
394 | count = strlen(protocols[0].name) + 1; | 425 | count = 0; |
395 | strncpy(pSMB->DialectsArray, protocols[0].name, 30); | 426 | for(i=0;i<CIFS_NUM_PROT;i++) { |
396 | /* null guaranteed to be at end of source and target buffers anyway */ | 427 | strncpy(pSMB->DialectsArray+count, protocols[i].name, 16); |
397 | 428 | count += strlen(protocols[i].name) + 1; | |
429 | /* null at end of source and target buffers anyway */ | ||
430 | } | ||
398 | pSMB->hdr.smb_buf_length += count; | 431 | pSMB->hdr.smb_buf_length += count; |
399 | pSMB->ByteCount = cpu_to_le16(count); | 432 | pSMB->ByteCount = cpu_to_le16(count); |
400 | 433 | ||
401 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 434 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
402 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 435 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
403 | if (rc == 0) { | 436 | if (rc != 0) |
404 | server->secMode = pSMBr->SecurityMode; | 437 | goto neg_err_exit; |
405 | if((server->secMode & SECMODE_USER) == 0) | 438 | |
406 | cFYI(1,("share mode security")); | 439 | cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); |
407 | server->secType = NTLM; /* BB override default for | 440 | /* Check wct = 1 error case */ |
408 | NTLMv2 or kerberos v5 */ | 441 | if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { |
409 | /* one byte - no need to convert this or EncryptionKeyLen | 442 | /* core returns wct = 1, but we do not ask for core - otherwise |
410 | from little endian */ | 443 | small wct just comes when dialect index is -1 indicating we |
411 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | 444 | could not negotiate a common dialect */ |
412 | /* probably no need to store and check maxvcs */ | 445 | rc = -EOPNOTSUPP; |
413 | server->maxBuf = | 446 | goto neg_err_exit; |
414 | min(le32_to_cpu(pSMBr->MaxBufferSize), | 447 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
448 | } else if((pSMBr->hdr.WordCount == 13) | ||
449 | && (pSMBr->DialectIndex == LANMAN_PROT)) { | ||
450 | struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; | ||
451 | |||
452 | if((secFlags & CIFSSEC_MAY_LANMAN) || | ||
453 | (secFlags & CIFSSEC_MAY_PLNTXT)) | ||
454 | server->secType = LANMAN; | ||
455 | else { | ||
456 | cERROR(1, ("mount failed weak security disabled" | ||
457 | " in /proc/fs/cifs/SecurityFlags")); | ||
458 | rc = -EOPNOTSUPP; | ||
459 | goto neg_err_exit; | ||
460 | } | ||
461 | server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); | ||
462 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | ||
463 | server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), | ||
464 | (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | ||
465 | GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); | ||
466 | /* even though we do not use raw we might as well set this | ||
467 | accurately, in case we ever find a need for it */ | ||
468 | if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { | ||
469 | server->maxRw = 0xFF00; | ||
470 | server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; | ||
471 | } else { | ||
472 | server->maxRw = 0;/* we do not need to use raw anyway */ | ||
473 | server->capabilities = CAP_MPX_MODE; | ||
474 | } | ||
475 | server->timeZone = le16_to_cpu(rsp->ServerTimeZone); | ||
476 | |||
477 | /* BB get server time for time conversions and add | ||
478 | code to use it and timezone since this is not UTC */ | ||
479 | |||
480 | if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | ||
481 | memcpy(server->cryptKey, rsp->EncryptionKey, | ||
482 | CIFS_CRYPTO_KEY_SIZE); | ||
483 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { | ||
484 | rc = -EIO; /* need cryptkey unless plain text */ | ||
485 | goto neg_err_exit; | ||
486 | } | ||
487 | |||
488 | cFYI(1,("LANMAN negotiated")); | ||
489 | /* we will not end up setting signing flags - as no signing | ||
490 | was in LANMAN and server did not return the flags on */ | ||
491 | goto signing_check; | ||
492 | #else /* weak security disabled */ | ||
493 | } else if(pSMBr->hdr.WordCount == 13) { | ||
494 | cERROR(1,("mount failed, cifs module not built " | ||
495 | "with CIFS_WEAK_PW_HASH support")); | ||
496 | rc = -EOPNOTSUPP; | ||
497 | #endif /* WEAK_PW_HASH */ | ||
498 | goto neg_err_exit; | ||
499 | } else if(pSMBr->hdr.WordCount != 17) { | ||
500 | /* unknown wct */ | ||
501 | rc = -EOPNOTSUPP; | ||
502 | goto neg_err_exit; | ||
503 | } | ||
504 | /* else wct == 17 NTLM */ | ||
505 | server->secMode = pSMBr->SecurityMode; | ||
506 | if((server->secMode & SECMODE_USER) == 0) | ||
507 | cFYI(1,("share mode security")); | ||
508 | |||
509 | if((server->secMode & SECMODE_PW_ENCRYPT) == 0) | ||
510 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
511 | if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) | ||
512 | #endif /* CIFS_WEAK_PW_HASH */ | ||
513 | cERROR(1,("Server requests plain text password" | ||
514 | " but client support disabled")); | ||
515 | |||
516 | if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) | ||
517 | server->secType = NTLMv2; | ||
518 | else if(secFlags & CIFSSEC_MAY_NTLM) | ||
519 | server->secType = NTLM; | ||
520 | else if(secFlags & CIFSSEC_MAY_NTLMV2) | ||
521 | server->secType = NTLMv2; | ||
522 | /* else krb5 ... any others ... */ | ||
523 | |||
524 | /* one byte, so no need to convert this or EncryptionKeyLen from | ||
525 | little endian */ | ||
526 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | ||
527 | /* probably no need to store and check maxvcs */ | ||
528 | server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), | ||
415 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 529 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
416 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | 530 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); |
417 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); | 531 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); |
418 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | 532 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); |
419 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 533 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
420 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); | 534 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); |
421 | /* BB with UTC do we ever need to be using srvr timezone? */ | 535 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { |
422 | if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { | 536 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, |
423 | memcpy(server->cryptKey, pSMBr->u.EncryptionKey, | 537 | CIFS_CRYPTO_KEY_SIZE); |
424 | CIFS_CRYPTO_KEY_SIZE); | 538 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) |
425 | } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) | 539 | && (pSMBr->EncryptionKeyLength == 0)) { |
426 | && (pSMBr->EncryptionKeyLength == 0)) { | 540 | /* decode security blob */ |
427 | /* decode security blob */ | 541 | } else if (server->secMode & SECMODE_PW_ENCRYPT) { |
428 | } else | 542 | rc = -EIO; /* no crypt key only if plain text pwd */ |
429 | rc = -EIO; | 543 | goto neg_err_exit; |
544 | } | ||
430 | 545 | ||
431 | /* BB might be helpful to save off the domain of server here */ | 546 | /* BB might be helpful to save off the domain of server here */ |
432 | 547 | ||
433 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && | 548 | if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && |
434 | (server->capabilities & CAP_EXTENDED_SECURITY)) { | 549 | (server->capabilities & CAP_EXTENDED_SECURITY)) { |
435 | count = pSMBr->ByteCount; | 550 | count = pSMBr->ByteCount; |
436 | if (count < 16) | 551 | if (count < 16) |
437 | rc = -EIO; | 552 | rc = -EIO; |
438 | else if (count == 16) { | 553 | else if (count == 16) { |
439 | server->secType = RawNTLMSSP; | 554 | server->secType = RawNTLMSSP; |
440 | if (server->socketUseCount.counter > 1) { | 555 | if (server->socketUseCount.counter > 1) { |
441 | if (memcmp | 556 | if (memcmp(server->server_GUID, |
442 | (server->server_GUID, | 557 | pSMBr->u.extended_response. |
443 | pSMBr->u.extended_response. | 558 | GUID, 16) != 0) { |
444 | GUID, 16) != 0) { | 559 | 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, | 560 | memcpy(server->server_GUID, |
454 | pSMBr->u.extended_response. | 561 | pSMBr->u.extended_response.GUID, |
455 | GUID, 16); | 562 | 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 | } | 563 | } |
564 | } else | ||
565 | memcpy(server->server_GUID, | ||
566 | pSMBr->u.extended_response.GUID, 16); | ||
567 | } else { | ||
568 | rc = decode_negTokenInit(pSMBr->u.extended_response. | ||
569 | SecurityBlob, | ||
570 | count - 16, | ||
571 | &server->secType); | ||
572 | if(rc == 1) { | ||
573 | /* BB Need to fill struct for sessetup here */ | ||
574 | rc = -EOPNOTSUPP; | ||
575 | } else { | ||
576 | rc = -EINVAL; | ||
468 | } | 577 | } |
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 | } | 578 | } |
480 | 579 | } else | |
580 | server->capabilities &= ~CAP_EXTENDED_SECURITY; | ||
581 | |||
582 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | ||
583 | signing_check: | ||
584 | #endif | ||
585 | if(sign_CIFS_PDUs == FALSE) { | ||
586 | if(server->secMode & SECMODE_SIGN_REQUIRED) | ||
587 | cERROR(1,("Server requires " | ||
588 | "/proc/fs/cifs/PacketSigningEnabled to be on")); | ||
589 | server->secMode &= | ||
590 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
591 | } else if(sign_CIFS_PDUs == 1) { | ||
592 | if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) | ||
593 | server->secMode &= | ||
594 | ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); | ||
595 | } else if(sign_CIFS_PDUs == 2) { | ||
596 | if((server->secMode & | ||
597 | (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { | ||
598 | cERROR(1,("signing required but server lacks support")); | ||
599 | } | ||
481 | } | 600 | } |
482 | 601 | neg_err_exit: | |
483 | cifs_buf_release(pSMB); | 602 | cifs_buf_release(pSMB); |
603 | |||
604 | cFYI(1,("negprot rc %d",rc)); | ||
484 | return rc; | 605 | return rc; |
485 | } | 606 | } |
486 | 607 | ||
@@ -2239,7 +2360,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
2239 | } | 2360 | } |
2240 | symlinkinfo[buflen] = 0; /* just in case so the caller | 2361 | symlinkinfo[buflen] = 0; /* just in case so the caller |
2241 | does not go off the end of the buffer */ | 2362 | does not go off the end of the buffer */ |
2242 | cFYI(1,("readlink result - %s ",symlinkinfo)); | 2363 | cFYI(1,("readlink result - %s",symlinkinfo)); |
2243 | } | 2364 | } |
2244 | } | 2365 | } |
2245 | qreparse_out: | 2366 | qreparse_out: |