aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2pdu.c
diff options
context:
space:
mode:
authorPavel Shilovsky <piastry@etersoft.ru>2011-12-27 07:22:00 -0500
committerPavel Shilovsky <pshilovsky@samba.org>2012-07-24 13:54:57 -0400
commit5478f9ba9a34d660eb3227dcd16314689c51f946 (patch)
tree6cb95588d403d5a962f6450b68d2daaf23566250 /fs/cifs/smb2pdu.c
parentec2e4523fdba88317e06d0c7a88af3a0860447fc (diff)
CIFS: Add session setup/logoff capability for SMB2
Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs/smb2pdu.c')
-rw-r--r--fs/cifs/smb2pdu.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 719e4c4f0307..2165f0d15963 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -328,3 +328,224 @@ neg_exit:
328 free_rsp_buf(resp_buftype, rsp); 328 free_rsp_buf(resp_buftype, rsp);
329 return rc; 329 return rc;
330} 330}
331
332int
333SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
334 const struct nls_table *nls_cp)
335{
336 struct smb2_sess_setup_req *req;
337 struct smb2_sess_setup_rsp *rsp = NULL;
338 struct kvec iov[2];
339 int rc = 0;
340 int resp_buftype;
341 __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
342 struct TCP_Server_Info *server;
343 unsigned int sec_flags;
344 u8 temp = 0;
345 u16 blob_length = 0;
346 char *security_blob;
347 char *ntlmssp_blob = NULL;
348 bool use_spnego = false; /* else use raw ntlmssp */
349
350 cFYI(1, "Session Setup");
351
352 if (ses->server)
353 server = ses->server;
354 else {
355 rc = -EIO;
356 return rc;
357 }
358
359 /*
360 * If memory allocation is successful, caller of this function
361 * frees it.
362 */
363 ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
364 if (!ses->ntlmssp)
365 return -ENOMEM;
366
367 ses->server->secType = RawNTLMSSP;
368
369ssetup_ntlmssp_authenticate:
370 if (phase == NtLmChallenge)
371 phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
372
373 rc = small_smb2_init(SMB2_SESSION_SETUP, NULL, (void **) &req);
374 if (rc)
375 return rc;
376
377 /* if any of auth flags (ie not sign or seal) are overriden use them */
378 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
379 sec_flags = ses->overrideSecFlg; /* BB FIXME fix sign flags?*/
380 else /* if override flags set only sign/seal OR them with global auth */
381 sec_flags = global_secflags | ses->overrideSecFlg;
382
383 cFYI(1, "sec_flags 0x%x", sec_flags);
384
385 req->hdr.SessionId = 0; /* First session, not a reauthenticate */
386 req->VcNumber = 0; /* MBZ */
387 /* to enable echos and oplocks */
388 req->hdr.CreditRequest = cpu_to_le16(3);
389
390 /* only one of SMB2 signing flags may be set in SMB2 request */
391 if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
392 temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
393 else if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
394 temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
395 else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
396 temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
397
398 req->SecurityMode = temp;
399 req->Capabilities = 0;
400 req->Channel = 0; /* MBZ */
401
402 iov[0].iov_base = (char *)req;
403 /* 4 for rfc1002 length field and 1 for pad */
404 iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
405 if (phase == NtLmNegotiate) {
406 ntlmssp_blob = kmalloc(sizeof(struct _NEGOTIATE_MESSAGE),
407 GFP_KERNEL);
408 if (ntlmssp_blob == NULL) {
409 rc = -ENOMEM;
410 goto ssetup_exit;
411 }
412 build_ntlmssp_negotiate_blob(ntlmssp_blob, ses);
413 if (use_spnego) {
414 /* blob_length = build_spnego_ntlmssp_blob(
415 &security_blob,
416 sizeof(struct _NEGOTIATE_MESSAGE),
417 ntlmssp_blob); */
418 /* BB eventually need to add this */
419 cERROR(1, "spnego not supported for SMB2 yet");
420 rc = -EOPNOTSUPP;
421 kfree(ntlmssp_blob);
422 goto ssetup_exit;
423 } else {
424 blob_length = sizeof(struct _NEGOTIATE_MESSAGE);
425 /* with raw NTLMSSP we don't encapsulate in SPNEGO */
426 security_blob = ntlmssp_blob;
427 }
428 } else if (phase == NtLmAuthenticate) {
429 req->hdr.SessionId = ses->Suid;
430 ntlmssp_blob = kzalloc(sizeof(struct _NEGOTIATE_MESSAGE) + 500,
431 GFP_KERNEL);
432 if (ntlmssp_blob == NULL) {
433 cERROR(1, "failed to malloc ntlmssp blob");
434 rc = -ENOMEM;
435 goto ssetup_exit;
436 }
437 rc = build_ntlmssp_auth_blob(ntlmssp_blob, &blob_length, ses,
438 nls_cp);
439 if (rc) {
440 cFYI(1, "build_ntlmssp_auth_blob failed %d", rc);
441 goto ssetup_exit; /* BB double check error handling */
442 }
443 if (use_spnego) {
444 /* blob_length = build_spnego_ntlmssp_blob(
445 &security_blob,
446 blob_length,
447 ntlmssp_blob); */
448 cERROR(1, "spnego not supported for SMB2 yet");
449 rc = -EOPNOTSUPP;
450 kfree(ntlmssp_blob);
451 goto ssetup_exit;
452 } else {
453 security_blob = ntlmssp_blob;
454 }
455 } else {
456 cERROR(1, "illegal ntlmssp phase");
457 rc = -EIO;
458 goto ssetup_exit;
459 }
460
461 /* Testing shows that buffer offset must be at location of Buffer[0] */
462 req->SecurityBufferOffset =
463 cpu_to_le16(sizeof(struct smb2_sess_setup_req) -
464 1 /* pad */ - 4 /* rfc1001 len */);
465 req->SecurityBufferLength = cpu_to_le16(blob_length);
466 iov[1].iov_base = security_blob;
467 iov[1].iov_len = blob_length;
468
469 inc_rfc1001_len(req, blob_length - 1 /* pad */);
470
471 /* BB add code to build os and lm fields */
472
473 rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, CIFS_LOG_ERROR);
474
475 kfree(security_blob);
476 rsp = (struct smb2_sess_setup_rsp *)iov[0].iov_base;
477 if (rsp->hdr.Status == STATUS_MORE_PROCESSING_REQUIRED) {
478 if (phase != NtLmNegotiate) {
479 cERROR(1, "Unexpected more processing error");
480 goto ssetup_exit;
481 }
482 if (offsetof(struct smb2_sess_setup_rsp, Buffer) - 4 !=
483 le16_to_cpu(rsp->SecurityBufferOffset)) {
484 cERROR(1, "Invalid security buffer offset %d",
485 le16_to_cpu(rsp->SecurityBufferOffset));
486 rc = -EIO;
487 goto ssetup_exit;
488 }
489
490 /* NTLMSSP Negotiate sent now processing challenge (response) */
491 phase = NtLmChallenge; /* process ntlmssp challenge */
492 rc = 0; /* MORE_PROCESSING is not an error here but expected */
493 ses->Suid = rsp->hdr.SessionId;
494 rc = decode_ntlmssp_challenge(rsp->Buffer,
495 le16_to_cpu(rsp->SecurityBufferLength), ses);
496 }
497
498 /*
499 * BB eventually add code for SPNEGO decoding of NtlmChallenge blob,
500 * but at least the raw NTLMSSP case works.
501 */
502 /*
503 * No tcon so can't do
504 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
505 */
506 if (rc != 0)
507 goto ssetup_exit;
508
509 if (rsp == NULL) {
510 rc = -EIO;
511 goto ssetup_exit;
512 }
513
514 ses->session_flags = le16_to_cpu(rsp->SessionFlags);
515ssetup_exit:
516 free_rsp_buf(resp_buftype, rsp);
517
518 /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
519 if ((phase == NtLmChallenge) && (rc == 0))
520 goto ssetup_ntlmssp_authenticate;
521 return rc;
522}
523
524int
525SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
526{
527 struct smb2_logoff_req *req; /* response is also trivial struct */
528 int rc = 0;
529 struct TCP_Server_Info *server;
530
531 cFYI(1, "disconnect session %p", ses);
532
533 if (ses && (ses->server))
534 server = ses->server;
535 else
536 return -EIO;
537
538 rc = small_smb2_init(SMB2_LOGOFF, NULL, (void **) &req);
539 if (rc)
540 return rc;
541
542 /* since no tcon, smb2_init can not do this, so do here */
543 req->hdr.SessionId = ses->Suid;
544
545 rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
546 /*
547 * No tcon so can't do
548 * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]);
549 */
550 return rc;
551}