xref: /titanic_44/usr/src/lib/libsmbfs/smb/ntlmssp.c (revision 02d09e03eb27f3a2dc299de704e45dae5173f43f)
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