aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/sess.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2007-11-16 18:37:35 -0500
committerSteve French <sfrench@us.ibm.com>2007-11-16 18:37:35 -0500
commit2442421b176420eca7cb68c575fc221332f488d8 (patch)
treeaaf7a89594c9ae116e4a1768a97dcaeb83841c07 /fs/cifs/sess.c
parent8840dee9dc53883883c321d2811e9f87700d9350 (diff)
[CIFS] Have CIFS_SessSetup build correct SPNEGO SessionSetup request
Have CIFS_SessSetup call cifs_get_spnego_key when Kerberos is negotiated. Use the info in the key payload to build a session setup request packet. Also clean up how the request buffer in the function is freed on error. With appropriate user space helper (in samba/source/client). Kerberos support (secure session establishment can be done now via Kerberos, previously users would have to use NTLMv2 instead for more secure session setup). Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r--fs/cifs/sess.c91
1 files changed, 74 insertions, 17 deletions
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
33extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, 34extern 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
562ssetup_exit: 617ssetup_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));