diff options
| -rw-r--r-- | fs/cifs/CHANGES | 1 | ||||
| -rw-r--r-- | fs/cifs/TODO | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
| -rw-r--r-- | fs/cifs/sess.c | 91 |
4 files changed, 77 insertions, 18 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 64dd22239b21..e31aa74f7d9e 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | Version 1.52 | 1 | Version 1.52 |
| 2 | ------------ | 2 | ------------ |
| 3 | Fix oops on second mount to server when null auth is used. | 3 | Fix oops on second mount to server when null auth is used. |
| 4 | Enable experimental Kerberos support | ||
| 4 | 5 | ||
| 5 | Version 1.51 | 6 | Version 1.51 |
| 6 | ------------ | 7 | ------------ |
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 29d4b2715254..a8852c200728 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
| @@ -16,7 +16,7 @@ SecurityDescriptors | |||
| 16 | c) Better pam/winbind integration (e.g. to handle uid mapping | 16 | c) Better pam/winbind integration (e.g. to handle uid mapping |
| 17 | better) | 17 | better) |
| 18 | 18 | ||
| 19 | d) Kerberos/SPNEGO session setup support - (started) | 19 | d) Verify that Kerberos signing works |
| 20 | 20 | ||
| 21 | e) Cleanup now unneeded SessSetup code in | 21 | e) Cleanup now unneeded SessSetup code in |
| 22 | fs/cifs/connect.c and add back in NTLMSSP code if any servers | 22 | fs/cifs/connect.c and add back in NTLMSSP code if any servers |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3525082f5e58..1fde2197ad76 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -110,6 +110,7 @@ struct mac_key { | |||
| 110 | unsigned int len; | 110 | unsigned int len; |
| 111 | union { | 111 | union { |
| 112 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; | 112 | char ntlm[CIFS_SESS_KEY_SIZE + 16]; |
| 113 | char krb5[CIFS_SESS_KEY_SIZE + 16]; /* BB: length correct? */ | ||
| 113 | struct { | 114 | struct { |
| 114 | char key[16]; | 115 | char key[16]; |
| 115 | struct ntlmv2_resp resp; | 116 | struct ntlmv2_resp resp; |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index ed01ef382aa9..d0cb469daab7 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "ntlmssp.h" | 29 | #include "ntlmssp.h" |
| 30 | #include "nterr.h" | 30 | #include "nterr.h" |
| 31 | #include <linux/utsname.h> | 31 | #include <linux/utsname.h> |
| 32 | #include "cifs_spnego.h" | ||
| 32 | 33 | ||
| 33 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 34 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| 34 | unsigned char *p24); | 35 | unsigned char *p24); |
| @@ -340,11 +341,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 340 | SESSION_SETUP_ANDX *pSMB; | 341 | SESSION_SETUP_ANDX *pSMB; |
| 341 | __u32 capabilities; | 342 | __u32 capabilities; |
| 342 | int count; | 343 | int count; |
| 343 | int resp_buf_type = 0; | 344 | int resp_buf_type; |
| 344 | struct kvec iov[2]; | 345 | struct kvec iov[3]; |
| 345 | enum securityEnum type; | 346 | enum securityEnum type; |
| 346 | __u16 action; | 347 | __u16 action; |
| 347 | int bytes_remaining; | 348 | int bytes_remaining; |
| 349 | struct key *spnego_key = NULL; | ||
| 348 | 350 | ||
| 349 | if (ses == NULL) | 351 | if (ses == NULL) |
| 350 | return -EINVAL; | 352 | return -EINVAL; |
| @@ -377,24 +379,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 377 | 379 | ||
| 378 | capabilities = cifs_ssetup_hdr(ses, pSMB); | 380 | capabilities = cifs_ssetup_hdr(ses, pSMB); |
| 379 | 381 | ||
| 380 | /* we will send the SMB in two pieces, | 382 | /* we will send the SMB in three pieces: |
| 381 | a fixed length beginning part, and a | 383 | a fixed length beginning part, an optional |
| 382 | second part which will include the strings | 384 | SPNEGO blob (which can be zero length), and a |
| 383 | and rest of bcc area, in order to avoid having | 385 | last part which will include the strings |
| 384 | to do a large buffer 17K allocation */ | 386 | and rest of bcc area. This allows us to avoid |
| 387 | a large buffer 17K allocation */ | ||
| 385 | iov[0].iov_base = (char *)pSMB; | 388 | iov[0].iov_base = (char *)pSMB; |
| 386 | iov[0].iov_len = smb_buf->smb_buf_length + 4; | 389 | iov[0].iov_len = smb_buf->smb_buf_length + 4; |
| 387 | 390 | ||
| 391 | /* setting this here allows the code at the end of the function | ||
| 392 | to free the request buffer if there's an error */ | ||
| 393 | resp_buf_type = CIFS_SMALL_BUFFER; | ||
| 394 | |||
| 388 | /* 2000 big enough to fit max user, domain, NOS name etc. */ | 395 | /* 2000 big enough to fit max user, domain, NOS name etc. */ |
| 389 | str_area = kmalloc(2000, GFP_KERNEL); | 396 | str_area = kmalloc(2000, GFP_KERNEL); |
| 390 | if (str_area == NULL) { | 397 | if (str_area == NULL) { |
| 391 | cifs_small_buf_release(smb_buf); | 398 | rc = -ENOMEM; |
| 392 | return -ENOMEM; | 399 | goto ssetup_exit; |
| 393 | } | 400 | } |
| 394 | bcc_ptr = str_area; | 401 | bcc_ptr = str_area; |
| 395 | 402 | ||
| 396 | ses->flags &= ~CIFS_SES_LANMAN; | 403 | ses->flags &= ~CIFS_SES_LANMAN; |
| 397 | 404 | ||
| 405 | iov[1].iov_base = NULL; | ||
| 406 | iov[1].iov_len = 0; | ||
| 407 | |||
| 398 | if (type == LANMAN) { | 408 | if (type == LANMAN) { |
| 399 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 409 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
| 400 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; | 410 | char lnm_session_key[CIFS_SESS_KEY_SIZE]; |
| @@ -463,8 +473,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 463 | struct ntlmv2_resp */ | 473 | struct ntlmv2_resp */ |
| 464 | 474 | ||
| 465 | if (v2_sess_key == NULL) { | 475 | if (v2_sess_key == NULL) { |
| 466 | cifs_small_buf_release(smb_buf); | 476 | rc = -ENOMEM; |
| 467 | return -ENOMEM; | 477 | goto ssetup_exit; |
| 468 | } | 478 | } |
| 469 | 479 | ||
| 470 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | 480 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); |
| @@ -499,21 +509,66 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 499 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); | 509 | unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); |
| 500 | } else | 510 | } else |
| 501 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | 511 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); |
| 502 | } else /* NTLMSSP or SPNEGO */ { | 512 | } else if (type == Kerberos) { |
| 513 | #ifdef CONFIG_CIFS_UPCALL | ||
| 514 | struct cifs_spnego_msg *msg; | ||
| 515 | spnego_key = cifs_get_spnego_key(ses); | ||
| 516 | if (IS_ERR(spnego_key)) { | ||
| 517 | rc = PTR_ERR(spnego_key); | ||
| 518 | spnego_key = NULL; | ||
| 519 | goto ssetup_exit; | ||
| 520 | } | ||
| 521 | |||
| 522 | msg = spnego_key->payload.data; | ||
| 523 | /* bail out if key is too long */ | ||
| 524 | if (msg->sesskey_len > | ||
| 525 | sizeof(ses->server->mac_signing_key.data.krb5)) { | ||
| 526 | cERROR(1, ("Kerberos signing key too long (%u bytes)", | ||
| 527 | msg->sesskey_len)); | ||
| 528 | rc = -EOVERFLOW; | ||
| 529 | goto ssetup_exit; | ||
| 530 | } | ||
| 531 | ses->server->mac_signing_key.len = msg->sesskey_len; | ||
| 532 | memcpy(ses->server->mac_signing_key.data.krb5, msg->data, | ||
| 533 | msg->sesskey_len); | ||
| 503 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 534 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 504 | capabilities |= CAP_EXTENDED_SECURITY; | 535 | capabilities |= CAP_EXTENDED_SECURITY; |
| 505 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | 536 | pSMB->req.Capabilities = cpu_to_le32(capabilities); |
| 506 | /* BB set password lengths */ | 537 | iov[1].iov_base = msg->data + msg->sesskey_len; |
| 538 | iov[1].iov_len = msg->secblob_len; | ||
| 539 | pSMB->req.SecurityBlobLength = cpu_to_le16(iov[1].iov_len); | ||
| 540 | |||
| 541 | if (ses->capabilities & CAP_UNICODE) { | ||
| 542 | /* unicode strings must be word aligned */ | ||
| 543 | if (iov[0].iov_len % 2) { | ||
| 544 | *bcc_ptr = 0; | ||
| 545 | bcc_ptr++; | ||
| 546 | } | ||
| 547 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
| 548 | unicode_domain_string(&bcc_ptr, ses, nls_cp); | ||
| 549 | } else | ||
| 550 | /* BB: is this right? */ | ||
| 551 | ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); | ||
| 552 | #else /* ! CONFIG_CIFS_UPCALL */ | ||
| 553 | cERROR(1, ("Kerberos negotiated but upcall support disabled!")); | ||
| 554 | rc = -ENOSYS; | ||
| 555 | goto ssetup_exit; | ||
| 556 | #endif /* CONFIG_CIFS_UPCALL */ | ||
| 557 | } else { | ||
| 558 | cERROR(1, ("secType %d not supported!", type)); | ||
| 559 | rc = -ENOSYS; | ||
| 560 | goto ssetup_exit; | ||
| 507 | } | 561 | } |
| 508 | 562 | ||
| 509 | count = (long) bcc_ptr - (long) str_area; | 563 | iov[2].iov_base = str_area; |
| 564 | iov[2].iov_len = (long) bcc_ptr - (long) str_area; | ||
| 565 | |||
| 566 | count = iov[1].iov_len + iov[2].iov_len; | ||
| 510 | smb_buf->smb_buf_length += count; | 567 | smb_buf->smb_buf_length += count; |
| 511 | 568 | ||
| 512 | BCC_LE(smb_buf) = cpu_to_le16(count); | 569 | BCC_LE(smb_buf) = cpu_to_le16(count); |
| 513 | 570 | ||
| 514 | iov[1].iov_base = str_area; | 571 | rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type, |
| 515 | iov[1].iov_len = count; | ||
| 516 | rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, | ||
| 517 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); | 572 | CIFS_STD_OP /* not long */ | CIFS_LOG_ERROR); |
| 518 | /* SMB request buf freed in SendReceive2 */ | 573 | /* SMB request buf freed in SendReceive2 */ |
| 519 | 574 | ||
| @@ -560,6 +615,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, | |||
| 560 | ses, nls_cp); | 615 | ses, nls_cp); |
| 561 | 616 | ||
| 562 | ssetup_exit: | 617 | ssetup_exit: |
| 618 | if (spnego_key) | ||
| 619 | key_put(spnego_key); | ||
| 563 | kfree(str_area); | 620 | kfree(str_area); |
| 564 | if (resp_buf_type == CIFS_SMALL_BUFFER) { | 621 | if (resp_buf_type == CIFS_SMALL_BUFFER) { |
| 565 | cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); | 622 | cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); |
