1613a2f6bSGordon Ross /* 2613a2f6bSGordon Ross * CDDL HEADER START 3613a2f6bSGordon Ross * 4613a2f6bSGordon Ross * The contents of this file are subject to the terms of the 5613a2f6bSGordon Ross * Common Development and Distribution License (the "License"). 6613a2f6bSGordon Ross * You may not use this file except in compliance with the License. 7613a2f6bSGordon Ross * 8613a2f6bSGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9613a2f6bSGordon Ross * or http://www.opensolaris.org/os/licensing. 10613a2f6bSGordon Ross * See the License for the specific language governing permissions 11613a2f6bSGordon Ross * and limitations under the License. 12613a2f6bSGordon Ross * 13613a2f6bSGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14613a2f6bSGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15613a2f6bSGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16613a2f6bSGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17613a2f6bSGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18613a2f6bSGordon Ross * 19613a2f6bSGordon Ross * CDDL HEADER END 20613a2f6bSGordon Ross */ 21613a2f6bSGordon Ross 22613a2f6bSGordon Ross /* 23*15359501SGordon Ross * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24613a2f6bSGordon Ross */ 25613a2f6bSGordon Ross 26613a2f6bSGordon Ross /* 27613a2f6bSGordon Ross * NT Lan Manager Security Support Provider (NTLMSSP) 28613a2f6bSGordon Ross * 29613a2f6bSGordon Ross * Based on information from the "Davenport NTLM" page: 30613a2f6bSGordon Ross * http://davenport.sourceforge.net/ntlm.html 31613a2f6bSGordon Ross */ 32613a2f6bSGordon Ross 33613a2f6bSGordon Ross 34613a2f6bSGordon Ross #include <errno.h> 35613a2f6bSGordon Ross #include <stdio.h> 36613a2f6bSGordon Ross #include <stddef.h> 37613a2f6bSGordon Ross #include <stdlib.h> 38613a2f6bSGordon Ross #include <unistd.h> 39613a2f6bSGordon Ross #include <strings.h> 40613a2f6bSGordon Ross #include <netdb.h> 41613a2f6bSGordon Ross #include <libintl.h> 42613a2f6bSGordon Ross #include <xti.h> 43613a2f6bSGordon Ross #include <assert.h> 44613a2f6bSGordon Ross 45613a2f6bSGordon Ross #include <sys/types.h> 46613a2f6bSGordon Ross #include <sys/time.h> 47613a2f6bSGordon Ross #include <sys/byteorder.h> 48613a2f6bSGordon Ross #include <sys/socket.h> 49613a2f6bSGordon Ross #include <sys/fcntl.h> 50613a2f6bSGordon Ross 51613a2f6bSGordon Ross #include <netinet/in.h> 52613a2f6bSGordon Ross #include <netinet/tcp.h> 53613a2f6bSGordon Ross #include <arpa/inet.h> 54613a2f6bSGordon Ross 55613a2f6bSGordon Ross #include <netsmb/smb.h> 56613a2f6bSGordon Ross #include <netsmb/smb_lib.h> 57613a2f6bSGordon Ross #include <netsmb/mchain.h> 58613a2f6bSGordon Ross 59613a2f6bSGordon Ross #include "private.h" 60613a2f6bSGordon Ross #include "charsets.h" 61613a2f6bSGordon Ross #include "spnego.h" 62613a2f6bSGordon Ross #include "derparse.h" 63613a2f6bSGordon Ross #include "ssp.h" 64613a2f6bSGordon Ross #include "ntlm.h" 65613a2f6bSGordon Ross #include "ntlmssp.h" 66613a2f6bSGordon Ross 67613a2f6bSGordon Ross typedef struct ntlmssp_state { 68613a2f6bSGordon Ross uint32_t ss_flags; 69613a2f6bSGordon Ross char *ss_target_name; 70613a2f6bSGordon Ross struct mbuf *ss_target_info; 71613a2f6bSGordon Ross } ntlmssp_state_t; 72613a2f6bSGordon Ross 73613a2f6bSGordon Ross /* 74613a2f6bSGordon Ross * So called "security buffer". 75613a2f6bSGordon Ross * A lot like an RPC string. 76613a2f6bSGordon Ross */ 77613a2f6bSGordon Ross struct sec_buf { 78613a2f6bSGordon Ross uint16_t sb_length; 79613a2f6bSGordon Ross uint16_t sb_maxlen; 80613a2f6bSGordon Ross uint32_t sb_offset; 81613a2f6bSGordon Ross }; 82613a2f6bSGordon Ross #define ID_SZ 8 83613a2f6bSGordon Ross static const char ntlmssp_id[ID_SZ] = "NTLMSSP"; 84613a2f6bSGordon Ross 85613a2f6bSGordon Ross /* 86613a2f6bSGordon Ross * Get a "security buffer" (header part) 87613a2f6bSGordon Ross */ 88613a2f6bSGordon Ross static int 8902d09e03SGordon Ross md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) 90613a2f6bSGordon Ross { 91613a2f6bSGordon Ross int err; 92613a2f6bSGordon Ross 9302d09e03SGordon Ross (void) md_get_uint16le(mbp, &sb->sb_length); 9402d09e03SGordon Ross (void) md_get_uint16le(mbp, &sb->sb_maxlen); 9502d09e03SGordon Ross err = md_get_uint32le(mbp, &sb->sb_offset); 96613a2f6bSGordon Ross 97613a2f6bSGordon Ross return (err); 98613a2f6bSGordon Ross } 99613a2f6bSGordon Ross 100613a2f6bSGordon Ross /* 101613a2f6bSGordon Ross * Get a "security buffer" (data part), where 102613a2f6bSGordon Ross * the data is delivered as an mbuf. 103613a2f6bSGordon Ross */ 104613a2f6bSGordon Ross static int 10502d09e03SGordon Ross md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp) 106613a2f6bSGordon Ross { 107613a2f6bSGordon Ross struct mbdata tmp_mb; 108613a2f6bSGordon Ross int err; 109613a2f6bSGordon Ross 110613a2f6bSGordon Ross /* 111613a2f6bSGordon Ross * Setup tmp_mb to point to the start of the header. 112613a2f6bSGordon Ross * This is a dup ref - do NOT free it. 113613a2f6bSGordon Ross */ 114613a2f6bSGordon Ross mb_initm(&tmp_mb, mbp->mb_top); 115613a2f6bSGordon Ross 116613a2f6bSGordon Ross /* Skip data up to the offset. */ 11702d09e03SGordon Ross err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM); 118613a2f6bSGordon Ross if (err) 119613a2f6bSGordon Ross return (err); 120613a2f6bSGordon Ross 121613a2f6bSGordon Ross /* Get the data (as an mbuf). */ 12202d09e03SGordon Ross err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp); 123613a2f6bSGordon Ross 124613a2f6bSGordon Ross return (err); 125613a2f6bSGordon Ross } 126613a2f6bSGordon Ross 127613a2f6bSGordon Ross /* 128613a2f6bSGordon Ross * Put a "security buffer" (header part) 129613a2f6bSGordon Ross */ 130613a2f6bSGordon Ross static int 131613a2f6bSGordon Ross mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) 132613a2f6bSGordon Ross { 133613a2f6bSGordon Ross int err; 134613a2f6bSGordon Ross 135613a2f6bSGordon Ross (void) mb_put_uint16le(mbp, sb->sb_length); 136613a2f6bSGordon Ross (void) mb_put_uint16le(mbp, sb->sb_maxlen); 137613a2f6bSGordon Ross err = mb_put_uint32le(mbp, sb->sb_offset); 138613a2f6bSGordon Ross 139613a2f6bSGordon Ross return (err); 140613a2f6bSGordon Ross } 141613a2f6bSGordon Ross 142613a2f6bSGordon Ross /* 143613a2f6bSGordon Ross * Put a "security buffer" (data part), where 144613a2f6bSGordon Ross * the data is an mbuf. Note: consumes m. 145613a2f6bSGordon Ross */ 146613a2f6bSGordon Ross static int 147613a2f6bSGordon Ross mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m) 148613a2f6bSGordon Ross { 149613a2f6bSGordon Ross int cnt0, err; 150613a2f6bSGordon Ross 151613a2f6bSGordon Ross sb->sb_offset = cnt0 = mbp->mb_count; 152613a2f6bSGordon Ross err = mb_put_mbuf(mbp, m); 153613a2f6bSGordon Ross sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0; 154613a2f6bSGordon Ross 155613a2f6bSGordon Ross return (err); 156613a2f6bSGordon Ross } 157613a2f6bSGordon Ross 158613a2f6bSGordon Ross /* 159613a2f6bSGordon Ross * Put a "security buffer" (data part), where 160613a2f6bSGordon Ross * the data is a string (OEM or unicode). 161613a2f6bSGordon Ross * 162613a2f6bSGordon Ross * The string is NOT null terminated. 163613a2f6bSGordon Ross */ 164613a2f6bSGordon Ross static int 165613a2f6bSGordon Ross mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb, 166613a2f6bSGordon Ross const char *s, int unicode) 167613a2f6bSGordon Ross { 168613a2f6bSGordon Ross int err, trim; 169613a2f6bSGordon Ross struct mbdata tmp_mb; 170613a2f6bSGordon Ross 171613a2f6bSGordon Ross /* 172613a2f6bSGordon Ross * Put the string into a temp. mbuf, 173613a2f6bSGordon Ross * then chop off the null terminator 174613a2f6bSGordon Ross * before appending to caller's mbp. 175613a2f6bSGordon Ross */ 17602d09e03SGordon Ross err = mb_init(&tmp_mb); 177613a2f6bSGordon Ross if (err) 178613a2f6bSGordon Ross return (err); 17902d09e03SGordon Ross err = mb_put_string(&tmp_mb, s, unicode); 180613a2f6bSGordon Ross if (err) 181613a2f6bSGordon Ross return (err); 182613a2f6bSGordon Ross 183613a2f6bSGordon Ross trim = (unicode) ? 2 : 1; 184613a2f6bSGordon Ross if (tmp_mb.mb_cur->m_len < trim) 185613a2f6bSGordon Ross return (EFAULT); 186613a2f6bSGordon Ross tmp_mb.mb_cur->m_len -= trim; 187613a2f6bSGordon Ross 188613a2f6bSGordon Ross err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top); 189613a2f6bSGordon Ross /* 190613a2f6bSGordon Ross * Note: tmp_mb.mb_top is consumed, 191613a2f6bSGordon Ross * so do NOT free it (no mb_done) 192613a2f6bSGordon Ross */ 193613a2f6bSGordon Ross return (err); 194613a2f6bSGordon Ross } 195613a2f6bSGordon Ross 196613a2f6bSGordon Ross /* 197613a2f6bSGordon Ross * Build a Type 1 message 198613a2f6bSGordon Ross * 199613a2f6bSGordon Ross * This message has a header section containing offsets to 200613a2f6bSGordon Ross * data later in the message. We use the common trick of 201613a2f6bSGordon Ross * building it in two parts and then concatenatening. 202613a2f6bSGordon Ross */ 203613a2f6bSGordon Ross int 204613a2f6bSGordon Ross ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb) 205613a2f6bSGordon Ross { 206613a2f6bSGordon Ross struct type1hdr { 207613a2f6bSGordon Ross char h_id[ID_SZ]; 208613a2f6bSGordon Ross uint32_t h_type; 209613a2f6bSGordon Ross uint32_t h_flags; 210613a2f6bSGordon Ross struct sec_buf h_cldom; 211613a2f6bSGordon Ross struct sec_buf h_wksta; 212613a2f6bSGordon Ross } hdr; 213613a2f6bSGordon Ross struct mbdata mb2; /* 2nd part */ 214613a2f6bSGordon Ross int err; 215613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 216613a2f6bSGordon Ross ntlmssp_state_t *ssp_st = sp->sp_private; 217613a2f6bSGordon Ross char *ucdom = NULL; 218613a2f6bSGordon Ross char *ucwks = NULL; 219613a2f6bSGordon Ross 22002d09e03SGordon Ross if ((err = mb_init(&mb2)) != 0) 221613a2f6bSGordon Ross return (err); 222613a2f6bSGordon Ross mb2.mb_count = sizeof (hdr); 223613a2f6bSGordon Ross 224613a2f6bSGordon Ross /* 225613a2f6bSGordon Ross * Initialize the negotiation flags, and 226613a2f6bSGordon Ross * save what we sent. For reference: 227613a2f6bSGordon Ross * [MS-NLMP] spec. (also ntlmssp.h) 228613a2f6bSGordon Ross */ 229613a2f6bSGordon Ross ssp_st->ss_flags = 230613a2f6bSGordon Ross NTLMSSP_REQUEST_TARGET | 231613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_NTLM | 232613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_TARGET_INFO | 233613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_128 | 234613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_56; 235613a2f6bSGordon Ross 236613a2f6bSGordon Ross if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE) 237613a2f6bSGordon Ross ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE; 238613a2f6bSGordon Ross else 239613a2f6bSGordon Ross ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM; 240613a2f6bSGordon Ross 241613a2f6bSGordon Ross if (ctx->ct_vcflags & SMBV_WILL_SIGN) { 242613a2f6bSGordon Ross ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; 243613a2f6bSGordon Ross ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 244613a2f6bSGordon Ross } 245613a2f6bSGordon Ross 246613a2f6bSGordon Ross bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); 247613a2f6bSGordon Ross hdr.h_type = 1; /* Type 1 */ 248613a2f6bSGordon Ross hdr.h_flags = ssp_st->ss_flags; 249613a2f6bSGordon Ross 250613a2f6bSGordon Ross /* 251613a2f6bSGordon Ross * Put the client domain, client name strings. 252613a2f6bSGordon Ross * These are always in OEM format, upper-case. 253613a2f6bSGordon Ross */ 254613a2f6bSGordon Ross ucdom = utf8_str_toupper(ctx->ct_domain); 255613a2f6bSGordon Ross ucwks = utf8_str_toupper(ctx->ct_locname); 256613a2f6bSGordon Ross if (ucdom == NULL || ucwks == NULL) { 257613a2f6bSGordon Ross err = ENOMEM; 258613a2f6bSGordon Ross goto out; 259613a2f6bSGordon Ross } 260613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0); 261613a2f6bSGordon Ross if (err) 262613a2f6bSGordon Ross goto out; 263613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0); 264613a2f6bSGordon Ross if (err) 265613a2f6bSGordon Ross goto out; 266613a2f6bSGordon Ross 267613a2f6bSGordon Ross /* 268613a2f6bSGordon Ross * Marshal the header (in LE order) 269613a2f6bSGordon Ross * then concatenate the 2nd part. 270613a2f6bSGordon Ross */ 27102d09e03SGordon Ross (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 272613a2f6bSGordon Ross (void) mb_put_uint32le(out_mb, hdr.h_type); 273613a2f6bSGordon Ross (void) mb_put_uint32le(out_mb, hdr.h_flags); 274613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom); 275613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta); 276613a2f6bSGordon Ross 277613a2f6bSGordon Ross err = mb_put_mbuf(out_mb, mb2.mb_top); 278613a2f6bSGordon Ross 279613a2f6bSGordon Ross out: 280613a2f6bSGordon Ross free(ucdom); 281613a2f6bSGordon Ross free(ucwks); 282613a2f6bSGordon Ross 283613a2f6bSGordon Ross return (err); 284613a2f6bSGordon Ross } 285613a2f6bSGordon Ross 286613a2f6bSGordon Ross /* 287613a2f6bSGordon Ross * Parse a Type 2 message 288613a2f6bSGordon Ross */ 289613a2f6bSGordon Ross int 290613a2f6bSGordon Ross ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb) 291613a2f6bSGordon Ross { 292613a2f6bSGordon Ross struct type2hdr { 293613a2f6bSGordon Ross char h_id[ID_SZ]; 294613a2f6bSGordon Ross uint32_t h_type; 295613a2f6bSGordon Ross struct sec_buf h_target_name; 296613a2f6bSGordon Ross uint32_t h_flags; 297613a2f6bSGordon Ross uint8_t h_challenge[8]; 298613a2f6bSGordon Ross uint32_t h_context[2]; /* optional */ 299613a2f6bSGordon Ross struct sec_buf h_target_info; /* optional */ 300613a2f6bSGordon Ross } hdr; 301613a2f6bSGordon Ross struct mbdata top_mb, tmp_mb; 302613a2f6bSGordon Ross struct mbuf *m; 303613a2f6bSGordon Ross int err, uc; 304613a2f6bSGordon Ross int min_hdr_sz = offsetof(struct type2hdr, h_context); 305613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 306613a2f6bSGordon Ross ntlmssp_state_t *ssp_st = sp->sp_private; 307613a2f6bSGordon Ross char *buf = NULL; 308613a2f6bSGordon Ross 309613a2f6bSGordon Ross if (m_totlen(in_mb->mb_top) < min_hdr_sz) { 310613a2f6bSGordon Ross err = EBADRPC; 311613a2f6bSGordon Ross goto out; 312613a2f6bSGordon Ross } 313613a2f6bSGordon Ross 314613a2f6bSGordon Ross /* 315613a2f6bSGordon Ross * Save the mbdata pointers before we consume anything. 316613a2f6bSGordon Ross * Careful to NOT free this (would be dup. free) 317613a2f6bSGordon Ross * We use this below to find data based on offsets 318613a2f6bSGordon Ross * from the start of the header. 319613a2f6bSGordon Ross */ 320613a2f6bSGordon Ross top_mb = *in_mb; 321613a2f6bSGordon Ross 322613a2f6bSGordon Ross /* Parse the fixed size header stuff. */ 323613a2f6bSGordon Ross bzero(&hdr, sizeof (hdr)); 32402d09e03SGordon Ross (void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 32502d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_type); 326613a2f6bSGordon Ross if (hdr.h_type != 2) { 327613a2f6bSGordon Ross err = EPROTO; 328613a2f6bSGordon Ross goto out; 329613a2f6bSGordon Ross } 33002d09e03SGordon Ross (void) md_get_sb_hdr(in_mb, &hdr.h_target_name); 33102d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_flags); 33202d09e03SGordon Ross (void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM); 333613a2f6bSGordon Ross 334613a2f6bSGordon Ross /* 335613a2f6bSGordon Ross * Save flags, challenge for later. 336613a2f6bSGordon Ross */ 337613a2f6bSGordon Ross ssp_st->ss_flags = hdr.h_flags; 338613a2f6bSGordon Ross uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE; 339613a2f6bSGordon Ross bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ); 340613a2f6bSGordon Ross 341613a2f6bSGordon Ross /* 342613a2f6bSGordon Ross * Now find out if the optional parts are there. 343613a2f6bSGordon Ross */ 344613a2f6bSGordon Ross if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) && 345613a2f6bSGordon Ross (hdr.h_target_name.sb_offset >= sizeof (hdr))) { 34602d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_context[0]); 34702d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_context[1]); 34802d09e03SGordon Ross (void) md_get_sb_hdr(in_mb, &hdr.h_target_info); 349613a2f6bSGordon Ross } 350613a2f6bSGordon Ross 351613a2f6bSGordon Ross /* 352613a2f6bSGordon Ross * Get the target name string. First get a copy of 353613a2f6bSGordon Ross * the data from the offset/length indicated in the 354613a2f6bSGordon Ross * security buffer header; then parse the string. 355613a2f6bSGordon Ross */ 35602d09e03SGordon Ross err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m); 357613a2f6bSGordon Ross if (err) 358613a2f6bSGordon Ross goto out; 359613a2f6bSGordon Ross mb_initm(&tmp_mb, m); 36002d09e03SGordon Ross err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc); 361613a2f6bSGordon Ross mb_done(&tmp_mb); 362613a2f6bSGordon Ross 363613a2f6bSGordon Ross /* 364613a2f6bSGordon Ross * Get the target info blob, if present. 365613a2f6bSGordon Ross */ 366613a2f6bSGordon Ross if (hdr.h_target_info.sb_offset >= sizeof (hdr)) { 36702d09e03SGordon Ross err = md_get_sb_data(&top_mb, &hdr.h_target_info, 368613a2f6bSGordon Ross &ssp_st->ss_target_info); 369613a2f6bSGordon Ross } 370613a2f6bSGordon Ross 371613a2f6bSGordon Ross out: 372613a2f6bSGordon Ross if (buf != NULL) 373613a2f6bSGordon Ross free(buf); 374613a2f6bSGordon Ross 375613a2f6bSGordon Ross return (err); 376613a2f6bSGordon Ross } 377613a2f6bSGordon Ross 378613a2f6bSGordon Ross /* 379613a2f6bSGordon Ross * Build a Type 3 message 380613a2f6bSGordon Ross * 381613a2f6bSGordon Ross * This message has a header section containing offsets to 382613a2f6bSGordon Ross * data later in the message. We use the common trick of 383613a2f6bSGordon Ross * building it in two parts and then concatenatening. 384613a2f6bSGordon Ross */ 385613a2f6bSGordon Ross int 386613a2f6bSGordon Ross ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) 387613a2f6bSGordon Ross { 388613a2f6bSGordon Ross struct type3hdr { 389613a2f6bSGordon Ross char h_id[ID_SZ]; 390613a2f6bSGordon Ross uint32_t h_type; 391613a2f6bSGordon Ross struct sec_buf h_lm_resp; 392613a2f6bSGordon Ross struct sec_buf h_nt_resp; 393613a2f6bSGordon Ross struct sec_buf h_domain; 394613a2f6bSGordon Ross struct sec_buf h_user; 395613a2f6bSGordon Ross struct sec_buf h_wksta; 396*15359501SGordon Ross struct sec_buf h_ssn_key; 397*15359501SGordon Ross uint32_t h_flags; 398613a2f6bSGordon Ross } hdr; 399*15359501SGordon Ross struct mbdata lm_mbc; /* LM response */ 400*15359501SGordon Ross struct mbdata nt_mbc; /* NT response */ 401*15359501SGordon Ross struct mbdata ti_mbc; /* target info */ 402*15359501SGordon Ross struct mbdata mb2; /* payload */ 403613a2f6bSGordon Ross int err, uc; 404613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 405613a2f6bSGordon Ross ntlmssp_state_t *ssp_st = sp->sp_private; 406613a2f6bSGordon Ross 407*15359501SGordon Ross bzero(&hdr, sizeof (hdr)); 408613a2f6bSGordon Ross bzero(&lm_mbc, sizeof (lm_mbc)); 409613a2f6bSGordon Ross bzero(&nt_mbc, sizeof (nt_mbc)); 410613a2f6bSGordon Ross bzero(&ti_mbc, sizeof (ti_mbc)); 411613a2f6bSGordon Ross bzero(&mb2, sizeof (mb2)); 412613a2f6bSGordon Ross 413613a2f6bSGordon Ross /* 414*15359501SGordon Ross * Fill in the NTLMSSP header, etc. 415613a2f6bSGordon Ross */ 41602d09e03SGordon Ross if ((err = mb_init(&mb2)) != 0) 417613a2f6bSGordon Ross goto out; 418613a2f6bSGordon Ross mb2.mb_count = sizeof (hdr); 419613a2f6bSGordon Ross uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE; 420613a2f6bSGordon Ross 421613a2f6bSGordon Ross bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); 422613a2f6bSGordon Ross hdr.h_type = 3; /* Type 3 */ 423*15359501SGordon Ross hdr.h_flags = ssp_st->ss_flags; 424613a2f6bSGordon Ross 425613a2f6bSGordon Ross /* 426613a2f6bSGordon Ross * Put the LMv2,NTLMv2 responses, or 427613a2f6bSGordon Ross * possibly LM, NTLM (v1) responses. 428613a2f6bSGordon Ross */ 429613a2f6bSGordon Ross if (ctx->ct_authflags & SMB_AT_NTLM2) { 430613a2f6bSGordon Ross /* Build the NTLMv2 "target info" blob. */ 431613a2f6bSGordon Ross err = ntlm_build_target_info(ctx, 432613a2f6bSGordon Ross ssp_st->ss_target_info, &ti_mbc); 433613a2f6bSGordon Ross if (err) 434613a2f6bSGordon Ross goto out; 435613a2f6bSGordon Ross err = ntlm_put_v2_responses(ctx, &ti_mbc, 436613a2f6bSGordon Ross &lm_mbc, &nt_mbc); 437613a2f6bSGordon Ross } else { 438613a2f6bSGordon Ross err = ntlm_put_v1_responses(ctx, 439613a2f6bSGordon Ross &lm_mbc, &nt_mbc); 440613a2f6bSGordon Ross } 441613a2f6bSGordon Ross if (err) 442613a2f6bSGordon Ross goto out; 443613a2f6bSGordon Ross 444613a2f6bSGordon Ross err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top); 445613a2f6bSGordon Ross lm_mbc.mb_top = NULL; /* consumed */ 446613a2f6bSGordon Ross if (err) 447613a2f6bSGordon Ross goto out; 448613a2f6bSGordon Ross err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top); 449613a2f6bSGordon Ross nt_mbc.mb_top = NULL; /* consumed */ 450613a2f6bSGordon Ross if (err) 451613a2f6bSGordon Ross goto out; 452613a2f6bSGordon Ross 453613a2f6bSGordon Ross /* 454613a2f6bSGordon Ross * Put the "target" (domain), user, workstation 455613a2f6bSGordon Ross */ 456*15359501SGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc); 457613a2f6bSGordon Ross if (err) 458613a2f6bSGordon Ross goto out; 459*15359501SGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc); 460613a2f6bSGordon Ross if (err) 461613a2f6bSGordon Ross goto out; 462*15359501SGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_wksta, ctx->ct_locname, uc); 463613a2f6bSGordon Ross if (err) 464613a2f6bSGordon Ross goto out; 465613a2f6bSGordon Ross 466613a2f6bSGordon Ross /* 467*15359501SGordon Ross * Put the "Random Session Key". We don't set 468*15359501SGordon Ross * NTLMSSP_NEGOTIATE_KEY_EXCH, so it's empty. 469*15359501SGordon Ross * (In-line mb_put_sb_data here.) 470*15359501SGordon Ross */ 471*15359501SGordon Ross hdr.h_ssn_key.sb_maxlen = hdr.h_ssn_key.sb_length = 0; 472*15359501SGordon Ross hdr.h_ssn_key.sb_offset = mb2.mb_count; 473*15359501SGordon Ross 474*15359501SGordon Ross /* 475613a2f6bSGordon Ross * Marshal the header (in LE order) 476613a2f6bSGordon Ross * then concatenate the 2nd part. 477613a2f6bSGordon Ross */ 47802d09e03SGordon Ross (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 479613a2f6bSGordon Ross (void) mb_put_uint32le(out_mb, hdr.h_type); 480613a2f6bSGordon Ross 481613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp); 482613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp); 483613a2f6bSGordon Ross 484613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_domain); 485613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_user); 486613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta); 487613a2f6bSGordon Ross 488*15359501SGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key); 489*15359501SGordon Ross (void) mb_put_uint32le(out_mb, hdr.h_flags); 490*15359501SGordon Ross 491613a2f6bSGordon Ross err = mb_put_mbuf(out_mb, mb2.mb_top); 492613a2f6bSGordon Ross mb2.mb_top = NULL; /* consumed */ 493613a2f6bSGordon Ross 494613a2f6bSGordon Ross out: 495613a2f6bSGordon Ross mb_done(&mb2); 496613a2f6bSGordon Ross mb_done(&lm_mbc); 497613a2f6bSGordon Ross mb_done(&nt_mbc); 498*15359501SGordon Ross mb_done(&ti_mbc); 499613a2f6bSGordon Ross 500613a2f6bSGordon Ross return (err); 501613a2f6bSGordon Ross } 502613a2f6bSGordon Ross 503613a2f6bSGordon Ross /* 504613a2f6bSGordon Ross * ntlmssp_final 505613a2f6bSGordon Ross * 506613a2f6bSGordon Ross * Called after successful authentication. 507613a2f6bSGordon Ross * Setup the MAC key for signing. 508613a2f6bSGordon Ross */ 509613a2f6bSGordon Ross int 510613a2f6bSGordon Ross ntlmssp_final(struct ssp_ctx *sp) 511613a2f6bSGordon Ross { 512613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 513613a2f6bSGordon Ross int err = 0; 514613a2f6bSGordon Ross 515613a2f6bSGordon Ross /* 516613a2f6bSGordon Ross * MAC_key is just the session key, but 517613a2f6bSGordon Ross * Only on the first successful auth. 518613a2f6bSGordon Ross */ 519613a2f6bSGordon Ross if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) && 520613a2f6bSGordon Ross (ctx->ct_mackey == NULL)) { 521613a2f6bSGordon Ross ctx->ct_mackeylen = NTLM_HASH_SZ; 522613a2f6bSGordon Ross ctx->ct_mackey = malloc(ctx->ct_mackeylen); 523613a2f6bSGordon Ross if (ctx->ct_mackey == NULL) { 524613a2f6bSGordon Ross ctx->ct_mackeylen = 0; 525613a2f6bSGordon Ross err = ENOMEM; 526613a2f6bSGordon Ross goto out; 527613a2f6bSGordon Ross } 528613a2f6bSGordon Ross memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ); 529613a2f6bSGordon Ross /* 530613a2f6bSGordon Ross * Apparently, the server used seq. no. zero 531613a2f6bSGordon Ross * for our previous message, so next is two. 532613a2f6bSGordon Ross */ 533613a2f6bSGordon Ross ctx->ct_mac_seqno = 2; 534613a2f6bSGordon Ross } 535613a2f6bSGordon Ross 536613a2f6bSGordon Ross out: 537613a2f6bSGordon Ross return (err); 538613a2f6bSGordon Ross } 539613a2f6bSGordon Ross 540613a2f6bSGordon Ross /* 541613a2f6bSGordon Ross * ntlmssp_next_token 542613a2f6bSGordon Ross * 543613a2f6bSGordon Ross * See ssp.c: ssp_ctx_next_token 544613a2f6bSGordon Ross */ 545613a2f6bSGordon Ross int 546613a2f6bSGordon Ross ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb, 547613a2f6bSGordon Ross struct mbdata *out_mb) 548613a2f6bSGordon Ross { 549613a2f6bSGordon Ross int err; 550613a2f6bSGordon Ross 551613a2f6bSGordon Ross if (out_mb == NULL) { 552613a2f6bSGordon Ross /* final call on successful auth. */ 553613a2f6bSGordon Ross err = ntlmssp_final(sp); 554613a2f6bSGordon Ross goto out; 555613a2f6bSGordon Ross } 556613a2f6bSGordon Ross 557613a2f6bSGordon Ross /* Will build an ouptut token. */ 55802d09e03SGordon Ross err = mb_init(out_mb); 559613a2f6bSGordon Ross if (err) 560613a2f6bSGordon Ross goto out; 561613a2f6bSGordon Ross 562613a2f6bSGordon Ross /* 563613a2f6bSGordon Ross * When called with in_mb == NULL, it means 564613a2f6bSGordon Ross * this is the first call for this session, 565613a2f6bSGordon Ross * so put a Type 1 (initialize) token. 566613a2f6bSGordon Ross */ 567613a2f6bSGordon Ross if (in_mb == NULL) { 568613a2f6bSGordon Ross err = ntlmssp_put_type1(sp, out_mb); 569613a2f6bSGordon Ross goto out; 570613a2f6bSGordon Ross } 571613a2f6bSGordon Ross 572613a2f6bSGordon Ross /* 573613a2f6bSGordon Ross * This is not the first call, so 574613a2f6bSGordon Ross * parse the response token we received. 575613a2f6bSGordon Ross * It should be a Type 2 (challenge). 576613a2f6bSGordon Ross * Then put a Type 3 (authenticate) 577613a2f6bSGordon Ross */ 578613a2f6bSGordon Ross err = ntlmssp_get_type2(sp, in_mb); 579613a2f6bSGordon Ross if (err) 580613a2f6bSGordon Ross goto out; 581613a2f6bSGordon Ross 582613a2f6bSGordon Ross err = ntlmssp_put_type3(sp, out_mb); 583613a2f6bSGordon Ross 584613a2f6bSGordon Ross out: 585613a2f6bSGordon Ross if (err) 586613a2f6bSGordon Ross DPRINT("ret: %d", err); 587613a2f6bSGordon Ross return (err); 588613a2f6bSGordon Ross } 589613a2f6bSGordon Ross 590613a2f6bSGordon Ross /* 591613a2f6bSGordon Ross * ntlmssp_ctx_destroy 592613a2f6bSGordon Ross * 593613a2f6bSGordon Ross * Destroy mechanism-specific data. 594613a2f6bSGordon Ross */ 595613a2f6bSGordon Ross void 596613a2f6bSGordon Ross ntlmssp_destroy(struct ssp_ctx *sp) 597613a2f6bSGordon Ross { 598613a2f6bSGordon Ross ntlmssp_state_t *ssp_st; 599613a2f6bSGordon Ross 600613a2f6bSGordon Ross ssp_st = sp->sp_private; 601613a2f6bSGordon Ross if (ssp_st != NULL) { 602613a2f6bSGordon Ross sp->sp_private = NULL; 603613a2f6bSGordon Ross free(ssp_st->ss_target_name); 604613a2f6bSGordon Ross m_freem(ssp_st->ss_target_info); 605613a2f6bSGordon Ross free(ssp_st); 606613a2f6bSGordon Ross } 607613a2f6bSGordon Ross } 608613a2f6bSGordon Ross 609613a2f6bSGordon Ross /* 610613a2f6bSGordon Ross * ntlmssp_init_clnt 611613a2f6bSGordon Ross * 612613a2f6bSGordon Ross * Initialize a new NTLMSSP client context. 613613a2f6bSGordon Ross */ 614613a2f6bSGordon Ross int 615613a2f6bSGordon Ross ntlmssp_init_client(struct ssp_ctx *sp) 616613a2f6bSGordon Ross { 617613a2f6bSGordon Ross ntlmssp_state_t *ssp_st; 618613a2f6bSGordon Ross 619613a2f6bSGordon Ross if ((sp->smb_ctx->ct_authflags & 620613a2f6bSGordon Ross (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) { 621613a2f6bSGordon Ross DPRINT("No NTLM authflags"); 622613a2f6bSGordon Ross return (ENOTSUP); 623613a2f6bSGordon Ross } 624613a2f6bSGordon Ross 625613a2f6bSGordon Ross ssp_st = calloc(1, sizeof (*ssp_st)); 626613a2f6bSGordon Ross if (ssp_st == NULL) 627613a2f6bSGordon Ross return (ENOMEM); 628613a2f6bSGordon Ross 629613a2f6bSGordon Ross sp->sp_nexttok = ntlmssp_next_token; 630613a2f6bSGordon Ross sp->sp_destroy = ntlmssp_destroy; 631613a2f6bSGordon Ross sp->sp_private = ssp_st; 632613a2f6bSGordon Ross 633613a2f6bSGordon Ross return (0); 634613a2f6bSGordon Ross } 635