xref: /illumos-gate/usr/src/lib/libsmbfs/smb/ntlmssp.c (revision 40c0e231)
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 /*
2315359501SGordon Ross  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24*40c0e231SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
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"
6285e6b674SGordon Ross #include "smb_crypt.h"
63613a2f6bSGordon Ross #include "spnego.h"
64613a2f6bSGordon Ross #include "derparse.h"
65613a2f6bSGordon Ross #include "ssp.h"
66613a2f6bSGordon Ross #include "ntlm.h"
67613a2f6bSGordon Ross #include "ntlmssp.h"
68613a2f6bSGordon Ross 
6985e6b674SGordon Ross /* A shorter alias for a crazy long name from [MS-NLMP] */
70*40c0e231SGordon Ross #define	NTLMSSP_NEGOTIATE_ESS \
7185e6b674SGordon Ross 	NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
7285e6b674SGordon Ross 
73613a2f6bSGordon Ross typedef struct ntlmssp_state {
74613a2f6bSGordon Ross 	uint32_t ss_flags;
7585e6b674SGordon Ross 	char *ss_target_name;	/* Primary domain or server name */
76613a2f6bSGordon Ross 	struct mbuf *ss_target_info;
77*40c0e231SGordon Ross 	uchar_t	ss_ssnkey[NTLM_HASH_SZ];
7885e6b674SGordon Ross 	uchar_t	ss_kxkey[NTLM_HASH_SZ];
79613a2f6bSGordon Ross } ntlmssp_state_t;
80613a2f6bSGordon Ross 
81613a2f6bSGordon Ross /*
82613a2f6bSGordon Ross  * So called "security buffer".
83613a2f6bSGordon Ross  * A lot like an RPC string.
84613a2f6bSGordon Ross  */
85613a2f6bSGordon Ross struct sec_buf {
86613a2f6bSGordon Ross 	uint16_t sb_length;
87613a2f6bSGordon Ross 	uint16_t sb_maxlen;
88613a2f6bSGordon Ross 	uint32_t sb_offset;
89613a2f6bSGordon Ross };
90613a2f6bSGordon Ross #define	ID_SZ 8
91613a2f6bSGordon Ross static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
92613a2f6bSGordon Ross 
9385e6b674SGordon Ross static int
94*40c0e231SGordon Ross ntlm_rand_ssn_key(ntlmssp_state_t *ssp_st, struct mbdata *ek_mbp);
9585e6b674SGordon Ross 
96613a2f6bSGordon Ross /*
97613a2f6bSGordon Ross  * Get a "security buffer" (header part)
98613a2f6bSGordon Ross  */
99613a2f6bSGordon Ross static int
md_get_sb_hdr(struct mbdata * mbp,struct sec_buf * sb)10002d09e03SGordon Ross md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
101613a2f6bSGordon Ross {
102613a2f6bSGordon Ross 	int err;
103613a2f6bSGordon Ross 
10402d09e03SGordon Ross 	(void) md_get_uint16le(mbp, &sb->sb_length);
10502d09e03SGordon Ross 	(void) md_get_uint16le(mbp, &sb->sb_maxlen);
10602d09e03SGordon Ross 	err = md_get_uint32le(mbp, &sb->sb_offset);
107613a2f6bSGordon Ross 
108613a2f6bSGordon Ross 	return (err);
109613a2f6bSGordon Ross }
110613a2f6bSGordon Ross 
111613a2f6bSGordon Ross /*
112613a2f6bSGordon Ross  * Get a "security buffer" (data part), where
113613a2f6bSGordon Ross  * the data is delivered as an mbuf.
114613a2f6bSGordon Ross  */
115613a2f6bSGordon Ross static int
md_get_sb_data(struct mbdata * mbp,struct sec_buf * sb,struct mbuf ** mp)11602d09e03SGordon Ross md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp)
117613a2f6bSGordon Ross {
118613a2f6bSGordon Ross 	struct mbdata tmp_mb;
119613a2f6bSGordon Ross 	int err;
120613a2f6bSGordon Ross 
121613a2f6bSGordon Ross 	/*
122613a2f6bSGordon Ross 	 * Setup tmp_mb to point to the start of the header.
123613a2f6bSGordon Ross 	 * This is a dup ref - do NOT free it.
124613a2f6bSGordon Ross 	 */
125613a2f6bSGordon Ross 	mb_initm(&tmp_mb, mbp->mb_top);
126613a2f6bSGordon Ross 
127613a2f6bSGordon Ross 	/* Skip data up to the offset. */
12802d09e03SGordon Ross 	err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM);
129613a2f6bSGordon Ross 	if (err)
130613a2f6bSGordon Ross 		return (err);
131613a2f6bSGordon Ross 
132613a2f6bSGordon Ross 	/* Get the data (as an mbuf). */
13302d09e03SGordon Ross 	err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp);
134613a2f6bSGordon Ross 
135613a2f6bSGordon Ross 	return (err);
136613a2f6bSGordon Ross }
137613a2f6bSGordon Ross 
138613a2f6bSGordon Ross /*
139613a2f6bSGordon Ross  * Put a "security buffer" (header part)
140613a2f6bSGordon Ross  */
141613a2f6bSGordon Ross static int
mb_put_sb_hdr(struct mbdata * mbp,struct sec_buf * sb)142613a2f6bSGordon Ross mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
143613a2f6bSGordon Ross {
144613a2f6bSGordon Ross 	int err;
145613a2f6bSGordon Ross 
146613a2f6bSGordon Ross 	(void) mb_put_uint16le(mbp, sb->sb_length);
147613a2f6bSGordon Ross 	(void) mb_put_uint16le(mbp, sb->sb_maxlen);
148613a2f6bSGordon Ross 	err = mb_put_uint32le(mbp, sb->sb_offset);
149613a2f6bSGordon Ross 
150613a2f6bSGordon Ross 	return (err);
151613a2f6bSGordon Ross }
152613a2f6bSGordon Ross 
153613a2f6bSGordon Ross /*
154613a2f6bSGordon Ross  * Put a "security buffer" (data part), where
155613a2f6bSGordon Ross  * the data is an mbuf.  Note: consumes m.
156613a2f6bSGordon Ross  */
157613a2f6bSGordon Ross static int
mb_put_sb_data(struct mbdata * mbp,struct sec_buf * sb,struct mbuf * m)158613a2f6bSGordon Ross mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
159613a2f6bSGordon Ross {
16085e6b674SGordon Ross 	int cnt0;
16185e6b674SGordon Ross 	int err = 0;
162613a2f6bSGordon Ross 
163613a2f6bSGordon Ross 	sb->sb_offset = cnt0 = mbp->mb_count;
16485e6b674SGordon Ross 	if (m != NULL)
16585e6b674SGordon Ross 		err = mb_put_mbuf(mbp, m);
166613a2f6bSGordon Ross 	sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
167613a2f6bSGordon Ross 
168613a2f6bSGordon Ross 	return (err);
169613a2f6bSGordon Ross }
170613a2f6bSGordon Ross 
171613a2f6bSGordon Ross /*
172613a2f6bSGordon Ross  * Put a "security buffer" (data part), where
173613a2f6bSGordon Ross  * the data is a string (OEM or unicode).
174613a2f6bSGordon Ross  *
175613a2f6bSGordon Ross  * The string is NOT null terminated.
176613a2f6bSGordon Ross  */
177613a2f6bSGordon Ross static int
mb_put_sb_string(struct mbdata * mbp,struct sec_buf * sb,const char * str,int unicode)178613a2f6bSGordon Ross mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
17985e6b674SGordon Ross 	const char *str, int unicode)
180613a2f6bSGordon Ross {
181613a2f6bSGordon Ross 	int err, trim;
182613a2f6bSGordon Ross 	struct mbdata tmp_mb;
183613a2f6bSGordon Ross 
18485e6b674SGordon Ross 	bzero(&tmp_mb, sizeof (tmp_mb));
185613a2f6bSGordon Ross 
18685e6b674SGordon Ross 	if (str != NULL && *str != '\0') {
18785e6b674SGordon Ross 		/*
18885e6b674SGordon Ross 		 * Put the string into a temp. mbuf,
18985e6b674SGordon Ross 		 * then chop off the null terminator
19085e6b674SGordon Ross 		 * before appending to caller's mbp.
19185e6b674SGordon Ross 		 */
19285e6b674SGordon Ross 		err = mb_init(&tmp_mb);
19385e6b674SGordon Ross 		if (err)
19485e6b674SGordon Ross 			return (err);
19585e6b674SGordon Ross 		err = mb_put_string(&tmp_mb, str, unicode);
19685e6b674SGordon Ross 		if (err)
19785e6b674SGordon Ross 			return (err);
19885e6b674SGordon Ross 
19985e6b674SGordon Ross 		trim = (unicode) ? 2 : 1;
20085e6b674SGordon Ross 		if (tmp_mb.mb_cur->m_len < trim)
20185e6b674SGordon Ross 			trim = 0;
20285e6b674SGordon Ross 		tmp_mb.mb_cur->m_len -= trim;
20385e6b674SGordon Ross 	}
204613a2f6bSGordon Ross 
205613a2f6bSGordon Ross 	err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
206613a2f6bSGordon Ross 	/*
20785e6b674SGordon Ross 	 * Note: tmp_mb.mb_top (if any) is consumed,
208613a2f6bSGordon Ross 	 * so do NOT free it (no mb_done)
209613a2f6bSGordon Ross 	 */
210613a2f6bSGordon Ross 	return (err);
211613a2f6bSGordon Ross }
212613a2f6bSGordon Ross 
213613a2f6bSGordon Ross /*
214613a2f6bSGordon Ross  * Build a Type 1 message
215613a2f6bSGordon Ross  *
216613a2f6bSGordon Ross  * This message has a header section containing offsets to
217613a2f6bSGordon Ross  * data later in the message.  We use the common trick of
218613a2f6bSGordon Ross  * building it in two parts and then concatenatening.
219613a2f6bSGordon Ross  */
220613a2f6bSGordon Ross int
ntlmssp_put_type1(struct ssp_ctx * sp,struct mbdata * out_mb)221613a2f6bSGordon Ross ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
222613a2f6bSGordon Ross {
223613a2f6bSGordon Ross 	struct type1hdr {
224613a2f6bSGordon Ross 		char h_id[ID_SZ];
225613a2f6bSGordon Ross 		uint32_t h_type;
226613a2f6bSGordon Ross 		uint32_t h_flags;
227613a2f6bSGordon Ross 		struct sec_buf h_cldom;
228613a2f6bSGordon Ross 		struct sec_buf h_wksta;
229613a2f6bSGordon Ross 	} hdr;
230613a2f6bSGordon Ross 	struct mbdata mb2;	/* 2nd part */
231613a2f6bSGordon Ross 	int err;
232613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
233613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
234613a2f6bSGordon Ross 
23502d09e03SGordon Ross 	if ((err = mb_init(&mb2)) != 0)
236613a2f6bSGordon Ross 		return (err);
237613a2f6bSGordon Ross 	mb2.mb_count = sizeof (hdr);
238613a2f6bSGordon Ross 
239613a2f6bSGordon Ross 	/*
24085e6b674SGordon Ross 	 * The initial negotiation flags represent the union of all
24185e6b674SGordon Ross 	 * options we support.  The server selects from these.
24285e6b674SGordon Ross 	 * See: [MS-NLMP 2.2.2.5 NEGOTIATE]
243613a2f6bSGordon Ross 	 */
244613a2f6bSGordon Ross 	ssp_st->ss_flags =
24585e6b674SGordon Ross 	    NTLMSSP_NEGOTIATE_UNICODE |
24685e6b674SGordon Ross 	    NTLMSSP_NEGOTIATE_OEM |
247613a2f6bSGordon Ross 	    NTLMSSP_REQUEST_TARGET |
24885e6b674SGordon Ross 	    NTLMSSP_NEGOTIATE_SIGN |
24985e6b674SGordon Ross 	    NTLMSSP_NEGOTIATE_SEAL |
25085e6b674SGordon Ross 	    /* NTLMSSP_NEGOTIATE_LM_KEY (never) */
251613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_NTLM |
252*40c0e231SGordon Ross 	    NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
253*40c0e231SGordon Ross 	    NTLMSSP_NEGOTIATE_ESS |
254613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_128 |
25585e6b674SGordon Ross 	    NTLMSSP_NEGOTIATE_KEY_EXCH |
256613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_56;
257613a2f6bSGordon Ross 
258*40c0e231SGordon Ross 	if ((ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED) == 0)
259*40c0e231SGordon Ross 		ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
260613a2f6bSGordon Ross 
261613a2f6bSGordon Ross 	bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
26285e6b674SGordon Ross 	hdr.h_type = NTLMSSP_MSGTYPE_NEGOTIATE;
263613a2f6bSGordon Ross 	hdr.h_flags = ssp_st->ss_flags;
264613a2f6bSGordon Ross 
265613a2f6bSGordon Ross 	/*
26685e6b674SGordon Ross 	 * We could put the client domain, client name strings
26785e6b674SGordon Ross 	 * here, (always in OEM format, upper-case), and set
26885e6b674SGordon Ross 	 * NTLMSSP_NEGOTIATE_OEM_..._SUPPLIED, but Windows
26985e6b674SGordon Ross 	 * leaves these NULL so let's do the same.
270613a2f6bSGordon Ross 	 */
27185e6b674SGordon Ross 	(void) mb_put_sb_string(&mb2, &hdr.h_cldom, NULL, 0);
27285e6b674SGordon Ross 	(void) mb_put_sb_string(&mb2, &hdr.h_wksta, NULL, 0);
273613a2f6bSGordon Ross 
274613a2f6bSGordon Ross 	/*
275613a2f6bSGordon Ross 	 * Marshal the header (in LE order)
276613a2f6bSGordon Ross 	 * then concatenate the 2nd part.
277613a2f6bSGordon Ross 	 */
27802d09e03SGordon Ross 	(void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
279613a2f6bSGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_type);
280613a2f6bSGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_flags);
281613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_cldom);
282613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
283613a2f6bSGordon Ross 
284613a2f6bSGordon Ross 	err = mb_put_mbuf(out_mb, mb2.mb_top);
285613a2f6bSGordon Ross 
286613a2f6bSGordon Ross 	return (err);
287613a2f6bSGordon Ross }
288613a2f6bSGordon Ross 
289613a2f6bSGordon Ross /*
290613a2f6bSGordon Ross  * Parse a Type 2 message
291613a2f6bSGordon Ross  */
292613a2f6bSGordon Ross int
ntlmssp_get_type2(struct ssp_ctx * sp,struct mbdata * in_mb)293613a2f6bSGordon Ross ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
294613a2f6bSGordon Ross {
295613a2f6bSGordon Ross 	struct type2hdr {
296613a2f6bSGordon Ross 		char h_id[ID_SZ];
297613a2f6bSGordon Ross 		uint32_t h_type;
298613a2f6bSGordon Ross 		struct sec_buf h_target_name;
299613a2f6bSGordon Ross 		uint32_t h_flags;
300613a2f6bSGordon Ross 		uint8_t h_challenge[8];
301613a2f6bSGordon Ross 		uint32_t h_context[2];		/* optional */
302613a2f6bSGordon Ross 		struct sec_buf h_target_info;	/* optional */
303613a2f6bSGordon Ross 	} hdr;
304613a2f6bSGordon Ross 	struct mbdata top_mb, tmp_mb;
305613a2f6bSGordon Ross 	struct mbuf *m;
306613a2f6bSGordon Ross 	int err, uc;
307613a2f6bSGordon Ross 	int min_hdr_sz = offsetof(struct type2hdr, h_context);
308613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
309613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
310613a2f6bSGordon Ross 	char *buf = NULL;
311613a2f6bSGordon Ross 
312613a2f6bSGordon Ross 	if (m_totlen(in_mb->mb_top) < min_hdr_sz) {
313613a2f6bSGordon Ross 		err = EBADRPC;
314613a2f6bSGordon Ross 		goto out;
315613a2f6bSGordon Ross 	}
316613a2f6bSGordon Ross 
317613a2f6bSGordon Ross 	/*
318613a2f6bSGordon Ross 	 * Save the mbdata pointers before we consume anything.
319613a2f6bSGordon Ross 	 * Careful to NOT free this (would be dup. free)
320613a2f6bSGordon Ross 	 * We use this below to find data based on offsets
321613a2f6bSGordon Ross 	 * from the start of the header.
322613a2f6bSGordon Ross 	 */
323613a2f6bSGordon Ross 	top_mb = *in_mb;
324613a2f6bSGordon Ross 
325613a2f6bSGordon Ross 	/* Parse the fixed size header stuff. */
326613a2f6bSGordon Ross 	bzero(&hdr, sizeof (hdr));
32702d09e03SGordon Ross 	(void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
32802d09e03SGordon Ross 	(void) md_get_uint32le(in_mb, &hdr.h_type);
32985e6b674SGordon Ross 	if (hdr.h_type != NTLMSSP_MSGTYPE_CHALLENGE) {
330613a2f6bSGordon Ross 		err = EPROTO;
331613a2f6bSGordon Ross 		goto out;
332613a2f6bSGordon Ross 	}
33302d09e03SGordon Ross 	(void) md_get_sb_hdr(in_mb, &hdr.h_target_name);
33402d09e03SGordon Ross 	(void) md_get_uint32le(in_mb, &hdr.h_flags);
33502d09e03SGordon Ross 	(void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM);
336613a2f6bSGordon Ross 
337613a2f6bSGordon Ross 	/*
33885e6b674SGordon Ross 	 * Save flags, server challenge for later.
339613a2f6bSGordon Ross 	 */
340613a2f6bSGordon Ross 	ssp_st->ss_flags = hdr.h_flags;
34185e6b674SGordon Ross 	bcopy(&hdr.h_challenge, ctx->ct_srv_chal, NTLM_CHAL_SZ);
34285e6b674SGordon Ross 
34385e6b674SGordon Ross 	/*
34485e6b674SGordon Ross 	 * Turn off flags that might have been given but
34585e6b674SGordon Ross 	 * that we don't want to send with authenticate.
34685e6b674SGordon Ross 	 */
347613a2f6bSGordon Ross 	uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
34885e6b674SGordon Ross 	ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_VERSION;
349613a2f6bSGordon Ross 
350613a2f6bSGordon Ross 	/*
351613a2f6bSGordon Ross 	 * Now find out if the optional parts are there.
352613a2f6bSGordon Ross 	 */
353613a2f6bSGordon Ross 	if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) &&
354613a2f6bSGordon Ross 	    (hdr.h_target_name.sb_offset >= sizeof (hdr))) {
35502d09e03SGordon Ross 		(void) md_get_uint32le(in_mb, &hdr.h_context[0]);
35602d09e03SGordon Ross 		(void) md_get_uint32le(in_mb, &hdr.h_context[1]);
35702d09e03SGordon Ross 		(void) md_get_sb_hdr(in_mb, &hdr.h_target_info);
358613a2f6bSGordon Ross 	}
359613a2f6bSGordon Ross 
360613a2f6bSGordon Ross 	/*
36185e6b674SGordon Ross 	 * Get the target name string.  (Server name or
36285e6b674SGordon Ross 	 * Primary domain name.)  First get a copy of the
36385e6b674SGordon Ross 	 * data from the offset/length indicated in the
364613a2f6bSGordon Ross 	 * security buffer header; then parse the string.
365613a2f6bSGordon Ross 	 */
36602d09e03SGordon Ross 	err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m);
367613a2f6bSGordon Ross 	if (err)
368613a2f6bSGordon Ross 		goto out;
369613a2f6bSGordon Ross 	mb_initm(&tmp_mb, m);
37002d09e03SGordon Ross 	err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc);
371613a2f6bSGordon Ross 	mb_done(&tmp_mb);
372613a2f6bSGordon Ross 
373613a2f6bSGordon Ross 	/*
374613a2f6bSGordon Ross 	 * Get the target info blob, if present.
375613a2f6bSGordon Ross 	 */
376613a2f6bSGordon Ross 	if (hdr.h_target_info.sb_offset >= sizeof (hdr)) {
37702d09e03SGordon Ross 		err = md_get_sb_data(&top_mb, &hdr.h_target_info,
378613a2f6bSGordon Ross 		    &ssp_st->ss_target_info);
379613a2f6bSGordon Ross 	}
380613a2f6bSGordon Ross 
381613a2f6bSGordon Ross out:
382613a2f6bSGordon Ross 	if (buf != NULL)
383613a2f6bSGordon Ross 		free(buf);
384613a2f6bSGordon Ross 
385613a2f6bSGordon Ross 	return (err);
386613a2f6bSGordon Ross }
387613a2f6bSGordon Ross 
388613a2f6bSGordon Ross /*
389613a2f6bSGordon Ross  * Build a Type 3 message
390613a2f6bSGordon Ross  *
391613a2f6bSGordon Ross  * This message has a header section containing offsets to
392613a2f6bSGordon Ross  * data later in the message.  We use the common trick of
393613a2f6bSGordon Ross  * building it in two parts and then concatenatening.
394613a2f6bSGordon Ross  */
395613a2f6bSGordon Ross int
ntlmssp_put_type3(struct ssp_ctx * sp,struct mbdata * out_mb)396613a2f6bSGordon Ross ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
397613a2f6bSGordon Ross {
398613a2f6bSGordon Ross 	struct type3hdr {
399613a2f6bSGordon Ross 		char h_id[ID_SZ];
400613a2f6bSGordon Ross 		uint32_t h_type;
401613a2f6bSGordon Ross 		struct sec_buf h_lm_resp;
402613a2f6bSGordon Ross 		struct sec_buf h_nt_resp;
403613a2f6bSGordon Ross 		struct sec_buf h_domain;
404613a2f6bSGordon Ross 		struct sec_buf h_user;
405613a2f6bSGordon Ross 		struct sec_buf h_wksta;
40615359501SGordon Ross 		struct sec_buf h_ssn_key;
40715359501SGordon Ross 		uint32_t h_flags;
40885e6b674SGordon Ross 		/* Version struct (ommitted) */
40985e6b674SGordon Ross 		uchar_t h_mic[NTLM_HASH_SZ];
410613a2f6bSGordon Ross 	} hdr;
41115359501SGordon Ross 	struct mbdata lm_mbc;	/* LM response */
41215359501SGordon Ross 	struct mbdata nt_mbc;	/* NT response */
41315359501SGordon Ross 	struct mbdata ti_mbc;	/* target info */
41485e6b674SGordon Ross 	struct mbdata ek_mbc;	/* encrypted session key */
41515359501SGordon Ross 	struct mbdata mb2;	/* payload */
416613a2f6bSGordon Ross 	int err, uc;
417613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
418613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
41985e6b674SGordon Ross 	uchar_t *pmic;
420613a2f6bSGordon Ross 
42115359501SGordon Ross 	bzero(&hdr, sizeof (hdr));
422613a2f6bSGordon Ross 	bzero(&lm_mbc, sizeof (lm_mbc));
423613a2f6bSGordon Ross 	bzero(&nt_mbc, sizeof (nt_mbc));
424613a2f6bSGordon Ross 	bzero(&ti_mbc, sizeof (ti_mbc));
42585e6b674SGordon Ross 	bzero(&ek_mbc, sizeof (ek_mbc));
426613a2f6bSGordon Ross 	bzero(&mb2, sizeof (mb2));
427613a2f6bSGordon Ross 
428613a2f6bSGordon Ross 	/*
42915359501SGordon Ross 	 * Fill in the NTLMSSP header, etc.
430613a2f6bSGordon Ross 	 */
43102d09e03SGordon Ross 	if ((err = mb_init(&mb2)) != 0)
432613a2f6bSGordon Ross 		goto out;
433613a2f6bSGordon Ross 	mb2.mb_count = sizeof (hdr);
434613a2f6bSGordon Ross 	uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
435613a2f6bSGordon Ross 
436613a2f6bSGordon Ross 	bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
43785e6b674SGordon Ross 	hdr.h_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
43815359501SGordon Ross 	hdr.h_flags = ssp_st->ss_flags;
439613a2f6bSGordon Ross 
440613a2f6bSGordon Ross 	/*
44185e6b674SGordon Ross 	 * Put the NTLMv2/LMv2 or NTLM/LM (v1) responses,
44285e6b674SGordon Ross 	 * and compute the session key, etc.
443613a2f6bSGordon Ross 	 */
44485e6b674SGordon Ross 	if (ctx->ct_authflags & SMB_AT_ANON) {
44585e6b674SGordon Ross 		/*
44685e6b674SGordon Ross 		 * We're setting up a NULL session, meaning
44785e6b674SGordon Ross 		 * the lm_mbc, nt_mbc parts remain empty.
448*40c0e231SGordon Ross 		 * Let's add the "anon" flag (hint), and
449*40c0e231SGordon Ross 		 * as we have no OWF hashes, we can't use
450*40c0e231SGordon Ross 		 * "extended session security" (_ESS).
451*40c0e231SGordon Ross 		 * The SessionBaseKey is all zeros, so
452*40c0e231SGordon Ross 		 * the KeyExchangeKey is too.  Otherwise
453*40c0e231SGordon Ross 		 * this is like NTLMv2/LMv2
45485e6b674SGordon Ross 		 */
455*40c0e231SGordon Ross 		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_NULL_SESSION;
456*40c0e231SGordon Ross 		ssp_st->ss_flags &= ~NTLMSSP_NEGOTIATE_ESS;
457*40c0e231SGordon Ross 		hdr.h_flags = ssp_st->ss_flags;
45885e6b674SGordon Ross 		err = 0;
459*40c0e231SGordon Ross 		/* KeyExchangeKey = SessionBaseKey = (zeros) */
460*40c0e231SGordon Ross 		memset(ssp_st->ss_ssnkey, 0, NTLM_HASH_SZ);
461*40c0e231SGordon Ross 		memset(ssp_st->ss_kxkey, 0, NTLM_HASH_SZ);
46285e6b674SGordon Ross 	} else if (ctx->ct_authflags & SMB_AT_NTLM2) {
46385e6b674SGordon Ross 		/*
46485e6b674SGordon Ross 		 * Doing NTLMv2/LMv2
46585e6b674SGordon Ross 		 */
466613a2f6bSGordon Ross 		err = ntlm_build_target_info(ctx,
467613a2f6bSGordon Ross 		    ssp_st->ss_target_info, &ti_mbc);
468613a2f6bSGordon Ross 		if (err)
469613a2f6bSGordon Ross 			goto out;
470613a2f6bSGordon Ross 		err = ntlm_put_v2_responses(ctx, &ti_mbc,
471*40c0e231SGordon Ross 		    &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
47285e6b674SGordon Ross 		if (err)
47385e6b674SGordon Ross 			goto out;
474*40c0e231SGordon Ross 		/* KeyExchangeKey = SessionBaseKey (v2) */
475*40c0e231SGordon Ross 		memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
476*40c0e231SGordon Ross 	} else if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_ESS) {
47785e6b674SGordon Ross 		/*
47885e6b674SGordon Ross 		 * Doing NTLM ("v1x") which is NTLM with
47985e6b674SGordon Ross 		 * "Extended Session Security"
48085e6b674SGordon Ross 		 */
48185e6b674SGordon Ross 		err = ntlm_put_v1x_responses(ctx,
482*40c0e231SGordon Ross 		    &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
48385e6b674SGordon Ross 		if (err)
48485e6b674SGordon Ross 			goto out;
485*40c0e231SGordon Ross 		/*
486*40c0e231SGordon Ross 		 * "v1x computes the KeyExchangeKey from both the
487*40c0e231SGordon Ross 		 * server and client nonce and (v1) SessionBaseKey.
488*40c0e231SGordon Ross 		 */
489*40c0e231SGordon Ross 		ntlm2_kxkey(ctx, &lm_mbc, ssp_st->ss_ssnkey,
490*40c0e231SGordon Ross 		    ssp_st->ss_kxkey);
491613a2f6bSGordon Ross 	} else {
49285e6b674SGordon Ross 		/*
49385e6b674SGordon Ross 		 * Doing plain old NTLM (and LM if enabled)
49485e6b674SGordon Ross 		 */
495613a2f6bSGordon Ross 		err = ntlm_put_v1_responses(ctx,
496*40c0e231SGordon Ross 		    &lm_mbc, &nt_mbc, ssp_st->ss_ssnkey);
49785e6b674SGordon Ross 		if (err)
49885e6b674SGordon Ross 			goto out;
499*40c0e231SGordon Ross 		/* KeyExchangeKey = SessionBaseKey (v1) */
500*40c0e231SGordon Ross 		memcpy(ssp_st->ss_kxkey, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
50185e6b674SGordon Ross 	}
50285e6b674SGordon Ross 
50385e6b674SGordon Ross 	/*
504*40c0e231SGordon Ross 	 * Compute the "ExportedSessionKey" and (possibly) the
505*40c0e231SGordon Ross 	 * "EncryptedRandomSesionKey". [MS-NLMP 3.1.5.1.2]
50685e6b674SGordon Ross 	 */
50785e6b674SGordon Ross 	if (ssp_st->ss_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
508*40c0e231SGordon Ross 		err = ntlm_rand_ssn_key(ssp_st, &ek_mbc);
50985e6b674SGordon Ross 		if (err)
51085e6b674SGordon Ross 			goto out;
51185e6b674SGordon Ross 	} else {
51285e6b674SGordon Ross 		/* ExportedSessionKey is the KeyExchangeKey */
513*40c0e231SGordon Ross 		memcpy(ssp_st->ss_ssnkey, ssp_st->ss_kxkey, NTLM_HASH_SZ);
51485e6b674SGordon Ross 		/* EncryptedRandomSessionKey remains NULL */
515613a2f6bSGordon Ross 	}
516613a2f6bSGordon Ross 
517613a2f6bSGordon Ross 	err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
518613a2f6bSGordon Ross 	lm_mbc.mb_top = NULL; /* consumed */
519613a2f6bSGordon Ross 	if (err)
520613a2f6bSGordon Ross 		goto out;
521613a2f6bSGordon Ross 	err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
522613a2f6bSGordon Ross 	nt_mbc.mb_top = NULL; /* consumed */
523613a2f6bSGordon Ross 	if (err)
524613a2f6bSGordon Ross 		goto out;
525613a2f6bSGordon Ross 
526613a2f6bSGordon Ross 	/*
527613a2f6bSGordon Ross 	 * Put the "target" (domain), user, workstation
528613a2f6bSGordon Ross 	 */
52915359501SGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc);
530613a2f6bSGordon Ross 	if (err)
531613a2f6bSGordon Ross 		goto out;
53215359501SGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc);
533613a2f6bSGordon Ross 	if (err)
534613a2f6bSGordon Ross 		goto out;
53515359501SGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_wksta, ctx->ct_locname, uc);
536613a2f6bSGordon Ross 	if (err)
537613a2f6bSGordon Ross 		goto out;
538613a2f6bSGordon Ross 
53915359501SGordon Ross 	/*
54085e6b674SGordon Ross 	 * Put the "Encrypted Random Session Key", if any.
54185e6b674SGordon Ross 	 * (ek_mbc.mb_top may be NULL)
54215359501SGordon Ross 	 */
54385e6b674SGordon Ross 	err = mb_put_sb_data(&mb2, &hdr.h_ssn_key, ek_mbc.mb_top);
54485e6b674SGordon Ross 	ek_mbc.mb_top = NULL; /* consumed (if any) */
54585e6b674SGordon Ross 	if (err)
54685e6b674SGordon Ross 		goto out;
54715359501SGordon Ross 
548613a2f6bSGordon Ross 	/*
549613a2f6bSGordon Ross 	 * Marshal the header (in LE order)
550613a2f6bSGordon Ross 	 * then concatenate the 2nd part.
551613a2f6bSGordon Ross 	 */
55202d09e03SGordon Ross 	(void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
553613a2f6bSGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_type);
554613a2f6bSGordon Ross 
555613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp);
556613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp);
557613a2f6bSGordon Ross 
558613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_domain);
559613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_user);
560613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
561613a2f6bSGordon Ross 
56215359501SGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key);
56315359501SGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_flags);
56415359501SGordon Ross 
56585e6b674SGordon Ross 	/* Put zeros for the MIC - filled in later */
56685e6b674SGordon Ross 	pmic = mb_reserve(out_mb, NTLM_HASH_SZ);
56785e6b674SGordon Ross 
56885e6b674SGordon Ross 	/* Put the payload. */
569613a2f6bSGordon Ross 	err = mb_put_mbuf(out_mb, mb2.mb_top);
570613a2f6bSGordon Ross 	mb2.mb_top = NULL; /* consumed */
571613a2f6bSGordon Ross 
57285e6b674SGordon Ross 	/*
57385e6b674SGordon Ross 	 * Compute the MIC and stuff that in...
57485e6b674SGordon Ross 	 * The MIC is apparently optional.
57585e6b674SGordon Ross 	 */
57685e6b674SGordon Ross 	(void) pmic;
57785e6b674SGordon Ross 
578613a2f6bSGordon Ross out:
579613a2f6bSGordon Ross 	mb_done(&mb2);
580613a2f6bSGordon Ross 	mb_done(&lm_mbc);
581613a2f6bSGordon Ross 	mb_done(&nt_mbc);
58215359501SGordon Ross 	mb_done(&ti_mbc);
58385e6b674SGordon Ross 	mb_done(&ek_mbc);
58485e6b674SGordon Ross 
58585e6b674SGordon Ross 	return (err);
58685e6b674SGordon Ross }
58785e6b674SGordon Ross 
58885e6b674SGordon Ross /*
58985e6b674SGordon Ross  * Helper for ntlmssp_put_type3 when doing key exchange.
59085e6b674SGordon Ross  *
59185e6b674SGordon Ross  * "ExportedSessionKey" is what we give to the "application"
59285e6b674SGordon Ross  * layer, which in here means the MAC key for SMB signing.
59385e6b674SGordon Ross  * With "key exchange", we replace the ExportedSessionKey
59485e6b674SGordon Ross  * with random data and send that (encrypted) to the peer.
59585e6b674SGordon Ross  */
59685e6b674SGordon Ross static int
ntlm_rand_ssn_key(ntlmssp_state_t * ssp_st,struct mbdata * ek_mbp)59785e6b674SGordon Ross ntlm_rand_ssn_key(
59885e6b674SGordon Ross 	ntlmssp_state_t *ssp_st,
59985e6b674SGordon Ross 	struct mbdata *ek_mbp)
60085e6b674SGordon Ross {
60185e6b674SGordon Ross 
60285e6b674SGordon Ross 	uchar_t *encr_ssn_key;
60385e6b674SGordon Ross 	int err;
60485e6b674SGordon Ross 
60585e6b674SGordon Ross 	if ((err = mb_init(ek_mbp)) != 0)
60685e6b674SGordon Ross 		return (err);
60785e6b674SGordon Ross 	encr_ssn_key = mb_reserve(ek_mbp, NTLM_HASH_SZ);
60885e6b674SGordon Ross 
60985e6b674SGordon Ross 	/* Set "ExportedSessionKey to NONCE(16) */
610*40c0e231SGordon Ross 	(void) smb_get_urandom(ssp_st->ss_ssnkey, NTLM_HASH_SZ);
61185e6b674SGordon Ross 
61285e6b674SGordon Ross 	/* Set "EncryptedRandomSessionKey" to RC4(...) */
61385e6b674SGordon Ross 	err = smb_encrypt_RC4(encr_ssn_key, NTLM_HASH_SZ,
61485e6b674SGordon Ross 	    ssp_st->ss_kxkey, NTLM_HASH_SZ,
615*40c0e231SGordon Ross 	    ssp_st->ss_ssnkey, NTLM_HASH_SZ);
616613a2f6bSGordon Ross 
617613a2f6bSGordon Ross 	return (err);
618613a2f6bSGordon Ross }
619613a2f6bSGordon Ross 
620613a2f6bSGordon Ross /*
621613a2f6bSGordon Ross  * ntlmssp_final
622613a2f6bSGordon Ross  *
623613a2f6bSGordon Ross  * Called after successful authentication.
624*40c0e231SGordon Ross  * Save the session key.
625613a2f6bSGordon Ross  */
626613a2f6bSGordon Ross int
ntlmssp_final(struct ssp_ctx * sp)627613a2f6bSGordon Ross ntlmssp_final(struct ssp_ctx *sp)
628613a2f6bSGordon Ross {
629613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
630*40c0e231SGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
631613a2f6bSGordon Ross 	int err = 0;
632613a2f6bSGordon Ross 
633613a2f6bSGordon Ross 	/*
634*40c0e231SGordon Ross 	 * Update/save the session key.
635613a2f6bSGordon Ross 	 */
636*40c0e231SGordon Ross 	if (ctx->ct_ssnkey_buf != NULL) {
637*40c0e231SGordon Ross 		free(ctx->ct_ssnkey_buf);
638*40c0e231SGordon Ross 		ctx->ct_ssnkey_buf = NULL;
639613a2f6bSGordon Ross 	}
640*40c0e231SGordon Ross 	ctx->ct_ssnkey_buf = malloc(NTLM_HASH_SZ);
641*40c0e231SGordon Ross 	if (ctx->ct_ssnkey_buf == NULL) {
642*40c0e231SGordon Ross 		err = ENOMEM;
643*40c0e231SGordon Ross 		goto out;
644*40c0e231SGordon Ross 	}
645*40c0e231SGordon Ross 	ctx->ct_ssnkey_len = NTLM_HASH_SZ;
646*40c0e231SGordon Ross 	memcpy(ctx->ct_ssnkey_buf, ssp_st->ss_ssnkey, NTLM_HASH_SZ);
647613a2f6bSGordon Ross 
648613a2f6bSGordon Ross out:
649613a2f6bSGordon Ross 	return (err);
650613a2f6bSGordon Ross }
651613a2f6bSGordon Ross 
652613a2f6bSGordon Ross /*
653613a2f6bSGordon Ross  * ntlmssp_next_token
654613a2f6bSGordon Ross  *
655613a2f6bSGordon Ross  * See ssp.c: ssp_ctx_next_token
656613a2f6bSGordon Ross  */
657613a2f6bSGordon Ross int
ntlmssp_next_token(struct ssp_ctx * sp,struct mbdata * in_mb,struct mbdata * out_mb)658613a2f6bSGordon Ross ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
659613a2f6bSGordon Ross 	struct mbdata *out_mb)
660613a2f6bSGordon Ross {
661613a2f6bSGordon Ross 	int err;
662613a2f6bSGordon Ross 
663613a2f6bSGordon Ross 	if (out_mb == NULL) {
664613a2f6bSGordon Ross 		/* final call on successful auth. */
665613a2f6bSGordon Ross 		err = ntlmssp_final(sp);
666613a2f6bSGordon Ross 		goto out;
667613a2f6bSGordon Ross 	}
668613a2f6bSGordon Ross 
669613a2f6bSGordon Ross 	/* Will build an ouptut token. */
67002d09e03SGordon Ross 	err = mb_init(out_mb);
671613a2f6bSGordon Ross 	if (err)
672613a2f6bSGordon Ross 		goto out;
673613a2f6bSGordon Ross 
674613a2f6bSGordon Ross 	/*
675613a2f6bSGordon Ross 	 * When called with in_mb == NULL, it means
676613a2f6bSGordon Ross 	 * this is the first call for this session,
677613a2f6bSGordon Ross 	 * so put a Type 1 (initialize) token.
678613a2f6bSGordon Ross 	 */
679613a2f6bSGordon Ross 	if (in_mb == NULL) {
680613a2f6bSGordon Ross 		err = ntlmssp_put_type1(sp, out_mb);
681613a2f6bSGordon Ross 		goto out;
682613a2f6bSGordon Ross 	}
683613a2f6bSGordon Ross 
684613a2f6bSGordon Ross 	/*
685613a2f6bSGordon Ross 	 * This is not the first call, so
686613a2f6bSGordon Ross 	 * parse the response token we received.
687613a2f6bSGordon Ross 	 * It should be a Type 2 (challenge).
688613a2f6bSGordon Ross 	 * Then put a Type 3 (authenticate)
689613a2f6bSGordon Ross 	 */
690613a2f6bSGordon Ross 	err = ntlmssp_get_type2(sp, in_mb);
691613a2f6bSGordon Ross 	if (err)
692613a2f6bSGordon Ross 		goto out;
693613a2f6bSGordon Ross 
694613a2f6bSGordon Ross 	err = ntlmssp_put_type3(sp, out_mb);
695613a2f6bSGordon Ross 
696613a2f6bSGordon Ross out:
697613a2f6bSGordon Ross 	if (err)
698613a2f6bSGordon Ross 		DPRINT("ret: %d", err);
699613a2f6bSGordon Ross 	return (err);
700613a2f6bSGordon Ross }
701613a2f6bSGordon Ross 
702613a2f6bSGordon Ross /*
703613a2f6bSGordon Ross  * ntlmssp_ctx_destroy
704613a2f6bSGordon Ross  *
705613a2f6bSGordon Ross  * Destroy mechanism-specific data.
706613a2f6bSGordon Ross  */
707613a2f6bSGordon Ross void
ntlmssp_destroy(struct ssp_ctx * sp)708613a2f6bSGordon Ross ntlmssp_destroy(struct ssp_ctx *sp)
709613a2f6bSGordon Ross {
710613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st;
711613a2f6bSGordon Ross 
712613a2f6bSGordon Ross 	ssp_st = sp->sp_private;
713613a2f6bSGordon Ross 	if (ssp_st != NULL) {
714613a2f6bSGordon Ross 		sp->sp_private = NULL;
715613a2f6bSGordon Ross 		free(ssp_st->ss_target_name);
716613a2f6bSGordon Ross 		m_freem(ssp_st->ss_target_info);
717613a2f6bSGordon Ross 		free(ssp_st);
718613a2f6bSGordon Ross 	}
719613a2f6bSGordon Ross }
720613a2f6bSGordon Ross 
721613a2f6bSGordon Ross /*
722613a2f6bSGordon Ross  * ntlmssp_init_clnt
723613a2f6bSGordon Ross  *
724613a2f6bSGordon Ross  * Initialize a new NTLMSSP client context.
725613a2f6bSGordon Ross  */
726613a2f6bSGordon Ross int
ntlmssp_init_client(struct ssp_ctx * sp)727613a2f6bSGordon Ross ntlmssp_init_client(struct ssp_ctx *sp)
728613a2f6bSGordon Ross {
729613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st;
730*40c0e231SGordon Ross 	smb_ctx_t *ctx = sp->smb_ctx;
731613a2f6bSGordon Ross 
732*40c0e231SGordon Ross 	if ((ctx->ct_authflags &
73385e6b674SGordon Ross 	    (SMB_AT_NTLM2 | SMB_AT_NTLM1 | SMB_AT_ANON)) == 0) {
734613a2f6bSGordon Ross 		DPRINT("No NTLM authflags");
73585e6b674SGordon Ross 		return (EINVAL);
736613a2f6bSGordon Ross 	}
737613a2f6bSGordon Ross 
738*40c0e231SGordon Ross 	/* Get the client nonce. */
739*40c0e231SGordon Ross 	(void) smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
740*40c0e231SGordon Ross 
741613a2f6bSGordon Ross 	ssp_st = calloc(1, sizeof (*ssp_st));
742613a2f6bSGordon Ross 	if (ssp_st == NULL)
743613a2f6bSGordon Ross 		return (ENOMEM);
744613a2f6bSGordon Ross 
745613a2f6bSGordon Ross 	sp->sp_nexttok = ntlmssp_next_token;
746613a2f6bSGordon Ross 	sp->sp_destroy = ntlmssp_destroy;
747613a2f6bSGordon Ross 	sp->sp_private = ssp_st;
748613a2f6bSGordon Ross 
749613a2f6bSGordon Ross 	return (0);
750613a2f6bSGordon Ross }
751