xref: /titanic_44/usr/src/lib/libsmbfs/smb/ntlmssp.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
1*613a2f6bSGordon Ross /*
2*613a2f6bSGordon Ross  * CDDL HEADER START
3*613a2f6bSGordon Ross  *
4*613a2f6bSGordon Ross  * The contents of this file are subject to the terms of the
5*613a2f6bSGordon Ross  * Common Development and Distribution License (the "License").
6*613a2f6bSGordon Ross  * You may not use this file except in compliance with the License.
7*613a2f6bSGordon Ross  *
8*613a2f6bSGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*613a2f6bSGordon Ross  * or http://www.opensolaris.org/os/licensing.
10*613a2f6bSGordon Ross  * See the License for the specific language governing permissions
11*613a2f6bSGordon Ross  * and limitations under the License.
12*613a2f6bSGordon Ross  *
13*613a2f6bSGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14*613a2f6bSGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*613a2f6bSGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16*613a2f6bSGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17*613a2f6bSGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18*613a2f6bSGordon Ross  *
19*613a2f6bSGordon Ross  * CDDL HEADER END
20*613a2f6bSGordon Ross  */
21*613a2f6bSGordon Ross 
22*613a2f6bSGordon Ross /*
23*613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*613a2f6bSGordon Ross  * Use is subject to license terms.
25*613a2f6bSGordon Ross  */
26*613a2f6bSGordon Ross 
27*613a2f6bSGordon Ross /*
28*613a2f6bSGordon Ross  * NT Lan Manager Security Support Provider (NTLMSSP)
29*613a2f6bSGordon Ross  *
30*613a2f6bSGordon Ross  * Based on information from the "Davenport NTLM" page:
31*613a2f6bSGordon Ross  * http://davenport.sourceforge.net/ntlm.html
32*613a2f6bSGordon Ross  */
33*613a2f6bSGordon Ross 
34*613a2f6bSGordon Ross 
35*613a2f6bSGordon Ross #include <errno.h>
36*613a2f6bSGordon Ross #include <stdio.h>
37*613a2f6bSGordon Ross #include <stddef.h>
38*613a2f6bSGordon Ross #include <stdlib.h>
39*613a2f6bSGordon Ross #include <unistd.h>
40*613a2f6bSGordon Ross #include <strings.h>
41*613a2f6bSGordon Ross #include <netdb.h>
42*613a2f6bSGordon Ross #include <libintl.h>
43*613a2f6bSGordon Ross #include <xti.h>
44*613a2f6bSGordon Ross #include <assert.h>
45*613a2f6bSGordon Ross 
46*613a2f6bSGordon Ross #include <sys/types.h>
47*613a2f6bSGordon Ross #include <sys/time.h>
48*613a2f6bSGordon Ross #include <sys/byteorder.h>
49*613a2f6bSGordon Ross #include <sys/socket.h>
50*613a2f6bSGordon Ross #include <sys/fcntl.h>
51*613a2f6bSGordon Ross 
52*613a2f6bSGordon Ross #include <netinet/in.h>
53*613a2f6bSGordon Ross #include <netinet/tcp.h>
54*613a2f6bSGordon Ross #include <arpa/inet.h>
55*613a2f6bSGordon Ross 
56*613a2f6bSGordon Ross #include <netsmb/smb.h>
57*613a2f6bSGordon Ross #include <netsmb/smb_lib.h>
58*613a2f6bSGordon Ross #include <netsmb/mchain.h>
59*613a2f6bSGordon Ross 
60*613a2f6bSGordon Ross #include "private.h"
61*613a2f6bSGordon Ross #include "charsets.h"
62*613a2f6bSGordon Ross #include "spnego.h"
63*613a2f6bSGordon Ross #include "derparse.h"
64*613a2f6bSGordon Ross #include "ssp.h"
65*613a2f6bSGordon Ross #include "ntlm.h"
66*613a2f6bSGordon Ross #include "ntlmssp.h"
67*613a2f6bSGordon Ross 
68*613a2f6bSGordon Ross typedef struct ntlmssp_state {
69*613a2f6bSGordon Ross 	uint32_t ss_flags;
70*613a2f6bSGordon Ross 	char *ss_target_name;
71*613a2f6bSGordon Ross 	struct mbuf *ss_target_info;
72*613a2f6bSGordon Ross } ntlmssp_state_t;
73*613a2f6bSGordon Ross 
74*613a2f6bSGordon Ross /*
75*613a2f6bSGordon Ross  * So called "security buffer".
76*613a2f6bSGordon Ross  * A lot like an RPC string.
77*613a2f6bSGordon Ross  */
78*613a2f6bSGordon Ross struct sec_buf {
79*613a2f6bSGordon Ross 	uint16_t sb_length;
80*613a2f6bSGordon Ross 	uint16_t sb_maxlen;
81*613a2f6bSGordon Ross 	uint32_t sb_offset;
82*613a2f6bSGordon Ross };
83*613a2f6bSGordon Ross #define	ID_SZ 8
84*613a2f6bSGordon Ross static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
85*613a2f6bSGordon Ross 
86*613a2f6bSGordon Ross /*
87*613a2f6bSGordon Ross  * Get a "security buffer" (header part)
88*613a2f6bSGordon Ross  */
89*613a2f6bSGordon Ross static int
90*613a2f6bSGordon Ross mb_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
91*613a2f6bSGordon Ross {
92*613a2f6bSGordon Ross 	int err;
93*613a2f6bSGordon Ross 
94*613a2f6bSGordon Ross 	(void) mb_get_uint16le(mbp, &sb->sb_length);
95*613a2f6bSGordon Ross 	(void) mb_get_uint16le(mbp, &sb->sb_maxlen);
96*613a2f6bSGordon Ross 	err = mb_get_uint32le(mbp, &sb->sb_offset);
97*613a2f6bSGordon Ross 
98*613a2f6bSGordon Ross 	return (err);
99*613a2f6bSGordon Ross }
100*613a2f6bSGordon Ross 
101*613a2f6bSGordon Ross /*
102*613a2f6bSGordon Ross  * Get a "security buffer" (data part), where
103*613a2f6bSGordon Ross  * the data is delivered as an mbuf.
104*613a2f6bSGordon Ross  */
105*613a2f6bSGordon Ross static int
106*613a2f6bSGordon Ross mb_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp)
107*613a2f6bSGordon Ross {
108*613a2f6bSGordon Ross 	struct mbdata tmp_mb;
109*613a2f6bSGordon Ross 	int err;
110*613a2f6bSGordon Ross 
111*613a2f6bSGordon Ross 	/*
112*613a2f6bSGordon Ross 	 * Setup tmp_mb to point to the start of the header.
113*613a2f6bSGordon Ross 	 * This is a dup ref - do NOT free it.
114*613a2f6bSGordon Ross 	 */
115*613a2f6bSGordon Ross 	mb_initm(&tmp_mb, mbp->mb_top);
116*613a2f6bSGordon Ross 
117*613a2f6bSGordon Ross 	/* Skip data up to the offset. */
118*613a2f6bSGordon Ross 	err = mb_get_mem(&tmp_mb, NULL, sb->sb_offset);
119*613a2f6bSGordon Ross 	if (err)
120*613a2f6bSGordon Ross 		return (err);
121*613a2f6bSGordon Ross 
122*613a2f6bSGordon Ross 	/* Get the data (as an mbuf). */
123*613a2f6bSGordon Ross 	err = mb_get_mbuf(&tmp_mb, sb->sb_maxlen, mp);
124*613a2f6bSGordon Ross 
125*613a2f6bSGordon Ross 	return (err);
126*613a2f6bSGordon Ross }
127*613a2f6bSGordon Ross 
128*613a2f6bSGordon Ross /*
129*613a2f6bSGordon Ross  * Put a "security buffer" (header part)
130*613a2f6bSGordon Ross  */
131*613a2f6bSGordon Ross static int
132*613a2f6bSGordon Ross mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
133*613a2f6bSGordon Ross {
134*613a2f6bSGordon Ross 	int err;
135*613a2f6bSGordon Ross 
136*613a2f6bSGordon Ross 	(void) mb_put_uint16le(mbp, sb->sb_length);
137*613a2f6bSGordon Ross 	(void) mb_put_uint16le(mbp, sb->sb_maxlen);
138*613a2f6bSGordon Ross 	err = mb_put_uint32le(mbp, sb->sb_offset);
139*613a2f6bSGordon Ross 
140*613a2f6bSGordon Ross 	return (err);
141*613a2f6bSGordon Ross }
142*613a2f6bSGordon Ross 
143*613a2f6bSGordon Ross /*
144*613a2f6bSGordon Ross  * Put a "security buffer" (data part), where
145*613a2f6bSGordon Ross  * the data is an mbuf.  Note: consumes m.
146*613a2f6bSGordon Ross  */
147*613a2f6bSGordon Ross static int
148*613a2f6bSGordon Ross mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
149*613a2f6bSGordon Ross {
150*613a2f6bSGordon Ross 	int cnt0, err;
151*613a2f6bSGordon Ross 
152*613a2f6bSGordon Ross 	sb->sb_offset = cnt0 = mbp->mb_count;
153*613a2f6bSGordon Ross 	err = mb_put_mbuf(mbp, m);
154*613a2f6bSGordon Ross 	sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
155*613a2f6bSGordon Ross 
156*613a2f6bSGordon Ross 	return (err);
157*613a2f6bSGordon Ross }
158*613a2f6bSGordon Ross 
159*613a2f6bSGordon Ross /*
160*613a2f6bSGordon Ross  * Put a "security buffer" (data part), where
161*613a2f6bSGordon Ross  * the data is a string (OEM or unicode).
162*613a2f6bSGordon Ross  *
163*613a2f6bSGordon Ross  * The string is NOT null terminated.
164*613a2f6bSGordon Ross  */
165*613a2f6bSGordon Ross static int
166*613a2f6bSGordon Ross mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
167*613a2f6bSGordon Ross 	const char *s, int unicode)
168*613a2f6bSGordon Ross {
169*613a2f6bSGordon Ross 	int err, trim;
170*613a2f6bSGordon Ross 	struct mbdata tmp_mb;
171*613a2f6bSGordon Ross 
172*613a2f6bSGordon Ross 	/*
173*613a2f6bSGordon Ross 	 * Put the string into a temp. mbuf,
174*613a2f6bSGordon Ross 	 * then chop off the null terminator
175*613a2f6bSGordon Ross 	 * before appending to caller's mbp.
176*613a2f6bSGordon Ross 	 */
177*613a2f6bSGordon Ross 	err = mb_init(&tmp_mb, M_MINSIZE);
178*613a2f6bSGordon Ross 	if (err)
179*613a2f6bSGordon Ross 		return (err);
180*613a2f6bSGordon Ross 	err = mb_put_dstring(&tmp_mb, s, unicode);
181*613a2f6bSGordon Ross 	if (err)
182*613a2f6bSGordon Ross 		return (err);
183*613a2f6bSGordon Ross 
184*613a2f6bSGordon Ross 	trim = (unicode) ? 2 : 1;
185*613a2f6bSGordon Ross 	if (tmp_mb.mb_cur->m_len < trim)
186*613a2f6bSGordon Ross 		return (EFAULT);
187*613a2f6bSGordon Ross 	tmp_mb.mb_cur->m_len -= trim;
188*613a2f6bSGordon Ross 
189*613a2f6bSGordon Ross 	err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
190*613a2f6bSGordon Ross 	/*
191*613a2f6bSGordon Ross 	 * Note: tmp_mb.mb_top is consumed,
192*613a2f6bSGordon Ross 	 * so do NOT free it (no mb_done)
193*613a2f6bSGordon Ross 	 */
194*613a2f6bSGordon Ross 	return (err);
195*613a2f6bSGordon Ross }
196*613a2f6bSGordon Ross 
197*613a2f6bSGordon Ross /*
198*613a2f6bSGordon Ross  * Build a Type 1 message
199*613a2f6bSGordon Ross  *
200*613a2f6bSGordon Ross  * This message has a header section containing offsets to
201*613a2f6bSGordon Ross  * data later in the message.  We use the common trick of
202*613a2f6bSGordon Ross  * building it in two parts and then concatenatening.
203*613a2f6bSGordon Ross  */
204*613a2f6bSGordon Ross int
205*613a2f6bSGordon Ross ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
206*613a2f6bSGordon Ross {
207*613a2f6bSGordon Ross 	struct type1hdr {
208*613a2f6bSGordon Ross 		char h_id[ID_SZ];
209*613a2f6bSGordon Ross 		uint32_t h_type;
210*613a2f6bSGordon Ross 		uint32_t h_flags;
211*613a2f6bSGordon Ross 		struct sec_buf h_cldom;
212*613a2f6bSGordon Ross 		struct sec_buf h_wksta;
213*613a2f6bSGordon Ross 	} hdr;
214*613a2f6bSGordon Ross 	struct mbdata mb2;	/* 2nd part */
215*613a2f6bSGordon Ross 	int err;
216*613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
217*613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
218*613a2f6bSGordon Ross 	char *ucdom = NULL;
219*613a2f6bSGordon Ross 	char *ucwks = NULL;
220*613a2f6bSGordon Ross 
221*613a2f6bSGordon Ross 	if ((err = mb_init(&mb2, M_MINSIZE)) != 0)
222*613a2f6bSGordon Ross 		return (err);
223*613a2f6bSGordon Ross 	mb2.mb_count = sizeof (hdr);
224*613a2f6bSGordon Ross 
225*613a2f6bSGordon Ross 	/*
226*613a2f6bSGordon Ross 	 * Initialize the negotiation flags, and
227*613a2f6bSGordon Ross 	 * save what we sent.  For reference:
228*613a2f6bSGordon Ross 	 * [MS-NLMP] spec. (also ntlmssp.h)
229*613a2f6bSGordon Ross 	 */
230*613a2f6bSGordon Ross 	ssp_st->ss_flags =
231*613a2f6bSGordon Ross 	    NTLMSSP_REQUEST_TARGET |
232*613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_NTLM |
233*613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_TARGET_INFO |
234*613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_128 |
235*613a2f6bSGordon Ross 	    NTLMSSP_NEGOTIATE_56;
236*613a2f6bSGordon Ross 
237*613a2f6bSGordon Ross 	if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE)
238*613a2f6bSGordon Ross 		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE;
239*613a2f6bSGordon Ross 	else
240*613a2f6bSGordon Ross 		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM;
241*613a2f6bSGordon Ross 
242*613a2f6bSGordon Ross 	if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
243*613a2f6bSGordon Ross 		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
244*613a2f6bSGordon Ross 		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
245*613a2f6bSGordon Ross 	}
246*613a2f6bSGordon Ross 
247*613a2f6bSGordon Ross 	bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
248*613a2f6bSGordon Ross 	hdr.h_type = 1; /* Type 1 */
249*613a2f6bSGordon Ross 	hdr.h_flags = ssp_st->ss_flags;
250*613a2f6bSGordon Ross 
251*613a2f6bSGordon Ross 	/*
252*613a2f6bSGordon Ross 	 * Put the client domain, client name strings.
253*613a2f6bSGordon Ross 	 * These are always in OEM format, upper-case.
254*613a2f6bSGordon Ross 	 */
255*613a2f6bSGordon Ross 	ucdom  = utf8_str_toupper(ctx->ct_domain);
256*613a2f6bSGordon Ross 	ucwks  = utf8_str_toupper(ctx->ct_locname);
257*613a2f6bSGordon Ross 	if (ucdom == NULL || ucwks == NULL) {
258*613a2f6bSGordon Ross 		err = ENOMEM;
259*613a2f6bSGordon Ross 		goto out;
260*613a2f6bSGordon Ross 	}
261*613a2f6bSGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0);
262*613a2f6bSGordon Ross 	if (err)
263*613a2f6bSGordon Ross 		goto out;
264*613a2f6bSGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0);
265*613a2f6bSGordon Ross 	if (err)
266*613a2f6bSGordon Ross 		goto out;
267*613a2f6bSGordon Ross 
268*613a2f6bSGordon Ross 	/*
269*613a2f6bSGordon Ross 	 * Marshal the header (in LE order)
270*613a2f6bSGordon Ross 	 * then concatenate the 2nd part.
271*613a2f6bSGordon Ross 	 */
272*613a2f6bSGordon Ross 	(void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ);
273*613a2f6bSGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_type);
274*613a2f6bSGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_flags);
275*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_cldom);
276*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
277*613a2f6bSGordon Ross 
278*613a2f6bSGordon Ross 	err = mb_put_mbuf(out_mb, mb2.mb_top);
279*613a2f6bSGordon Ross 
280*613a2f6bSGordon Ross out:
281*613a2f6bSGordon Ross 	free(ucdom);
282*613a2f6bSGordon Ross 	free(ucwks);
283*613a2f6bSGordon Ross 
284*613a2f6bSGordon Ross 	return (err);
285*613a2f6bSGordon Ross }
286*613a2f6bSGordon Ross 
287*613a2f6bSGordon Ross /*
288*613a2f6bSGordon Ross  * Parse a Type 2 message
289*613a2f6bSGordon Ross  */
290*613a2f6bSGordon Ross int
291*613a2f6bSGordon Ross ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
292*613a2f6bSGordon Ross {
293*613a2f6bSGordon Ross 	struct type2hdr {
294*613a2f6bSGordon Ross 		char h_id[ID_SZ];
295*613a2f6bSGordon Ross 		uint32_t h_type;
296*613a2f6bSGordon Ross 		struct sec_buf h_target_name;
297*613a2f6bSGordon Ross 		uint32_t h_flags;
298*613a2f6bSGordon Ross 		uint8_t h_challenge[8];
299*613a2f6bSGordon Ross 		uint32_t h_context[2];		/* optional */
300*613a2f6bSGordon Ross 		struct sec_buf h_target_info;	/* optional */
301*613a2f6bSGordon Ross 	} hdr;
302*613a2f6bSGordon Ross 	struct mbdata top_mb, tmp_mb;
303*613a2f6bSGordon Ross 	struct mbuf *m;
304*613a2f6bSGordon Ross 	int err, uc;
305*613a2f6bSGordon Ross 	int min_hdr_sz = offsetof(struct type2hdr, h_context);
306*613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
307*613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
308*613a2f6bSGordon Ross 	char *buf = NULL;
309*613a2f6bSGordon Ross 
310*613a2f6bSGordon Ross 	if (m_totlen(in_mb->mb_top) < min_hdr_sz) {
311*613a2f6bSGordon Ross 		err = EBADRPC;
312*613a2f6bSGordon Ross 		goto out;
313*613a2f6bSGordon Ross 	}
314*613a2f6bSGordon Ross 
315*613a2f6bSGordon Ross 	/*
316*613a2f6bSGordon Ross 	 * Save the mbdata pointers before we consume anything.
317*613a2f6bSGordon Ross 	 * Careful to NOT free this (would be dup. free)
318*613a2f6bSGordon Ross 	 * We use this below to find data based on offsets
319*613a2f6bSGordon Ross 	 * from the start of the header.
320*613a2f6bSGordon Ross 	 */
321*613a2f6bSGordon Ross 	top_mb = *in_mb;
322*613a2f6bSGordon Ross 
323*613a2f6bSGordon Ross 	/* Parse the fixed size header stuff. */
324*613a2f6bSGordon Ross 	bzero(&hdr, sizeof (hdr));
325*613a2f6bSGordon Ross 	(void) mb_get_mem(in_mb, &hdr.h_id, ID_SZ);
326*613a2f6bSGordon Ross 	(void) mb_get_uint32le(in_mb, &hdr.h_type);
327*613a2f6bSGordon Ross 	if (hdr.h_type != 2) {
328*613a2f6bSGordon Ross 		err = EPROTO;
329*613a2f6bSGordon Ross 		goto out;
330*613a2f6bSGordon Ross 	}
331*613a2f6bSGordon Ross 	(void) mb_get_sb_hdr(in_mb, &hdr.h_target_name);
332*613a2f6bSGordon Ross 	(void) mb_get_uint32le(in_mb, &hdr.h_flags);
333*613a2f6bSGordon Ross 	(void) mb_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ);
334*613a2f6bSGordon Ross 
335*613a2f6bSGordon Ross 	/*
336*613a2f6bSGordon Ross 	 * Save flags, challenge for later.
337*613a2f6bSGordon Ross 	 */
338*613a2f6bSGordon Ross 	ssp_st->ss_flags = hdr.h_flags;
339*613a2f6bSGordon Ross 	uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
340*613a2f6bSGordon Ross 	bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
341*613a2f6bSGordon Ross 
342*613a2f6bSGordon Ross 	/*
343*613a2f6bSGordon Ross 	 * Now find out if the optional parts are there.
344*613a2f6bSGordon Ross 	 */
345*613a2f6bSGordon Ross 	if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) &&
346*613a2f6bSGordon Ross 	    (hdr.h_target_name.sb_offset >= sizeof (hdr))) {
347*613a2f6bSGordon Ross 		(void) mb_get_uint32le(in_mb, &hdr.h_context[0]);
348*613a2f6bSGordon Ross 		(void) mb_get_uint32le(in_mb, &hdr.h_context[1]);
349*613a2f6bSGordon Ross 		(void) mb_get_sb_hdr(in_mb, &hdr.h_target_info);
350*613a2f6bSGordon Ross 	}
351*613a2f6bSGordon Ross 
352*613a2f6bSGordon Ross 	/*
353*613a2f6bSGordon Ross 	 * Get the target name string.  First get a copy of
354*613a2f6bSGordon Ross 	 * the data from the offset/length indicated in the
355*613a2f6bSGordon Ross 	 * security buffer header; then parse the string.
356*613a2f6bSGordon Ross 	 */
357*613a2f6bSGordon Ross 	err = mb_get_sb_data(&top_mb, &hdr.h_target_name, &m);
358*613a2f6bSGordon Ross 	if (err)
359*613a2f6bSGordon Ross 		goto out;
360*613a2f6bSGordon Ross 	mb_initm(&tmp_mb, m);
361*613a2f6bSGordon Ross 	err = mb_get_string(&tmp_mb, &ssp_st->ss_target_name, uc);
362*613a2f6bSGordon Ross 	mb_done(&tmp_mb);
363*613a2f6bSGordon Ross 
364*613a2f6bSGordon Ross 	/*
365*613a2f6bSGordon Ross 	 * Get the target info blob, if present.
366*613a2f6bSGordon Ross 	 */
367*613a2f6bSGordon Ross 	if (hdr.h_target_info.sb_offset >= sizeof (hdr)) {
368*613a2f6bSGordon Ross 		err = mb_get_sb_data(&top_mb, &hdr.h_target_info,
369*613a2f6bSGordon Ross 		    &ssp_st->ss_target_info);
370*613a2f6bSGordon Ross 	}
371*613a2f6bSGordon Ross 
372*613a2f6bSGordon Ross out:
373*613a2f6bSGordon Ross 	if (buf != NULL)
374*613a2f6bSGordon Ross 		free(buf);
375*613a2f6bSGordon Ross 
376*613a2f6bSGordon Ross 	return (err);
377*613a2f6bSGordon Ross }
378*613a2f6bSGordon Ross 
379*613a2f6bSGordon Ross /*
380*613a2f6bSGordon Ross  * Build a Type 3 message
381*613a2f6bSGordon Ross  *
382*613a2f6bSGordon Ross  * This message has a header section containing offsets to
383*613a2f6bSGordon Ross  * data later in the message.  We use the common trick of
384*613a2f6bSGordon Ross  * building it in two parts and then concatenatening.
385*613a2f6bSGordon Ross  */
386*613a2f6bSGordon Ross int
387*613a2f6bSGordon Ross ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
388*613a2f6bSGordon Ross {
389*613a2f6bSGordon Ross 	struct type3hdr {
390*613a2f6bSGordon Ross 		char h_id[ID_SZ];
391*613a2f6bSGordon Ross 		uint32_t h_type;
392*613a2f6bSGordon Ross 		struct sec_buf h_lm_resp;
393*613a2f6bSGordon Ross 		struct sec_buf h_nt_resp;
394*613a2f6bSGordon Ross 		struct sec_buf h_domain;
395*613a2f6bSGordon Ross 		struct sec_buf h_user;
396*613a2f6bSGordon Ross 		struct sec_buf h_wksta;
397*613a2f6bSGordon Ross 	} hdr;
398*613a2f6bSGordon Ross 	struct mbdata lm_mbc, nt_mbc, ti_mbc;
399*613a2f6bSGordon Ross 	struct mbdata mb2;	/* 2nd part */
400*613a2f6bSGordon Ross 	int err, uc;
401*613a2f6bSGordon Ross 	char *ucdom = NULL;	/* user's domain */
402*613a2f6bSGordon Ross 	char *ucuser = NULL;	/* user name */
403*613a2f6bSGordon Ross 	char *ucwksta = NULL;	/* workstation */
404*613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
405*613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st = sp->sp_private;
406*613a2f6bSGordon Ross 
407*613a2f6bSGordon Ross 	bzero(&lm_mbc, sizeof (lm_mbc));
408*613a2f6bSGordon Ross 	bzero(&nt_mbc, sizeof (nt_mbc));
409*613a2f6bSGordon Ross 	bzero(&ti_mbc, sizeof (ti_mbc));
410*613a2f6bSGordon Ross 	bzero(&mb2, sizeof (mb2));
411*613a2f6bSGordon Ross 
412*613a2f6bSGordon Ross 	/*
413*613a2f6bSGordon Ross 	 * Convert the user name to upper-case, as that's what's
414*613a2f6bSGordon Ross 	 * used when computing LMv2 and NTLMv2 responses.  Also
415*613a2f6bSGordon Ross 	 * domain, workstation
416*613a2f6bSGordon Ross 	 */
417*613a2f6bSGordon Ross 	ucdom  = utf8_str_toupper(ctx->ct_domain);
418*613a2f6bSGordon Ross 	ucuser = utf8_str_toupper(ctx->ct_user);
419*613a2f6bSGordon Ross 	ucwksta = utf8_str_toupper(ctx->ct_locname);
420*613a2f6bSGordon Ross 	if (ucdom == NULL || ucuser == NULL || ucwksta == NULL) {
421*613a2f6bSGordon Ross 		err = ENOMEM;
422*613a2f6bSGordon Ross 		goto out;
423*613a2f6bSGordon Ross 	}
424*613a2f6bSGordon Ross 
425*613a2f6bSGordon Ross 	if ((err = mb_init(&mb2, M_MINSIZE)) != 0)
426*613a2f6bSGordon Ross 		goto out;
427*613a2f6bSGordon Ross 	mb2.mb_count = sizeof (hdr);
428*613a2f6bSGordon Ross 	uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
429*613a2f6bSGordon Ross 
430*613a2f6bSGordon Ross 	bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
431*613a2f6bSGordon Ross 	hdr.h_type = 3; /* Type 3 */
432*613a2f6bSGordon Ross 
433*613a2f6bSGordon Ross 	/*
434*613a2f6bSGordon Ross 	 * Put the LMv2,NTLMv2 responses, or
435*613a2f6bSGordon Ross 	 * possibly LM, NTLM (v1) responses.
436*613a2f6bSGordon Ross 	 */
437*613a2f6bSGordon Ross 	if (ctx->ct_authflags & SMB_AT_NTLM2) {
438*613a2f6bSGordon Ross 		/* Build the NTLMv2 "target info" blob. */
439*613a2f6bSGordon Ross 		err = ntlm_build_target_info(ctx,
440*613a2f6bSGordon Ross 		    ssp_st->ss_target_info, &ti_mbc);
441*613a2f6bSGordon Ross 		if (err)
442*613a2f6bSGordon Ross 			goto out;
443*613a2f6bSGordon Ross 		err = ntlm_put_v2_responses(ctx, &ti_mbc,
444*613a2f6bSGordon Ross 		    &lm_mbc, &nt_mbc);
445*613a2f6bSGordon Ross 	} else {
446*613a2f6bSGordon Ross 		err = ntlm_put_v1_responses(ctx,
447*613a2f6bSGordon Ross 		    &lm_mbc, &nt_mbc);
448*613a2f6bSGordon Ross 	}
449*613a2f6bSGordon Ross 	if (err)
450*613a2f6bSGordon Ross 		goto out;
451*613a2f6bSGordon Ross 
452*613a2f6bSGordon Ross 	err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
453*613a2f6bSGordon Ross 	lm_mbc.mb_top = NULL; /* consumed */
454*613a2f6bSGordon Ross 	if (err)
455*613a2f6bSGordon Ross 		goto out;
456*613a2f6bSGordon Ross 	err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
457*613a2f6bSGordon Ross 	nt_mbc.mb_top = NULL; /* consumed */
458*613a2f6bSGordon Ross 	if (err)
459*613a2f6bSGordon Ross 		goto out;
460*613a2f6bSGordon Ross 
461*613a2f6bSGordon Ross 	/*
462*613a2f6bSGordon Ross 	 * Put the "target" (domain), user, workstation
463*613a2f6bSGordon Ross 	 */
464*613a2f6bSGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_domain, ucdom, uc);
465*613a2f6bSGordon Ross 	if (err)
466*613a2f6bSGordon Ross 		goto out;
467*613a2f6bSGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_user, ucuser, uc);
468*613a2f6bSGordon Ross 	if (err)
469*613a2f6bSGordon Ross 		goto out;
470*613a2f6bSGordon Ross 	err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwksta, uc);
471*613a2f6bSGordon Ross 	if (err)
472*613a2f6bSGordon Ross 		goto out;
473*613a2f6bSGordon Ross 
474*613a2f6bSGordon Ross 	/*
475*613a2f6bSGordon Ross 	 * Marshal the header (in LE order)
476*613a2f6bSGordon Ross 	 * then concatenate the 2nd part.
477*613a2f6bSGordon Ross 	 */
478*613a2f6bSGordon Ross 	(void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ);
479*613a2f6bSGordon Ross 	(void) mb_put_uint32le(out_mb, hdr.h_type);
480*613a2f6bSGordon Ross 
481*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp);
482*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp);
483*613a2f6bSGordon Ross 
484*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_domain);
485*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_user);
486*613a2f6bSGordon Ross 	(void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
487*613a2f6bSGordon Ross 
488*613a2f6bSGordon Ross 	err = mb_put_mbuf(out_mb, mb2.mb_top);
489*613a2f6bSGordon Ross 	mb2.mb_top = NULL; /* consumed */
490*613a2f6bSGordon Ross 
491*613a2f6bSGordon Ross out:
492*613a2f6bSGordon Ross 	free(ucdom);
493*613a2f6bSGordon Ross 	free(ucuser);
494*613a2f6bSGordon Ross 	free(ucwksta);
495*613a2f6bSGordon Ross 
496*613a2f6bSGordon Ross 	mb_done(&mb2);
497*613a2f6bSGordon Ross 	mb_done(&lm_mbc);
498*613a2f6bSGordon Ross 	mb_done(&nt_mbc);
499*613a2f6bSGordon Ross 
500*613a2f6bSGordon Ross 	return (err);
501*613a2f6bSGordon Ross }
502*613a2f6bSGordon Ross 
503*613a2f6bSGordon Ross /*
504*613a2f6bSGordon Ross  * ntlmssp_final
505*613a2f6bSGordon Ross  *
506*613a2f6bSGordon Ross  * Called after successful authentication.
507*613a2f6bSGordon Ross  * Setup the MAC key for signing.
508*613a2f6bSGordon Ross  */
509*613a2f6bSGordon Ross int
510*613a2f6bSGordon Ross ntlmssp_final(struct ssp_ctx *sp)
511*613a2f6bSGordon Ross {
512*613a2f6bSGordon Ross 	struct smb_ctx *ctx = sp->smb_ctx;
513*613a2f6bSGordon Ross 	int err = 0;
514*613a2f6bSGordon Ross 
515*613a2f6bSGordon Ross 	/*
516*613a2f6bSGordon Ross 	 * MAC_key is just the session key, but
517*613a2f6bSGordon Ross 	 * Only on the first successful auth.
518*613a2f6bSGordon Ross 	 */
519*613a2f6bSGordon Ross 	if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
520*613a2f6bSGordon Ross 	    (ctx->ct_mackey == NULL)) {
521*613a2f6bSGordon Ross 		ctx->ct_mackeylen = NTLM_HASH_SZ;
522*613a2f6bSGordon Ross 		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
523*613a2f6bSGordon Ross 		if (ctx->ct_mackey == NULL) {
524*613a2f6bSGordon Ross 			ctx->ct_mackeylen = 0;
525*613a2f6bSGordon Ross 			err = ENOMEM;
526*613a2f6bSGordon Ross 			goto out;
527*613a2f6bSGordon Ross 		}
528*613a2f6bSGordon Ross 		memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
529*613a2f6bSGordon Ross 		/*
530*613a2f6bSGordon Ross 		 * Apparently, the server used seq. no. zero
531*613a2f6bSGordon Ross 		 * for our previous message, so next is two.
532*613a2f6bSGordon Ross 		 */
533*613a2f6bSGordon Ross 		ctx->ct_mac_seqno = 2;
534*613a2f6bSGordon Ross 	}
535*613a2f6bSGordon Ross 
536*613a2f6bSGordon Ross out:
537*613a2f6bSGordon Ross 	return (err);
538*613a2f6bSGordon Ross }
539*613a2f6bSGordon Ross 
540*613a2f6bSGordon Ross /*
541*613a2f6bSGordon Ross  * ntlmssp_next_token
542*613a2f6bSGordon Ross  *
543*613a2f6bSGordon Ross  * See ssp.c: ssp_ctx_next_token
544*613a2f6bSGordon Ross  */
545*613a2f6bSGordon Ross int
546*613a2f6bSGordon Ross ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
547*613a2f6bSGordon Ross 	struct mbdata *out_mb)
548*613a2f6bSGordon Ross {
549*613a2f6bSGordon Ross 	int err;
550*613a2f6bSGordon Ross 
551*613a2f6bSGordon Ross 	if (out_mb == NULL) {
552*613a2f6bSGordon Ross 		/* final call on successful auth. */
553*613a2f6bSGordon Ross 		err = ntlmssp_final(sp);
554*613a2f6bSGordon Ross 		goto out;
555*613a2f6bSGordon Ross 	}
556*613a2f6bSGordon Ross 
557*613a2f6bSGordon Ross 	/* Will build an ouptut token. */
558*613a2f6bSGordon Ross 	err = mb_init(out_mb, M_MINSIZE);
559*613a2f6bSGordon Ross 	if (err)
560*613a2f6bSGordon Ross 		goto out;
561*613a2f6bSGordon Ross 
562*613a2f6bSGordon Ross 	/*
563*613a2f6bSGordon Ross 	 * When called with in_mb == NULL, it means
564*613a2f6bSGordon Ross 	 * this is the first call for this session,
565*613a2f6bSGordon Ross 	 * so put a Type 1 (initialize) token.
566*613a2f6bSGordon Ross 	 */
567*613a2f6bSGordon Ross 	if (in_mb == NULL) {
568*613a2f6bSGordon Ross 		err = ntlmssp_put_type1(sp, out_mb);
569*613a2f6bSGordon Ross 		goto out;
570*613a2f6bSGordon Ross 	}
571*613a2f6bSGordon Ross 
572*613a2f6bSGordon Ross 	/*
573*613a2f6bSGordon Ross 	 * This is not the first call, so
574*613a2f6bSGordon Ross 	 * parse the response token we received.
575*613a2f6bSGordon Ross 	 * It should be a Type 2 (challenge).
576*613a2f6bSGordon Ross 	 * Then put a Type 3 (authenticate)
577*613a2f6bSGordon Ross 	 */
578*613a2f6bSGordon Ross 	err = ntlmssp_get_type2(sp, in_mb);
579*613a2f6bSGordon Ross 	if (err)
580*613a2f6bSGordon Ross 		goto out;
581*613a2f6bSGordon Ross 
582*613a2f6bSGordon Ross 	err = ntlmssp_put_type3(sp, out_mb);
583*613a2f6bSGordon Ross 
584*613a2f6bSGordon Ross out:
585*613a2f6bSGordon Ross 	if (err)
586*613a2f6bSGordon Ross 		DPRINT("ret: %d", err);
587*613a2f6bSGordon Ross 	return (err);
588*613a2f6bSGordon Ross }
589*613a2f6bSGordon Ross 
590*613a2f6bSGordon Ross /*
591*613a2f6bSGordon Ross  * ntlmssp_ctx_destroy
592*613a2f6bSGordon Ross  *
593*613a2f6bSGordon Ross  * Destroy mechanism-specific data.
594*613a2f6bSGordon Ross  */
595*613a2f6bSGordon Ross void
596*613a2f6bSGordon Ross ntlmssp_destroy(struct ssp_ctx *sp)
597*613a2f6bSGordon Ross {
598*613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st;
599*613a2f6bSGordon Ross 
600*613a2f6bSGordon Ross 	ssp_st = sp->sp_private;
601*613a2f6bSGordon Ross 	if (ssp_st != NULL) {
602*613a2f6bSGordon Ross 		sp->sp_private = NULL;
603*613a2f6bSGordon Ross 		free(ssp_st->ss_target_name);
604*613a2f6bSGordon Ross 		m_freem(ssp_st->ss_target_info);
605*613a2f6bSGordon Ross 		free(ssp_st);
606*613a2f6bSGordon Ross 	}
607*613a2f6bSGordon Ross }
608*613a2f6bSGordon Ross 
609*613a2f6bSGordon Ross /*
610*613a2f6bSGordon Ross  * ntlmssp_init_clnt
611*613a2f6bSGordon Ross  *
612*613a2f6bSGordon Ross  * Initialize a new NTLMSSP client context.
613*613a2f6bSGordon Ross  */
614*613a2f6bSGordon Ross int
615*613a2f6bSGordon Ross ntlmssp_init_client(struct ssp_ctx *sp)
616*613a2f6bSGordon Ross {
617*613a2f6bSGordon Ross 	ntlmssp_state_t *ssp_st;
618*613a2f6bSGordon Ross 
619*613a2f6bSGordon Ross 	if ((sp->smb_ctx->ct_authflags &
620*613a2f6bSGordon Ross 	    (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
621*613a2f6bSGordon Ross 		DPRINT("No NTLM authflags");
622*613a2f6bSGordon Ross 		return (ENOTSUP);
623*613a2f6bSGordon Ross 	}
624*613a2f6bSGordon Ross 
625*613a2f6bSGordon Ross 	ssp_st = calloc(1, sizeof (*ssp_st));
626*613a2f6bSGordon Ross 	if (ssp_st == NULL)
627*613a2f6bSGordon Ross 		return (ENOMEM);
628*613a2f6bSGordon Ross 
629*613a2f6bSGordon Ross 	sp->sp_nexttok = ntlmssp_next_token;
630*613a2f6bSGordon Ross 	sp->sp_destroy = ntlmssp_destroy;
631*613a2f6bSGordon Ross 	sp->sp_private = ssp_st;
632*613a2f6bSGordon Ross 
633*613a2f6bSGordon Ross 	return (0);
634*613a2f6bSGordon Ross }
635