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 /* 23613a2f6bSGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24613a2f6bSGordon Ross * Use is subject to license terms. 25613a2f6bSGordon Ross */ 26613a2f6bSGordon Ross 27613a2f6bSGordon Ross /* 28613a2f6bSGordon Ross * NT Lan Manager Security Support Provider (NTLMSSP) 29613a2f6bSGordon Ross * 30613a2f6bSGordon Ross * Based on information from the "Davenport NTLM" page: 31613a2f6bSGordon Ross * http://davenport.sourceforge.net/ntlm.html 32613a2f6bSGordon Ross */ 33613a2f6bSGordon Ross 34613a2f6bSGordon Ross 35613a2f6bSGordon Ross #include <errno.h> 36613a2f6bSGordon Ross #include <stdio.h> 37613a2f6bSGordon Ross #include <stddef.h> 38613a2f6bSGordon Ross #include <stdlib.h> 39613a2f6bSGordon Ross #include <unistd.h> 40613a2f6bSGordon Ross #include <strings.h> 41613a2f6bSGordon Ross #include <netdb.h> 42613a2f6bSGordon Ross #include <libintl.h> 43613a2f6bSGordon Ross #include <xti.h> 44613a2f6bSGordon Ross #include <assert.h> 45613a2f6bSGordon Ross 46613a2f6bSGordon Ross #include <sys/types.h> 47613a2f6bSGordon Ross #include <sys/time.h> 48613a2f6bSGordon Ross #include <sys/byteorder.h> 49613a2f6bSGordon Ross #include <sys/socket.h> 50613a2f6bSGordon Ross #include <sys/fcntl.h> 51613a2f6bSGordon Ross 52613a2f6bSGordon Ross #include <netinet/in.h> 53613a2f6bSGordon Ross #include <netinet/tcp.h> 54613a2f6bSGordon Ross #include <arpa/inet.h> 55613a2f6bSGordon Ross 56613a2f6bSGordon Ross #include <netsmb/smb.h> 57613a2f6bSGordon Ross #include <netsmb/smb_lib.h> 58613a2f6bSGordon Ross #include <netsmb/mchain.h> 59613a2f6bSGordon Ross 60613a2f6bSGordon Ross #include "private.h" 61613a2f6bSGordon Ross #include "charsets.h" 62613a2f6bSGordon Ross #include "spnego.h" 63613a2f6bSGordon Ross #include "derparse.h" 64613a2f6bSGordon Ross #include "ssp.h" 65613a2f6bSGordon Ross #include "ntlm.h" 66613a2f6bSGordon Ross #include "ntlmssp.h" 67613a2f6bSGordon Ross 68613a2f6bSGordon Ross typedef struct ntlmssp_state { 69613a2f6bSGordon Ross uint32_t ss_flags; 70613a2f6bSGordon Ross char *ss_target_name; 71613a2f6bSGordon Ross struct mbuf *ss_target_info; 72613a2f6bSGordon Ross } ntlmssp_state_t; 73613a2f6bSGordon Ross 74613a2f6bSGordon Ross /* 75613a2f6bSGordon Ross * So called "security buffer". 76613a2f6bSGordon Ross * A lot like an RPC string. 77613a2f6bSGordon Ross */ 78613a2f6bSGordon Ross struct sec_buf { 79613a2f6bSGordon Ross uint16_t sb_length; 80613a2f6bSGordon Ross uint16_t sb_maxlen; 81613a2f6bSGordon Ross uint32_t sb_offset; 82613a2f6bSGordon Ross }; 83613a2f6bSGordon Ross #define ID_SZ 8 84613a2f6bSGordon Ross static const char ntlmssp_id[ID_SZ] = "NTLMSSP"; 85613a2f6bSGordon Ross 86613a2f6bSGordon Ross /* 87613a2f6bSGordon Ross * Get a "security buffer" (header part) 88613a2f6bSGordon Ross */ 89613a2f6bSGordon Ross static int 90*02d09e03SGordon Ross md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) 91613a2f6bSGordon Ross { 92613a2f6bSGordon Ross int err; 93613a2f6bSGordon Ross 94*02d09e03SGordon Ross (void) md_get_uint16le(mbp, &sb->sb_length); 95*02d09e03SGordon Ross (void) md_get_uint16le(mbp, &sb->sb_maxlen); 96*02d09e03SGordon Ross err = md_get_uint32le(mbp, &sb->sb_offset); 97613a2f6bSGordon Ross 98613a2f6bSGordon Ross return (err); 99613a2f6bSGordon Ross } 100613a2f6bSGordon Ross 101613a2f6bSGordon Ross /* 102613a2f6bSGordon Ross * Get a "security buffer" (data part), where 103613a2f6bSGordon Ross * the data is delivered as an mbuf. 104613a2f6bSGordon Ross */ 105613a2f6bSGordon Ross static int 106*02d09e03SGordon Ross md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp) 107613a2f6bSGordon Ross { 108613a2f6bSGordon Ross struct mbdata tmp_mb; 109613a2f6bSGordon Ross int err; 110613a2f6bSGordon Ross 111613a2f6bSGordon Ross /* 112613a2f6bSGordon Ross * Setup tmp_mb to point to the start of the header. 113613a2f6bSGordon Ross * This is a dup ref - do NOT free it. 114613a2f6bSGordon Ross */ 115613a2f6bSGordon Ross mb_initm(&tmp_mb, mbp->mb_top); 116613a2f6bSGordon Ross 117613a2f6bSGordon Ross /* Skip data up to the offset. */ 118*02d09e03SGordon Ross err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM); 119613a2f6bSGordon Ross if (err) 120613a2f6bSGordon Ross return (err); 121613a2f6bSGordon Ross 122613a2f6bSGordon Ross /* Get the data (as an mbuf). */ 123*02d09e03SGordon Ross err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp); 124613a2f6bSGordon Ross 125613a2f6bSGordon Ross return (err); 126613a2f6bSGordon Ross } 127613a2f6bSGordon Ross 128613a2f6bSGordon Ross /* 129613a2f6bSGordon Ross * Put a "security buffer" (header part) 130613a2f6bSGordon Ross */ 131613a2f6bSGordon Ross static int 132613a2f6bSGordon Ross mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) 133613a2f6bSGordon Ross { 134613a2f6bSGordon Ross int err; 135613a2f6bSGordon Ross 136613a2f6bSGordon Ross (void) mb_put_uint16le(mbp, sb->sb_length); 137613a2f6bSGordon Ross (void) mb_put_uint16le(mbp, sb->sb_maxlen); 138613a2f6bSGordon Ross err = mb_put_uint32le(mbp, sb->sb_offset); 139613a2f6bSGordon Ross 140613a2f6bSGordon Ross return (err); 141613a2f6bSGordon Ross } 142613a2f6bSGordon Ross 143613a2f6bSGordon Ross /* 144613a2f6bSGordon Ross * Put a "security buffer" (data part), where 145613a2f6bSGordon Ross * the data is an mbuf. Note: consumes m. 146613a2f6bSGordon Ross */ 147613a2f6bSGordon Ross static int 148613a2f6bSGordon Ross mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m) 149613a2f6bSGordon Ross { 150613a2f6bSGordon Ross int cnt0, err; 151613a2f6bSGordon Ross 152613a2f6bSGordon Ross sb->sb_offset = cnt0 = mbp->mb_count; 153613a2f6bSGordon Ross err = mb_put_mbuf(mbp, m); 154613a2f6bSGordon Ross sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0; 155613a2f6bSGordon Ross 156613a2f6bSGordon Ross return (err); 157613a2f6bSGordon Ross } 158613a2f6bSGordon Ross 159613a2f6bSGordon Ross /* 160613a2f6bSGordon Ross * Put a "security buffer" (data part), where 161613a2f6bSGordon Ross * the data is a string (OEM or unicode). 162613a2f6bSGordon Ross * 163613a2f6bSGordon Ross * The string is NOT null terminated. 164613a2f6bSGordon Ross */ 165613a2f6bSGordon Ross static int 166613a2f6bSGordon Ross mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb, 167613a2f6bSGordon Ross const char *s, int unicode) 168613a2f6bSGordon Ross { 169613a2f6bSGordon Ross int err, trim; 170613a2f6bSGordon Ross struct mbdata tmp_mb; 171613a2f6bSGordon Ross 172613a2f6bSGordon Ross /* 173613a2f6bSGordon Ross * Put the string into a temp. mbuf, 174613a2f6bSGordon Ross * then chop off the null terminator 175613a2f6bSGordon Ross * before appending to caller's mbp. 176613a2f6bSGordon Ross */ 177*02d09e03SGordon Ross err = mb_init(&tmp_mb); 178613a2f6bSGordon Ross if (err) 179613a2f6bSGordon Ross return (err); 180*02d09e03SGordon Ross err = mb_put_string(&tmp_mb, s, unicode); 181613a2f6bSGordon Ross if (err) 182613a2f6bSGordon Ross return (err); 183613a2f6bSGordon Ross 184613a2f6bSGordon Ross trim = (unicode) ? 2 : 1; 185613a2f6bSGordon Ross if (tmp_mb.mb_cur->m_len < trim) 186613a2f6bSGordon Ross return (EFAULT); 187613a2f6bSGordon Ross tmp_mb.mb_cur->m_len -= trim; 188613a2f6bSGordon Ross 189613a2f6bSGordon Ross err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top); 190613a2f6bSGordon Ross /* 191613a2f6bSGordon Ross * Note: tmp_mb.mb_top is consumed, 192613a2f6bSGordon Ross * so do NOT free it (no mb_done) 193613a2f6bSGordon Ross */ 194613a2f6bSGordon Ross return (err); 195613a2f6bSGordon Ross } 196613a2f6bSGordon Ross 197613a2f6bSGordon Ross /* 198613a2f6bSGordon Ross * Build a Type 1 message 199613a2f6bSGordon Ross * 200613a2f6bSGordon Ross * This message has a header section containing offsets to 201613a2f6bSGordon Ross * data later in the message. We use the common trick of 202613a2f6bSGordon Ross * building it in two parts and then concatenatening. 203613a2f6bSGordon Ross */ 204613a2f6bSGordon Ross int 205613a2f6bSGordon Ross ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb) 206613a2f6bSGordon Ross { 207613a2f6bSGordon Ross struct type1hdr { 208613a2f6bSGordon Ross char h_id[ID_SZ]; 209613a2f6bSGordon Ross uint32_t h_type; 210613a2f6bSGordon Ross uint32_t h_flags; 211613a2f6bSGordon Ross struct sec_buf h_cldom; 212613a2f6bSGordon Ross struct sec_buf h_wksta; 213613a2f6bSGordon Ross } hdr; 214613a2f6bSGordon Ross struct mbdata mb2; /* 2nd part */ 215613a2f6bSGordon Ross int err; 216613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 217613a2f6bSGordon Ross ntlmssp_state_t *ssp_st = sp->sp_private; 218613a2f6bSGordon Ross char *ucdom = NULL; 219613a2f6bSGordon Ross char *ucwks = NULL; 220613a2f6bSGordon Ross 221*02d09e03SGordon Ross if ((err = mb_init(&mb2)) != 0) 222613a2f6bSGordon Ross return (err); 223613a2f6bSGordon Ross mb2.mb_count = sizeof (hdr); 224613a2f6bSGordon Ross 225613a2f6bSGordon Ross /* 226613a2f6bSGordon Ross * Initialize the negotiation flags, and 227613a2f6bSGordon Ross * save what we sent. For reference: 228613a2f6bSGordon Ross * [MS-NLMP] spec. (also ntlmssp.h) 229613a2f6bSGordon Ross */ 230613a2f6bSGordon Ross ssp_st->ss_flags = 231613a2f6bSGordon Ross NTLMSSP_REQUEST_TARGET | 232613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_NTLM | 233613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_TARGET_INFO | 234613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_128 | 235613a2f6bSGordon Ross NTLMSSP_NEGOTIATE_56; 236613a2f6bSGordon Ross 237613a2f6bSGordon Ross if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE) 238613a2f6bSGordon Ross ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE; 239613a2f6bSGordon Ross else 240613a2f6bSGordon Ross ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM; 241613a2f6bSGordon Ross 242613a2f6bSGordon Ross if (ctx->ct_vcflags & SMBV_WILL_SIGN) { 243613a2f6bSGordon Ross ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; 244613a2f6bSGordon Ross ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; 245613a2f6bSGordon Ross } 246613a2f6bSGordon Ross 247613a2f6bSGordon Ross bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); 248613a2f6bSGordon Ross hdr.h_type = 1; /* Type 1 */ 249613a2f6bSGordon Ross hdr.h_flags = ssp_st->ss_flags; 250613a2f6bSGordon Ross 251613a2f6bSGordon Ross /* 252613a2f6bSGordon Ross * Put the client domain, client name strings. 253613a2f6bSGordon Ross * These are always in OEM format, upper-case. 254613a2f6bSGordon Ross */ 255613a2f6bSGordon Ross ucdom = utf8_str_toupper(ctx->ct_domain); 256613a2f6bSGordon Ross ucwks = utf8_str_toupper(ctx->ct_locname); 257613a2f6bSGordon Ross if (ucdom == NULL || ucwks == NULL) { 258613a2f6bSGordon Ross err = ENOMEM; 259613a2f6bSGordon Ross goto out; 260613a2f6bSGordon Ross } 261613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0); 262613a2f6bSGordon Ross if (err) 263613a2f6bSGordon Ross goto out; 264613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0); 265613a2f6bSGordon Ross if (err) 266613a2f6bSGordon Ross goto out; 267613a2f6bSGordon Ross 268613a2f6bSGordon Ross /* 269613a2f6bSGordon Ross * Marshal the header (in LE order) 270613a2f6bSGordon Ross * then concatenate the 2nd part. 271613a2f6bSGordon Ross */ 272*02d09e03SGordon Ross (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 273613a2f6bSGordon Ross (void) mb_put_uint32le(out_mb, hdr.h_type); 274613a2f6bSGordon Ross (void) mb_put_uint32le(out_mb, hdr.h_flags); 275613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom); 276613a2f6bSGordon Ross (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta); 277613a2f6bSGordon Ross 278613a2f6bSGordon Ross err = mb_put_mbuf(out_mb, mb2.mb_top); 279613a2f6bSGordon Ross 280613a2f6bSGordon Ross out: 281613a2f6bSGordon Ross free(ucdom); 282613a2f6bSGordon Ross free(ucwks); 283613a2f6bSGordon Ross 284613a2f6bSGordon Ross return (err); 285613a2f6bSGordon Ross } 286613a2f6bSGordon Ross 287613a2f6bSGordon Ross /* 288613a2f6bSGordon Ross * Parse a Type 2 message 289613a2f6bSGordon Ross */ 290613a2f6bSGordon Ross int 291613a2f6bSGordon Ross ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb) 292613a2f6bSGordon Ross { 293613a2f6bSGordon Ross struct type2hdr { 294613a2f6bSGordon Ross char h_id[ID_SZ]; 295613a2f6bSGordon Ross uint32_t h_type; 296613a2f6bSGordon Ross struct sec_buf h_target_name; 297613a2f6bSGordon Ross uint32_t h_flags; 298613a2f6bSGordon Ross uint8_t h_challenge[8]; 299613a2f6bSGordon Ross uint32_t h_context[2]; /* optional */ 300613a2f6bSGordon Ross struct sec_buf h_target_info; /* optional */ 301613a2f6bSGordon Ross } hdr; 302613a2f6bSGordon Ross struct mbdata top_mb, tmp_mb; 303613a2f6bSGordon Ross struct mbuf *m; 304613a2f6bSGordon Ross int err, uc; 305613a2f6bSGordon Ross int min_hdr_sz = offsetof(struct type2hdr, h_context); 306613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 307613a2f6bSGordon Ross ntlmssp_state_t *ssp_st = sp->sp_private; 308613a2f6bSGordon Ross char *buf = NULL; 309613a2f6bSGordon Ross 310613a2f6bSGordon Ross if (m_totlen(in_mb->mb_top) < min_hdr_sz) { 311613a2f6bSGordon Ross err = EBADRPC; 312613a2f6bSGordon Ross goto out; 313613a2f6bSGordon Ross } 314613a2f6bSGordon Ross 315613a2f6bSGordon Ross /* 316613a2f6bSGordon Ross * Save the mbdata pointers before we consume anything. 317613a2f6bSGordon Ross * Careful to NOT free this (would be dup. free) 318613a2f6bSGordon Ross * We use this below to find data based on offsets 319613a2f6bSGordon Ross * from the start of the header. 320613a2f6bSGordon Ross */ 321613a2f6bSGordon Ross top_mb = *in_mb; 322613a2f6bSGordon Ross 323613a2f6bSGordon Ross /* Parse the fixed size header stuff. */ 324613a2f6bSGordon Ross bzero(&hdr, sizeof (hdr)); 325*02d09e03SGordon Ross (void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); 326*02d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_type); 327613a2f6bSGordon Ross if (hdr.h_type != 2) { 328613a2f6bSGordon Ross err = EPROTO; 329613a2f6bSGordon Ross goto out; 330613a2f6bSGordon Ross } 331*02d09e03SGordon Ross (void) md_get_sb_hdr(in_mb, &hdr.h_target_name); 332*02d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_flags); 333*02d09e03SGordon Ross (void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM); 334613a2f6bSGordon Ross 335613a2f6bSGordon Ross /* 336613a2f6bSGordon Ross * Save flags, challenge for later. 337613a2f6bSGordon Ross */ 338613a2f6bSGordon Ross ssp_st->ss_flags = hdr.h_flags; 339613a2f6bSGordon Ross uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE; 340613a2f6bSGordon Ross bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ); 341613a2f6bSGordon Ross 342613a2f6bSGordon Ross /* 343613a2f6bSGordon Ross * Now find out if the optional parts are there. 344613a2f6bSGordon Ross */ 345613a2f6bSGordon Ross if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) && 346613a2f6bSGordon Ross (hdr.h_target_name.sb_offset >= sizeof (hdr))) { 347*02d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_context[0]); 348*02d09e03SGordon Ross (void) md_get_uint32le(in_mb, &hdr.h_context[1]); 349*02d09e03SGordon Ross (void) md_get_sb_hdr(in_mb, &hdr.h_target_info); 350613a2f6bSGordon Ross } 351613a2f6bSGordon Ross 352613a2f6bSGordon Ross /* 353613a2f6bSGordon Ross * Get the target name string. First get a copy of 354613a2f6bSGordon Ross * the data from the offset/length indicated in the 355613a2f6bSGordon Ross * security buffer header; then parse the string. 356613a2f6bSGordon Ross */ 357*02d09e03SGordon Ross err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m); 358613a2f6bSGordon Ross if (err) 359613a2f6bSGordon Ross goto out; 360613a2f6bSGordon Ross mb_initm(&tmp_mb, m); 361*02d09e03SGordon Ross err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc); 362613a2f6bSGordon Ross mb_done(&tmp_mb); 363613a2f6bSGordon Ross 364613a2f6bSGordon Ross /* 365613a2f6bSGordon Ross * Get the target info blob, if present. 366613a2f6bSGordon Ross */ 367613a2f6bSGordon Ross if (hdr.h_target_info.sb_offset >= sizeof (hdr)) { 368*02d09e03SGordon Ross err = md_get_sb_data(&top_mb, &hdr.h_target_info, 369613a2f6bSGordon Ross &ssp_st->ss_target_info); 370613a2f6bSGordon Ross } 371613a2f6bSGordon Ross 372613a2f6bSGordon Ross out: 373613a2f6bSGordon Ross if (buf != NULL) 374613a2f6bSGordon Ross free(buf); 375613a2f6bSGordon Ross 376613a2f6bSGordon Ross return (err); 377613a2f6bSGordon Ross } 378613a2f6bSGordon Ross 379613a2f6bSGordon Ross /* 380613a2f6bSGordon Ross * Build a Type 3 message 381613a2f6bSGordon Ross * 382613a2f6bSGordon Ross * This message has a header section containing offsets to 383613a2f6bSGordon Ross * data later in the message. We use the common trick of 384613a2f6bSGordon Ross * building it in two parts and then concatenatening. 385613a2f6bSGordon Ross */ 386613a2f6bSGordon Ross int 387613a2f6bSGordon Ross ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) 388613a2f6bSGordon Ross { 389613a2f6bSGordon Ross struct type3hdr { 390613a2f6bSGordon Ross char h_id[ID_SZ]; 391613a2f6bSGordon Ross uint32_t h_type; 392613a2f6bSGordon Ross struct sec_buf h_lm_resp; 393613a2f6bSGordon Ross struct sec_buf h_nt_resp; 394613a2f6bSGordon Ross struct sec_buf h_domain; 395613a2f6bSGordon Ross struct sec_buf h_user; 396613a2f6bSGordon Ross struct sec_buf h_wksta; 397613a2f6bSGordon Ross } hdr; 398613a2f6bSGordon Ross struct mbdata lm_mbc, nt_mbc, ti_mbc; 399613a2f6bSGordon Ross struct mbdata mb2; /* 2nd part */ 400613a2f6bSGordon Ross int err, uc; 401613a2f6bSGordon Ross char *ucdom = NULL; /* user's domain */ 402613a2f6bSGordon Ross char *ucuser = NULL; /* user name */ 403613a2f6bSGordon Ross char *ucwksta = NULL; /* workstation */ 404613a2f6bSGordon Ross struct smb_ctx *ctx = sp->smb_ctx; 405613a2f6bSGordon Ross ntlmssp_state_t *ssp_st = sp->sp_private; 406613a2f6bSGordon Ross 407613a2f6bSGordon Ross bzero(&lm_mbc, sizeof (lm_mbc)); 408613a2f6bSGordon Ross bzero(&nt_mbc, sizeof (nt_mbc)); 409613a2f6bSGordon Ross bzero(&ti_mbc, sizeof (ti_mbc)); 410613a2f6bSGordon Ross bzero(&mb2, sizeof (mb2)); 411613a2f6bSGordon Ross 412613a2f6bSGordon Ross /* 413613a2f6bSGordon Ross * Convert the user name to upper-case, as that's what's 414613a2f6bSGordon Ross * used when computing LMv2 and NTLMv2 responses. Also 415613a2f6bSGordon Ross * domain, workstation 416613a2f6bSGordon Ross */ 417613a2f6bSGordon Ross ucdom = utf8_str_toupper(ctx->ct_domain); 418613a2f6bSGordon Ross ucuser = utf8_str_toupper(ctx->ct_user); 419613a2f6bSGordon Ross ucwksta = utf8_str_toupper(ctx->ct_locname); 420613a2f6bSGordon Ross if (ucdom == NULL || ucuser == NULL || ucwksta == NULL) { 421613a2f6bSGordon Ross err = ENOMEM; 422613a2f6bSGordon Ross goto out; 423613a2f6bSGordon Ross } 424613a2f6bSGordon Ross 425*02d09e03SGordon Ross if ((err = mb_init(&mb2)) != 0) 426613a2f6bSGordon Ross goto out; 427613a2f6bSGordon Ross mb2.mb_count = sizeof (hdr); 428613a2f6bSGordon Ross uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE; 429613a2f6bSGordon Ross 430613a2f6bSGordon Ross bcopy(ntlmssp_id, &hdr.h_id, ID_SZ); 431613a2f6bSGordon Ross hdr.h_type = 3; /* Type 3 */ 432613a2f6bSGordon Ross 433613a2f6bSGordon Ross /* 434613a2f6bSGordon Ross * Put the LMv2,NTLMv2 responses, or 435613a2f6bSGordon Ross * possibly LM, NTLM (v1) responses. 436613a2f6bSGordon Ross */ 437613a2f6bSGordon Ross if (ctx->ct_authflags & SMB_AT_NTLM2) { 438613a2f6bSGordon Ross /* Build the NTLMv2 "target info" blob. */ 439613a2f6bSGordon Ross err = ntlm_build_target_info(ctx, 440613a2f6bSGordon Ross ssp_st->ss_target_info, &ti_mbc); 441613a2f6bSGordon Ross if (err) 442613a2f6bSGordon Ross goto out; 443613a2f6bSGordon Ross err = ntlm_put_v2_responses(ctx, &ti_mbc, 444613a2f6bSGordon Ross &lm_mbc, &nt_mbc); 445613a2f6bSGordon Ross } else { 446613a2f6bSGordon Ross err = ntlm_put_v1_responses(ctx, 447613a2f6bSGordon Ross &lm_mbc, &nt_mbc); 448613a2f6bSGordon Ross } 449613a2f6bSGordon Ross if (err) 450613a2f6bSGordon Ross goto out; 451613a2f6bSGordon Ross 452613a2f6bSGordon Ross err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top); 453613a2f6bSGordon Ross lm_mbc.mb_top = NULL; /* consumed */ 454613a2f6bSGordon Ross if (err) 455613a2f6bSGordon Ross goto out; 456613a2f6bSGordon Ross err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top); 457613a2f6bSGordon Ross nt_mbc.mb_top = NULL; /* consumed */ 458613a2f6bSGordon Ross if (err) 459613a2f6bSGordon Ross goto out; 460613a2f6bSGordon Ross 461613a2f6bSGordon Ross /* 462613a2f6bSGordon Ross * Put the "target" (domain), user, workstation 463613a2f6bSGordon Ross */ 464613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_domain, ucdom, uc); 465613a2f6bSGordon Ross if (err) 466613a2f6bSGordon Ross goto out; 467613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_user, ucuser, uc); 468613a2f6bSGordon Ross if (err) 469613a2f6bSGordon Ross goto out; 470613a2f6bSGordon Ross err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwksta, uc); 471613a2f6bSGordon Ross if (err) 472613a2f6bSGordon Ross goto out; 473613a2f6bSGordon Ross 474613a2f6bSGordon Ross /* 475613a2f6bSGordon Ross * Marshal the header (in LE order) 476613a2f6bSGordon Ross * then concatenate the 2nd part. 477613a2f6bSGordon Ross */ 478*02d09e03SGordon 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 488613a2f6bSGordon Ross err = mb_put_mbuf(out_mb, mb2.mb_top); 489613a2f6bSGordon Ross mb2.mb_top = NULL; /* consumed */ 490613a2f6bSGordon Ross 491613a2f6bSGordon Ross out: 492613a2f6bSGordon Ross free(ucdom); 493613a2f6bSGordon Ross free(ucuser); 494613a2f6bSGordon Ross free(ucwksta); 495613a2f6bSGordon Ross 496613a2f6bSGordon Ross mb_done(&mb2); 497613a2f6bSGordon Ross mb_done(&lm_mbc); 498613a2f6bSGordon Ross mb_done(&nt_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. */ 558*02d09e03SGordon 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