Print this page
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
SUP-513 Unable to join AD domain (fix lint)
SUP-513 Unable to join AD domain (with NtlmMinSeverSec set in the registry)
 Implement "Extended Session Security" and "Key Exchange" in NTLMSSP
re #12739 rb4271 AD join with lmauth_level=2 fails
re #12394 rb3934 Even NULL sessions should use SPNEGO


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * NT Lan Manager Security Support Provider (NTLMSSP)
  29  *
  30  * Based on information from the "Davenport NTLM" page:
  31  * http://davenport.sourceforge.net/ntlm.html
  32  */
  33 
  34 
  35 #include <errno.h>
  36 #include <stdio.h>
  37 #include <stddef.h>
  38 #include <stdlib.h>
  39 #include <unistd.h>
  40 #include <strings.h>
  41 #include <netdb.h>
  42 #include <libintl.h>
  43 #include <xti.h>
  44 #include <assert.h>


  50 #include <sys/fcntl.h>
  51 
  52 #include <netinet/in.h>
  53 #include <netinet/tcp.h>
  54 #include <arpa/inet.h>
  55 
  56 #include <netsmb/smb.h>
  57 #include <netsmb/smb_lib.h>
  58 #include <netsmb/mchain.h>
  59 
  60 #include "private.h"
  61 #include "charsets.h"
  62 #include "smb_crypt.h"
  63 #include "spnego.h"
  64 #include "derparse.h"
  65 #include "ssp.h"
  66 #include "ntlm.h"
  67 #include "ntlmssp.h"
  68 
  69 /* A shorter alias for a crazy long name from [MS-NLMP] */
  70 #define NTLMSSP_NEGOTIATE_NTLM2 \
  71         NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
  72 
  73 typedef struct ntlmssp_state {
  74         uint32_t ss_flags;
  75         char *ss_target_name;   /* Primary domain or server name */
  76         struct mbuf *ss_target_info;

  77         uchar_t ss_kxkey[NTLM_HASH_SZ];
  78 } ntlmssp_state_t;
  79 
  80 /*
  81  * So called "security buffer".
  82  * A lot like an RPC string.
  83  */
  84 struct sec_buf {
  85         uint16_t sb_length;
  86         uint16_t sb_maxlen;
  87         uint32_t sb_offset;
  88 };
  89 #define ID_SZ 8
  90 static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
  91 
  92 static int
  93 ntlm_rand_ssn_key(struct smb_ctx *ctx,
  94         ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
  95 
  96 /*
  97  * Get a "security buffer" (header part)
  98  */
  99 static int
 100 md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
 101 {
 102         int err;
 103 
 104         (void) md_get_uint16le(mbp, &sb->sb_length);
 105         (void) md_get_uint16le(mbp, &sb->sb_maxlen);
 106         err = md_get_uint32le(mbp, &sb->sb_offset);
 107 
 108         return (err);
 109 }
 110 
 111 /*
 112  * Get a "security buffer" (data part), where
 113  * the data is delivered as an mbuf.
 114  */


 232         struct smb_ctx *ctx = sp->smb_ctx;
 233         ntlmssp_state_t *ssp_st = sp->sp_private;
 234 
 235         if ((err = mb_init(&mb2)) != 0)
 236                 return (err);
 237         mb2.mb_count = sizeof (hdr);
 238 
 239         /*
 240          * The initial negotiation flags represent the union of all
 241          * options we support.  The server selects from these.
 242          * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
 243          */
 244         ssp_st->ss_flags =
 245             NTLMSSP_NEGOTIATE_UNICODE |
 246             NTLMSSP_NEGOTIATE_OEM |
 247             NTLMSSP_REQUEST_TARGET |
 248             NTLMSSP_NEGOTIATE_SIGN |
 249             NTLMSSP_NEGOTIATE_SEAL |
 250             /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
 251             NTLMSSP_NEGOTIATE_NTLM |
 252             /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN (set below) */
 253             NTLMSSP_NEGOTIATE_NTLM2 |
 254             NTLMSSP_NEGOTIATE_128 |
 255             NTLMSSP_NEGOTIATE_KEY_EXCH |
 256             NTLMSSP_NEGOTIATE_56;
 257 
 258         if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
 259                 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
 260                 ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
 261         }
 262 
 263         bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
 264         hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
 265         hdr.h_flags = ssp_st->ss_flags;
 266 
 267         /*
 268          * We could put the client domain, client name strings
 269          * here, (always in OEM format, upper-case), and set
 270          * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
 271          * leaves these NULL so let's do the same.
 272          */
 273         (void) mb_put_sb_string(&mb2, &hdr.h_cldom, NULL, 0);
 274         (void) mb_put_sb_string(&mb2, &hdr.h_wksta, NULL, 0);
 275 
 276         /*
 277          * Marshal the header (in LE order)
 278          * then concatenate the 2nd part.
 279          */
 280         (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
 281         (void) mb_put_uint32le(out_mb, hdr.h_type);


 430         /*
 431          * Fill in the NTLMSSP header, etc.
 432          */
 433         if ((err = mb_init(&mb2)) != 0)
 434                 goto out;
 435         mb2.mb_count = sizeof (hdr);
 436         uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
 437 
 438         bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
 439         hdr.h_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
 440         hdr.h_flags = ssp_st->ss_flags;
 441 
 442         /*
 443          * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
 444          * and compute the session key, etc.
 445          */
 446         if (ctx->ct_authflags & SMB_AT_ANON) {
 447                 /*
 448                  * We're setting up a NULL session, meaning
 449                  * the lm_mbc, nt_mbc parts remain empty.
 450                  * Let's add the "anon" flag (hint).
 451                  * As there is no session key, disable the
 452                  * fancy session key stuff.



 453                  */
 454                 hdr.h_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
 455                 ssp_st->ss_flags &= ~(
 456                     NTLMSSP_NEGOTIATE_NTLM2 |
 457                     NTLMSSP_NEGOTIATE_KEY_EXCH);
 458                 err = 0;



 459         } else if (ctx->ct_authflags & SMB_AT_NTLM2) {
 460                 /*
 461                  * Doing NTLMv2/LMv2
 462                  */
 463                 err = ntlm_build_target_info(ctx,
 464                     ssp_st->ss_target_info, &ti_mbc);
 465                 if (err)
 466                         goto out;
 467                 err = ntlm_put_v2_responses(ctx, &ti_mbc,
 468                     &lm_mbc, &nt_mbc);
 469                 if (err)
 470                         goto out;
 471                 /* The "key exg. key" is the session base key */
 472                 memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
 473 
 474         } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_NTLM2) {
 475                 /*
 476                  * Doing NTLM ("v1x") which is NTLM with
 477                  * "Extended Session Security"
 478                  */
 479                 err = ntlm_put_v1x_responses(ctx,
 480                     &lm_mbc, &nt_mbc);
 481                 if (err)
 482                         goto out;
 483                 /* Compute the "Key exchange key". */
 484                 ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_kxkey);




 485         } else {
 486                 /*
 487                  * Doing plain old NTLM (and LM if enabled)
 488                  */
 489                 err = ntlm_put_v1_responses(ctx,
 490                     &lm_mbc, &nt_mbc);
 491                 if (err)
 492                         goto out;
 493                 /* The "key exg. key" is the session base key */
 494                 memcpy(ssp_st->ss_kxkey, ctx->ct_ssn_key, NTLM_HASH_SZ);
 495         }
 496 
 497         /*
 498          * Compute the "Exported Session Key" and (possibly)
 499          * the "Encrypted Random Sesion Key".
 500          * [MS-NLMP 3.1.5.1.2]
 501          */
 502         if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
 503                 err = ntlm_rand_ssn_key(ctx, ssp_st, &ek_mbc);
 504                 if (err)
 505                         goto out;
 506         } else {
 507                 /* ExportedSessionKey is the KeyExchangeKey */
 508                 memcpy(ctx->ct_ssn_key, ssp_st->ss_kxkey, NTLM_HASH_SZ);
 509                 /* EncryptedRandomSessionKey remains NULL */
 510         }
 511 
 512         err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
 513         lm_mbc.mb_top = NULL; /* consumed */
 514         if (err)
 515                 goto out;
 516         err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
 517         nt_mbc.mb_top = NULL; /* consumed */
 518         if (err)
 519                 goto out;
 520 
 521         /*
 522          * Put the "target" (domain), user, workstation
 523          */
 524         err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc);
 525         if (err)
 526                 goto out;
 527         err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc);
 528         if (err)


 573 out:
 574         mb_done(&mb2);
 575         mb_done(&lm_mbc);
 576         mb_done(&nt_mbc);
 577         mb_done(&ti_mbc);
 578         mb_done(&ek_mbc);
 579 
 580         return (err);
 581 }
 582 
 583 /*
 584  * Helper for ntlmssp_put_type3 when doing key exchange.
 585  *
 586  * "ExportedSessionKey" is what we give to the "application"
 587  * layer, which in here means the MAC key for SMB signing.
 588  * With "key exchange", we replace the ExportedSessionKey
 589  * with random data and send that (encrypted) to the peer.
 590  */
 591 static int
 592 ntlm_rand_ssn_key(
 593         struct smb_ctx *ctx,
 594         ntlmssp_state_t *ssp_st,
 595         struct mbdata *ek_mbp)
 596 {
 597 
 598         uchar_t *encr_ssn_key;
 599         int err;
 600 
 601         if ((err = mb_init(ek_mbp)) != 0)
 602                 return (err);
 603         encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
 604 
 605         /* Set "ExportedSessionKey to NONCE(16) */
 606         (void) smb_get_urandom(ctx->ct_ssn_key, NTLM_HASH_SZ);
 607 
 608         /* Set "EncryptedRandomSessionKey" to RC4(...) */
 609         err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
 610             ssp_st->ss_kxkey, NTLM_HASH_SZ,
 611             ctx->ct_ssn_key, NTLM_HASH_SZ);
 612 
 613         return (err);
 614 }
 615 
 616 /*
 617  * ntlmssp_final
 618  *
 619  * Called after successful authentication.
 620  * Setup the MAC key for signing.
 621  */
 622 int
 623 ntlmssp_final(struct ssp_ctx *sp)
 624 {
 625         struct smb_ctx *ctx = sp->smb_ctx;

 626         int err = 0;
 627 
 628         /*
 629          * MAC_key is just the session key, but
 630          * Only on the first successful auth.
 631          */
 632         if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
 633             (ctx->ct_mackey == NULL)) {
 634                 ctx->ct_mackeylen = NTLM_HASH_SZ;
 635                 ctx->ct_mackey = malloc(ctx->ct_mackeylen);
 636                 if (ctx->ct_mackey == NULL) {
 637                         ctx->ct_mackeylen = 0;
 638                         err = ENOMEM;
 639                         goto out;
 640                 }
 641                 memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
 642                 /*
 643                  * Apparently, the server used seq. no. zero
 644                  * for our previous message, so next is two.
 645                  */
 646                 ctx->ct_mac_seqno = 2;
 647         }
 648 
 649 out:
 650         return (err);
 651 }
 652 
 653 /*
 654  * ntlmssp_next_token
 655  *
 656  * See ssp.c: ssp_ctx_next_token
 657  */
 658 int
 659 ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
 660         struct mbdata *out_mb)
 661 {
 662         int err;
 663 
 664         if (out_mb == NULL) {
 665                 /* final call on successful auth. */
 666                 err = ntlmssp_final(sp);
 667                 goto out;


 711         ntlmssp_state_t *ssp_st;
 712 
 713         ssp_st = sp->sp_private;
 714         if (ssp_st != NULL) {
 715                 sp->sp_private = NULL;
 716                 free(ssp_st->ss_target_name);
 717                 m_freem(ssp_st->ss_target_info);
 718                 free(ssp_st);
 719         }
 720 }
 721 
 722 /*
 723  * ntlmssp_init_clnt
 724  *
 725  * Initialize a new NTLMSSP client context.
 726  */
 727 int
 728 ntlmssp_init_client(struct ssp_ctx *sp)
 729 {
 730         ntlmssp_state_t *ssp_st;

 731 
 732         if ((sp->smb_ctx->ct_authflags &
 733             (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
 734                 DPRINT("No NTLM authflags");
 735                 return (EINVAL);
 736         }
 737 



 738         ssp_st = calloc(1, sizeof (*ssp_st));
 739         if (ssp_st == NULL)
 740                 return (ENOMEM);
 741 
 742         sp->sp_nexttok = ntlmssp_next_token;
 743         sp->sp_destroy = ntlmssp_destroy;
 744         sp->sp_private = ssp_st;
 745 
 746         return (0);
 747 }


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * NT Lan Manager Security Support Provider (NTLMSSP)
  29  *
  30  * Based on information from the "Davenport NTLM" page:
  31  * http://davenport.sourceforge.net/ntlm.html
  32  */
  33 
  34 
  35 #include <errno.h>
  36 #include <stdio.h>
  37 #include <stddef.h>
  38 #include <stdlib.h>
  39 #include <unistd.h>
  40 #include <strings.h>
  41 #include <netdb.h>
  42 #include <libintl.h>
  43 #include <xti.h>
  44 #include <assert.h>


  50 #include <sys/fcntl.h>
  51 
  52 #include <netinet/in.h>
  53 #include <netinet/tcp.h>
  54 #include <arpa/inet.h>
  55 
  56 #include <netsmb/smb.h>
  57 #include <netsmb/smb_lib.h>
  58 #include <netsmb/mchain.h>
  59 
  60 #include "private.h"
  61 #include "charsets.h"
  62 #include "smb_crypt.h"
  63 #include "spnego.h"
  64 #include "derparse.h"
  65 #include "ssp.h"
  66 #include "ntlm.h"
  67 #include "ntlmssp.h"
  68 
  69 /* A shorter alias for a crazy long name from [MS-NLMP] */
  70 #define NTLMSSP_NEGOTIATE_ESS \
  71         NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
  72 
  73 typedef struct ntlmssp_state {
  74         uint32_t ss_flags;
  75         char *ss_target_name;   /* Primary domain or server name */
  76         struct mbuf *ss_target_info;
  77         uchar_t ss_ssnkey[NTLM_HASH_SZ];
  78         uchar_t ss_kxkey[NTLM_HASH_SZ];
  79 } ntlmssp_state_t;
  80 
  81 /*
  82  * So called "security buffer".
  83  * A lot like an RPC string.
  84  */
  85 struct sec_buf {
  86         uint16_t sb_length;
  87         uint16_t sb_maxlen;
  88         uint32_t sb_offset;
  89 };
  90 #define ID_SZ 8
  91 static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
  92 
  93 static int
  94 ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);

  95 
  96 /*
  97  * Get a "security buffer" (header part)
  98  */
  99 static int
 100 md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
 101 {
 102         int err;
 103 
 104         (void) md_get_uint16le(mbp, &sb->sb_length);
 105         (void) md_get_uint16le(mbp, &sb->sb_maxlen);
 106         err = md_get_uint32le(mbp, &sb->sb_offset);
 107 
 108         return (err);
 109 }
 110 
 111 /*
 112  * Get a "security buffer" (data part), where
 113  * the data is delivered as an mbuf.
 114  */


 232         struct smb_ctx *ctx = sp->smb_ctx;
 233         ntlmssp_state_t *ssp_st = sp->sp_private;
 234 
 235         if ((err = mb_init(&mb2)) != 0)
 236                 return (err);
 237         mb2.mb_count = sizeof (hdr);
 238 
 239         /*
 240          * The initial negotiation flags represent the union of all
 241          * options we support.  The server selects from these.
 242          * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
 243          */
 244         ssp_st->ss_flags =
 245             NTLMSSP_NEGOTIATE_UNICODE |
 246             NTLMSSP_NEGOTIATE_OEM |
 247             NTLMSSP_REQUEST_TARGET |
 248             NTLMSSP_NEGOTIATE_SIGN |
 249             NTLMSSP_NEGOTIATE_SEAL |
 250             /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
 251             NTLMSSP_NEGOTIATE_NTLM |
 252             NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
 253             NTLMSSP_NEGOTIATE_ESS |
 254             NTLMSSP_NEGOTIATE_128 |
 255             NTLMSSP_NEGOTIATE_KEY_EXCH |
 256             NTLMSSP_NEGOTIATE_56;
 257 
 258         if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
 259                 ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;


 260 
 261         bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
 262         hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
 263         hdr.h_flags = ssp_st->ss_flags;
 264 
 265         /*
 266          * We could put the client domain, client name strings
 267          * here, (always in OEM format, upper-case), and set
 268          * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
 269          * leaves these NULL so let's do the same.
 270          */
 271         (void) mb_put_sb_string(&mb2, &hdr.h_cldom, NULL, 0);
 272         (void) mb_put_sb_string(&mb2, &hdr.h_wksta, NULL, 0);
 273 
 274         /*
 275          * Marshal the header (in LE order)
 276          * then concatenate the 2nd part.
 277          */
 278         (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
 279         (void) mb_put_uint32le(out_mb, hdr.h_type);


 428         /*
 429          * Fill in the NTLMSSP header, etc.
 430          */
 431         if ((err = mb_init(&mb2)) != 0)
 432                 goto out;
 433         mb2.mb_count = sizeof (hdr);
 434         uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
 435 
 436         bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
 437         hdr.h_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
 438         hdr.h_flags = ssp_st->ss_flags;
 439 
 440         /*
 441          * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
 442          * and compute the session key, etc.
 443          */
 444         if (ctx->ct_authflags & SMB_AT_ANON) {
 445                 /*
 446                  * We're setting up a NULL session, meaning
 447                  * the lm_mbc, nt_mbc parts remain empty.
 448                  * Let's add the "anon" flag (hint), and
 449                  * as we have no OWF hashes, we can't use
 450                  * "extended session security" (_ESS).
 451                  * The SessionBaseKey is all zeros, so
 452                  * the KeyExchangeKey is too.  Otherwise
 453                  * this is like NTLMv2/LMv2
 454                  */
 455                 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
 456                 ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
 457                 hdr.h_flags = ssp_st->ss_flags;

 458                 err = 0;
 459                 /* KeyExchangeKey = SessionBaseKey = (zeros) */
 460                 memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
 461                 memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
 462         } else if (ctx->ct_authflags & SMB_AT_NTLM2) {
 463                 /*
 464                  * Doing NTLMv2/LMv2
 465                  */
 466                 err = ntlm_build_target_info(ctx,
 467                     ssp_st->ss_target_info, &ti_mbc);
 468                 if (err)
 469                         goto out;
 470                 err = ntlm_put_v2_responses(ctx, &ti_mbc,
 471                     &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
 472                 if (err)
 473                         goto out;
 474                 /* KeyExchangeKey = SessionBaseKey (v2) */
 475                 memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
 476         } else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {

 477                 /*
 478                  * Doing NTLM ("v1x") which is NTLM with
 479                  * "Extended Session Security"
 480                  */
 481                 err = ntlm_put_v1x_responses(ctx,
 482                     &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
 483                 if (err)
 484                         goto out;
 485                 /*
 486                  * "v1x computes the KeyExchangeKey from both the
 487                  * server and client nonce and (v1) SessionBaseKey.
 488                  */
 489                 ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
 490                     ssp_st->ss_kxkey);
 491         } else {
 492                 /*
 493                  * Doing plain old NTLM (and LM if enabled)
 494                  */
 495                 err = ntlm_put_v1_responses(ctx,
 496                     &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
 497                 if (err)
 498                         goto out;
 499                 /* KeyExchangeKey = SessionBaseKey (v1) */
 500                 memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
 501         }
 502 
 503         /*
 504          * Compute the "ExportedSessionKey" and (possibly) the
 505          * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]

 506          */
 507         if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
 508                 err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
 509                 if (err)
 510                         goto out;
 511         } else {
 512                 /* ExportedSessionKey is the KeyExchangeKey */
 513                 memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
 514                 /* EncryptedRandomSessionKey remains NULL */
 515         }
 516 
 517         err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
 518         lm_mbc.mb_top = NULL; /* consumed */
 519         if (err)
 520                 goto out;
 521         err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
 522         nt_mbc.mb_top = NULL; /* consumed */
 523         if (err)
 524                 goto out;
 525 
 526         /*
 527          * Put the "target" (domain), user, workstation
 528          */
 529         err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc);
 530         if (err)
 531                 goto out;
 532         err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc);
 533         if (err)


 578 out:
 579         mb_done(&mb2);
 580         mb_done(&lm_mbc);
 581         mb_done(&nt_mbc);
 582         mb_done(&ti_mbc);
 583         mb_done(&ek_mbc);
 584 
 585         return (err);
 586 }
 587 
 588 /*
 589  * Helper for ntlmssp_put_type3 when doing key exchange.
 590  *
 591  * "ExportedSessionKey" is what we give to the "application"
 592  * layer, which in here means the MAC key for SMB signing.
 593  * With "key exchange", we replace the ExportedSessionKey
 594  * with random data and send that (encrypted) to the peer.
 595  */
 596 static int
 597 ntlm_rand_ssn_key(

 598         ntlmssp_state_t *ssp_st,
 599         struct mbdata *ek_mbp)
 600 {
 601 
 602         uchar_t *encr_ssn_key;
 603         int err;
 604 
 605         if ((err = mb_init(ek_mbp)) != 0)
 606                 return (err);
 607         encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
 608 
 609         /* Set "ExportedSessionKey to NONCE(16) */
 610         (void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
 611 
 612         /* Set "EncryptedRandomSessionKey" to RC4(...) */
 613         err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
 614             ssp_st->ss_kxkey, NTLM_HASH_SZ,
 615             ssp_st->ss_ssnkey, NTLM_HASH_SZ);
 616 
 617         return (err);
 618 }
 619 
 620 /*
 621  * ntlmssp_final
 622  *
 623  * Called after successful authentication.
 624  * Save the session key.
 625  */
 626 int
 627 ntlmssp_final(struct ssp_ctx *sp)
 628 {
 629         struct smb_ctx *ctx = sp->smb_ctx;
 630         ntlmssp_state_t *ssp_st = sp->sp_private;
 631         int err = 0;
 632 
 633         /*
 634          * Update/save the session key.

 635          */
 636         if (ctx->ct_ssnkey_buf != NULL) {
 637                 free(ctx->ct_ssnkey_buf);
 638                 ctx->ct_ssnkey_buf = NULL;
 639         }
 640         ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
 641         if (ctx->ct_ssnkey_buf == NULL) {
 642                 err = ENOMEM;
 643                 goto out;
 644         }
 645         ctx->ct_ssnkey_len = NTLM_HASH_SZ;
 646         memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);





 647 
 648 out:
 649         return (err);
 650 }
 651 
 652 /*
 653  * ntlmssp_next_token
 654  *
 655  * See ssp.c: ssp_ctx_next_token
 656  */
 657 int
 658 ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
 659         struct mbdata *out_mb)
 660 {
 661         int err;
 662 
 663         if (out_mb == NULL) {
 664                 /* final call on successful auth. */
 665                 err = ntlmssp_final(sp);
 666                 goto out;


 710         ntlmssp_state_t *ssp_st;
 711 
 712         ssp_st = sp->sp_private;
 713         if (ssp_st != NULL) {
 714                 sp->sp_private = NULL;
 715                 free(ssp_st->ss_target_name);
 716                 m_freem(ssp_st->ss_target_info);
 717                 free(ssp_st);
 718         }
 719 }
 720 
 721 /*
 722  * ntlmssp_init_clnt
 723  *
 724  * Initialize a new NTLMSSP client context.
 725  */
 726 int
 727 ntlmssp_init_client(struct ssp_ctx *sp)
 728 {
 729         ntlmssp_state_t *ssp_st;
 730         smb_ctx_t *ctx = sp->smb_ctx;
 731 
 732         if ((ctx->ct_authflags &
 733             (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
 734                 DPRINT("No NTLM authflags");
 735                 return (EINVAL);
 736         }
 737 
 738         /* Get the client nonce. */
 739         (void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
 740 
 741         ssp_st = calloc(1, sizeof (*ssp_st));
 742         if (ssp_st == NULL)
 743                 return (ENOMEM);
 744 
 745         sp->sp_nexttok = ntlmssp_next_token;
 746         sp->sp_destroy = ntlmssp_destroy;
 747         sp->sp_private = ssp_st;
 748 
 749         return (0);
 750 }