xref: /onnv-gate/usr/src/lib/libsmbfs/smb/ssnsetup.c (revision 10023:71bf38dba3d6)
1*10023SGordon.Ross@Sun.COM /*
2*10023SGordon.Ross@Sun.COM  * Copyright (c) 2000-2001 Boris Popov
3*10023SGordon.Ross@Sun.COM  * All rights reserved.
4*10023SGordon.Ross@Sun.COM  *
5*10023SGordon.Ross@Sun.COM  * Redistribution and use in source and binary forms, with or without
6*10023SGordon.Ross@Sun.COM  * modification, are permitted provided that the following conditions
7*10023SGordon.Ross@Sun.COM  * are met:
8*10023SGordon.Ross@Sun.COM  * 1. Redistributions of source code must retain the above copyright
9*10023SGordon.Ross@Sun.COM  *    notice, this list of conditions and the following disclaimer.
10*10023SGordon.Ross@Sun.COM  * 2. Redistributions in binary form must reproduce the above copyright
11*10023SGordon.Ross@Sun.COM  *    notice, this list of conditions and the following disclaimer in the
12*10023SGordon.Ross@Sun.COM  *    documentation and/or other materials provided with the distribution.
13*10023SGordon.Ross@Sun.COM  * 3. All advertising materials mentioning features or use of this software
14*10023SGordon.Ross@Sun.COM  *    must display the following acknowledgement:
15*10023SGordon.Ross@Sun.COM  *    This product includes software developed by Boris Popov.
16*10023SGordon.Ross@Sun.COM  * 4. Neither the name of the author nor the names of any co-contributors
17*10023SGordon.Ross@Sun.COM  *    may be used to endorse or promote products derived from this software
18*10023SGordon.Ross@Sun.COM  *    without specific prior written permission.
19*10023SGordon.Ross@Sun.COM  *
20*10023SGordon.Ross@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21*10023SGordon.Ross@Sun.COM  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*10023SGordon.Ross@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*10023SGordon.Ross@Sun.COM  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*10023SGordon.Ross@Sun.COM  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*10023SGordon.Ross@Sun.COM  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*10023SGordon.Ross@Sun.COM  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*10023SGordon.Ross@Sun.COM  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*10023SGordon.Ross@Sun.COM  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*10023SGordon.Ross@Sun.COM  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*10023SGordon.Ross@Sun.COM  * SUCH DAMAGE.
31*10023SGordon.Ross@Sun.COM  */
32*10023SGordon.Ross@Sun.COM 
33*10023SGordon.Ross@Sun.COM /*
34*10023SGordon.Ross@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
35*10023SGordon.Ross@Sun.COM  * Use is subject to license terms.
36*10023SGordon.Ross@Sun.COM  */
37*10023SGordon.Ross@Sun.COM 
38*10023SGordon.Ross@Sun.COM /*
39*10023SGordon.Ross@Sun.COM  * SMB Session Setup, and related.
40*10023SGordon.Ross@Sun.COM  * Copied from the driver: smb_smb.c
41*10023SGordon.Ross@Sun.COM  */
42*10023SGordon.Ross@Sun.COM 
43*10023SGordon.Ross@Sun.COM #include <errno.h>
44*10023SGordon.Ross@Sun.COM #include <stdio.h>
45*10023SGordon.Ross@Sun.COM #include <stdlib.h>
46*10023SGordon.Ross@Sun.COM #include <unistd.h>
47*10023SGordon.Ross@Sun.COM #include <strings.h>
48*10023SGordon.Ross@Sun.COM #include <netdb.h>
49*10023SGordon.Ross@Sun.COM #include <libintl.h>
50*10023SGordon.Ross@Sun.COM #include <xti.h>
51*10023SGordon.Ross@Sun.COM #include <assert.h>
52*10023SGordon.Ross@Sun.COM 
53*10023SGordon.Ross@Sun.COM #include <sys/types.h>
54*10023SGordon.Ross@Sun.COM #include <sys/time.h>
55*10023SGordon.Ross@Sun.COM #include <sys/byteorder.h>
56*10023SGordon.Ross@Sun.COM #include <sys/socket.h>
57*10023SGordon.Ross@Sun.COM #include <sys/fcntl.h>
58*10023SGordon.Ross@Sun.COM 
59*10023SGordon.Ross@Sun.COM #include <netinet/in.h>
60*10023SGordon.Ross@Sun.COM #include <netinet/tcp.h>
61*10023SGordon.Ross@Sun.COM #include <arpa/inet.h>
62*10023SGordon.Ross@Sun.COM 
63*10023SGordon.Ross@Sun.COM #include <netsmb/mchain.h>
64*10023SGordon.Ross@Sun.COM #include <netsmb/netbios.h>
65*10023SGordon.Ross@Sun.COM #include <netsmb/smb_dev.h>
66*10023SGordon.Ross@Sun.COM #include <netsmb/smb.h>
67*10023SGordon.Ross@Sun.COM 
68*10023SGordon.Ross@Sun.COM #include <netsmb/smb_lib.h>
69*10023SGordon.Ross@Sun.COM #include <netsmb/nb_lib.h>
70*10023SGordon.Ross@Sun.COM 
71*10023SGordon.Ross@Sun.COM #include "private.h"
72*10023SGordon.Ross@Sun.COM #include "charsets.h"
73*10023SGordon.Ross@Sun.COM #include "ntlm.h"
74*10023SGordon.Ross@Sun.COM #include "smb_crypt.h"
75*10023SGordon.Ross@Sun.COM 
76*10023SGordon.Ross@Sun.COM /*
77*10023SGordon.Ross@Sun.COM  * When we have a _real_ ntstatus.h, eliminate this.
78*10023SGordon.Ross@Sun.COM  * XXX: Current smb.h defines it without the high bits.
79*10023SGordon.Ross@Sun.COM  */
80*10023SGordon.Ross@Sun.COM #define	STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
81*10023SGordon.Ross@Sun.COM 
82*10023SGordon.Ross@Sun.COM static int
83*10023SGordon.Ross@Sun.COM smb__ssnsetup(struct smb_ctx *ctx,
84*10023SGordon.Ross@Sun.COM 	struct mbdata *mbc1, struct mbdata *mbc2,
85*10023SGordon.Ross@Sun.COM 	uint32_t *statusp, uint16_t *actionp);
86*10023SGordon.Ross@Sun.COM 
87*10023SGordon.Ross@Sun.COM /*
88*10023SGordon.Ross@Sun.COM  * Session Setup: NULL session (anonymous)
89*10023SGordon.Ross@Sun.COM  */
90*10023SGordon.Ross@Sun.COM int
91*10023SGordon.Ross@Sun.COM smb_ssnsetup_null(struct smb_ctx *ctx)
92*10023SGordon.Ross@Sun.COM {
93*10023SGordon.Ross@Sun.COM 	int err;
94*10023SGordon.Ross@Sun.COM 	uint32_t ntstatus;
95*10023SGordon.Ross@Sun.COM 	uint16_t action = 0;
96*10023SGordon.Ross@Sun.COM 
97*10023SGordon.Ross@Sun.COM 	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
98*10023SGordon.Ross@Sun.COM 		/* Should not get here with... */
99*10023SGordon.Ross@Sun.COM 		err = EINVAL;
100*10023SGordon.Ross@Sun.COM 		goto out;
101*10023SGordon.Ross@Sun.COM 	}
102*10023SGordon.Ross@Sun.COM 
103*10023SGordon.Ross@Sun.COM 	err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
104*10023SGordon.Ross@Sun.COM 	if (err)
105*10023SGordon.Ross@Sun.COM 		goto out;
106*10023SGordon.Ross@Sun.COM 
107*10023SGordon.Ross@Sun.COM 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
108*10023SGordon.Ross@Sun.COM 	if (ntstatus != 0)
109*10023SGordon.Ross@Sun.COM 		err = EAUTH;
110*10023SGordon.Ross@Sun.COM 
111*10023SGordon.Ross@Sun.COM out:
112*10023SGordon.Ross@Sun.COM 	return (err);
113*10023SGordon.Ross@Sun.COM }
114*10023SGordon.Ross@Sun.COM 
115*10023SGordon.Ross@Sun.COM 
116*10023SGordon.Ross@Sun.COM /*
117*10023SGordon.Ross@Sun.COM  * SMB Session Setup, using NTLMv1 (and maybe LMv1)
118*10023SGordon.Ross@Sun.COM  */
119*10023SGordon.Ross@Sun.COM int
120*10023SGordon.Ross@Sun.COM smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
121*10023SGordon.Ross@Sun.COM {
122*10023SGordon.Ross@Sun.COM 	struct mbdata lm_mbc, nt_mbc;
123*10023SGordon.Ross@Sun.COM 	int err;
124*10023SGordon.Ross@Sun.COM 	uint32_t ntstatus;
125*10023SGordon.Ross@Sun.COM 	uint16_t action = 0;
126*10023SGordon.Ross@Sun.COM 
127*10023SGordon.Ross@Sun.COM 	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
128*10023SGordon.Ross@Sun.COM 		/* Should not get here with... */
129*10023SGordon.Ross@Sun.COM 		err = EINVAL;
130*10023SGordon.Ross@Sun.COM 		goto out;
131*10023SGordon.Ross@Sun.COM 	}
132*10023SGordon.Ross@Sun.COM 
133*10023SGordon.Ross@Sun.COM 	/* Make mb_done calls at out safe. */
134*10023SGordon.Ross@Sun.COM 	bzero(&lm_mbc, sizeof (lm_mbc));
135*10023SGordon.Ross@Sun.COM 	bzero(&nt_mbc, sizeof (nt_mbc));
136*10023SGordon.Ross@Sun.COM 
137*10023SGordon.Ross@Sun.COM 	/* Put the LM,NTLM responses (as mbdata). */
138*10023SGordon.Ross@Sun.COM 	err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
139*10023SGordon.Ross@Sun.COM 	if (err)
140*10023SGordon.Ross@Sun.COM 		goto out;
141*10023SGordon.Ross@Sun.COM 
142*10023SGordon.Ross@Sun.COM 	/*
143*10023SGordon.Ross@Sun.COM 	 * If we negotiated signing, compute the MAC key
144*10023SGordon.Ross@Sun.COM 	 * and start signing messages, but only on the
145*10023SGordon.Ross@Sun.COM 	 * first non-null session login.
146*10023SGordon.Ross@Sun.COM 	 */
147*10023SGordon.Ross@Sun.COM 	if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
148*10023SGordon.Ross@Sun.COM 	    (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
149*10023SGordon.Ross@Sun.COM 		struct mbuf *m = nt_mbc.mb_top;
150*10023SGordon.Ross@Sun.COM 		char *p;
151*10023SGordon.Ross@Sun.COM 
152*10023SGordon.Ross@Sun.COM 		/*
153*10023SGordon.Ross@Sun.COM 		 * MAC_key = concat(session_key, nt_response)
154*10023SGordon.Ross@Sun.COM 		 */
155*10023SGordon.Ross@Sun.COM 		ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
156*10023SGordon.Ross@Sun.COM 		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
157*10023SGordon.Ross@Sun.COM 		if (ctx->ct_mackey == NULL) {
158*10023SGordon.Ross@Sun.COM 			ctx->ct_mackeylen = 0;
159*10023SGordon.Ross@Sun.COM 			err = ENOMEM;
160*10023SGordon.Ross@Sun.COM 			goto out;
161*10023SGordon.Ross@Sun.COM 		}
162*10023SGordon.Ross@Sun.COM 		p = ctx->ct_mackey;
163*10023SGordon.Ross@Sun.COM 		memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
164*10023SGordon.Ross@Sun.COM 		memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
165*10023SGordon.Ross@Sun.COM 
166*10023SGordon.Ross@Sun.COM 		/* OK, start signing! */
167*10023SGordon.Ross@Sun.COM 		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
168*10023SGordon.Ross@Sun.COM 	}
169*10023SGordon.Ross@Sun.COM 
170*10023SGordon.Ross@Sun.COM 	err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
171*10023SGordon.Ross@Sun.COM 	if (err)
172*10023SGordon.Ross@Sun.COM 		goto out;
173*10023SGordon.Ross@Sun.COM 
174*10023SGordon.Ross@Sun.COM 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
175*10023SGordon.Ross@Sun.COM 	if (ntstatus != 0)
176*10023SGordon.Ross@Sun.COM 		err = EAUTH;
177*10023SGordon.Ross@Sun.COM 
178*10023SGordon.Ross@Sun.COM out:
179*10023SGordon.Ross@Sun.COM 	mb_done(&lm_mbc);
180*10023SGordon.Ross@Sun.COM 	mb_done(&nt_mbc);
181*10023SGordon.Ross@Sun.COM 
182*10023SGordon.Ross@Sun.COM 	return (err);
183*10023SGordon.Ross@Sun.COM }
184*10023SGordon.Ross@Sun.COM 
185*10023SGordon.Ross@Sun.COM /*
186*10023SGordon.Ross@Sun.COM  * SMB Session Setup, using NTLMv2 (and LMv2)
187*10023SGordon.Ross@Sun.COM  */
188*10023SGordon.Ross@Sun.COM int
189*10023SGordon.Ross@Sun.COM smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
190*10023SGordon.Ross@Sun.COM {
191*10023SGordon.Ross@Sun.COM 	struct mbdata lm_mbc, nt_mbc, ti_mbc;
192*10023SGordon.Ross@Sun.COM 	int err;
193*10023SGordon.Ross@Sun.COM 	uint32_t ntstatus;
194*10023SGordon.Ross@Sun.COM 	uint16_t action = 0;
195*10023SGordon.Ross@Sun.COM 
196*10023SGordon.Ross@Sun.COM 	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
197*10023SGordon.Ross@Sun.COM 		/* Should not get here with... */
198*10023SGordon.Ross@Sun.COM 		err = EINVAL;
199*10023SGordon.Ross@Sun.COM 		goto out;
200*10023SGordon.Ross@Sun.COM 	}
201*10023SGordon.Ross@Sun.COM 
202*10023SGordon.Ross@Sun.COM 	/* Make mb_done calls at out safe. */
203*10023SGordon.Ross@Sun.COM 	bzero(&lm_mbc, sizeof (lm_mbc));
204*10023SGordon.Ross@Sun.COM 	bzero(&nt_mbc, sizeof (nt_mbc));
205*10023SGordon.Ross@Sun.COM 	bzero(&ti_mbc, sizeof (ti_mbc));
206*10023SGordon.Ross@Sun.COM 
207*10023SGordon.Ross@Sun.COM 	/* Build the NTLMv2 "target info" blob (as mbdata) */
208*10023SGordon.Ross@Sun.COM 	err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
209*10023SGordon.Ross@Sun.COM 	if (err)
210*10023SGordon.Ross@Sun.COM 		goto out;
211*10023SGordon.Ross@Sun.COM 
212*10023SGordon.Ross@Sun.COM 	/* Put the LMv2, NTLMv2 responses (as mbdata). */
213*10023SGordon.Ross@Sun.COM 	err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
214*10023SGordon.Ross@Sun.COM 	if (err)
215*10023SGordon.Ross@Sun.COM 		goto out;
216*10023SGordon.Ross@Sun.COM 
217*10023SGordon.Ross@Sun.COM 	/*
218*10023SGordon.Ross@Sun.COM 	 * If we negotiated signing, compute the MAC key
219*10023SGordon.Ross@Sun.COM 	 * and start signing messages, but only on the
220*10023SGordon.Ross@Sun.COM 	 * first non-null session login.
221*10023SGordon.Ross@Sun.COM 	 */
222*10023SGordon.Ross@Sun.COM 	if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
223*10023SGordon.Ross@Sun.COM 	    (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
224*10023SGordon.Ross@Sun.COM 		struct mbuf *m = nt_mbc.mb_top;
225*10023SGordon.Ross@Sun.COM 		char *p;
226*10023SGordon.Ross@Sun.COM 
227*10023SGordon.Ross@Sun.COM 		/*
228*10023SGordon.Ross@Sun.COM 		 * MAC_key = concat(session_key, nt_response)
229*10023SGordon.Ross@Sun.COM 		 */
230*10023SGordon.Ross@Sun.COM 		ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
231*10023SGordon.Ross@Sun.COM 		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
232*10023SGordon.Ross@Sun.COM 		if (ctx->ct_mackey == NULL) {
233*10023SGordon.Ross@Sun.COM 			ctx->ct_mackeylen = 0;
234*10023SGordon.Ross@Sun.COM 			err = ENOMEM;
235*10023SGordon.Ross@Sun.COM 			goto out;
236*10023SGordon.Ross@Sun.COM 		}
237*10023SGordon.Ross@Sun.COM 		p = ctx->ct_mackey;
238*10023SGordon.Ross@Sun.COM 		memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
239*10023SGordon.Ross@Sun.COM 		memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
240*10023SGordon.Ross@Sun.COM 
241*10023SGordon.Ross@Sun.COM 		/* OK, start signing! */
242*10023SGordon.Ross@Sun.COM 		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
243*10023SGordon.Ross@Sun.COM 	}
244*10023SGordon.Ross@Sun.COM 
245*10023SGordon.Ross@Sun.COM 	err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
246*10023SGordon.Ross@Sun.COM 	if (err)
247*10023SGordon.Ross@Sun.COM 		goto out;
248*10023SGordon.Ross@Sun.COM 
249*10023SGordon.Ross@Sun.COM 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
250*10023SGordon.Ross@Sun.COM 	if (ntstatus != 0)
251*10023SGordon.Ross@Sun.COM 		err = EAUTH;
252*10023SGordon.Ross@Sun.COM 
253*10023SGordon.Ross@Sun.COM out:
254*10023SGordon.Ross@Sun.COM 	mb_done(&ti_mbc);
255*10023SGordon.Ross@Sun.COM 	mb_done(&lm_mbc);
256*10023SGordon.Ross@Sun.COM 	mb_done(&nt_mbc);
257*10023SGordon.Ross@Sun.COM 
258*10023SGordon.Ross@Sun.COM 	return (err);
259*10023SGordon.Ross@Sun.COM }
260*10023SGordon.Ross@Sun.COM 
261*10023SGordon.Ross@Sun.COM int
262*10023SGordon.Ross@Sun.COM smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
263*10023SGordon.Ross@Sun.COM {
264*10023SGordon.Ross@Sun.COM 	struct mbdata send_mb, recv_mb;
265*10023SGordon.Ross@Sun.COM 	int		err;
266*10023SGordon.Ross@Sun.COM 	uint32_t	ntstatus;
267*10023SGordon.Ross@Sun.COM 	uint16_t	action = 0;
268*10023SGordon.Ross@Sun.COM 
269*10023SGordon.Ross@Sun.COM 	err = ssp_ctx_create_client(ctx, hint_mb);
270*10023SGordon.Ross@Sun.COM 	if (err)
271*10023SGordon.Ross@Sun.COM 		goto out;
272*10023SGordon.Ross@Sun.COM 
273*10023SGordon.Ross@Sun.COM 	bzero(&send_mb, sizeof (send_mb));
274*10023SGordon.Ross@Sun.COM 	bzero(&recv_mb, sizeof (recv_mb));
275*10023SGordon.Ross@Sun.COM 
276*10023SGordon.Ross@Sun.COM 	/* NULL input indicates first call. */
277*10023SGordon.Ross@Sun.COM 	err = ssp_ctx_next_token(ctx, NULL, &send_mb);
278*10023SGordon.Ross@Sun.COM 	if (err)
279*10023SGordon.Ross@Sun.COM 		goto out;
280*10023SGordon.Ross@Sun.COM 
281*10023SGordon.Ross@Sun.COM 	for (;;) {
282*10023SGordon.Ross@Sun.COM 		err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
283*10023SGordon.Ross@Sun.COM 		    &ntstatus, &action);
284*10023SGordon.Ross@Sun.COM 		if (err)
285*10023SGordon.Ross@Sun.COM 			goto out;
286*10023SGordon.Ross@Sun.COM 		if (ntstatus == 0)
287*10023SGordon.Ross@Sun.COM 			break; /* normal loop termination */
288*10023SGordon.Ross@Sun.COM 		if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) {
289*10023SGordon.Ross@Sun.COM 			err = EAUTH;
290*10023SGordon.Ross@Sun.COM 			break;
291*10023SGordon.Ross@Sun.COM 		}
292*10023SGordon.Ross@Sun.COM 
293*10023SGordon.Ross@Sun.COM 		/* middle calls get both in, out */
294*10023SGordon.Ross@Sun.COM 		err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
295*10023SGordon.Ross@Sun.COM 		if (err)
296*10023SGordon.Ross@Sun.COM 			goto out;
297*10023SGordon.Ross@Sun.COM 	}
298*10023SGordon.Ross@Sun.COM 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
299*10023SGordon.Ross@Sun.COM 
300*10023SGordon.Ross@Sun.COM 	/* NULL output indicates last call. */
301*10023SGordon.Ross@Sun.COM 	(void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
302*10023SGordon.Ross@Sun.COM 
303*10023SGordon.Ross@Sun.COM out:
304*10023SGordon.Ross@Sun.COM 	ssp_ctx_destroy(ctx);
305*10023SGordon.Ross@Sun.COM 
306*10023SGordon.Ross@Sun.COM 	return (err);
307*10023SGordon.Ross@Sun.COM }
308*10023SGordon.Ross@Sun.COM 
309*10023SGordon.Ross@Sun.COM /*
310*10023SGordon.Ross@Sun.COM  * Session Setup function used for all the forms we support.
311*10023SGordon.Ross@Sun.COM  * To allow this sharing, the crypto stuff is computed by
312*10023SGordon.Ross@Sun.COM  * callers and passed in as mbdata chains.  Also, the args
313*10023SGordon.Ross@Sun.COM  * have different meanings for extended security vs. old.
314*10023SGordon.Ross@Sun.COM  * Some may be used as either IN or OUT parameters.
315*10023SGordon.Ross@Sun.COM  *
316*10023SGordon.Ross@Sun.COM  * For NTLM (v1, v2), all parameters are inputs
317*10023SGordon.Ross@Sun.COM  * 	mbc1: [in] LM password hash
318*10023SGordon.Ross@Sun.COM  * 	mbc2: [in] NT password hash
319*10023SGordon.Ross@Sun.COM  * For Extended security (spnego)
320*10023SGordon.Ross@Sun.COM  *	mbc1: [in]  outgoing blob data
321*10023SGordon.Ross@Sun.COM  *	mbc2: [out] received blob data
322*10023SGordon.Ross@Sun.COM  * For both forms, these are optional:
323*10023SGordon.Ross@Sun.COM  *	statusp: [out] NT status
324*10023SGordon.Ross@Sun.COM  *	actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
325*10023SGordon.Ross@Sun.COM  */
326*10023SGordon.Ross@Sun.COM static int
327*10023SGordon.Ross@Sun.COM smb__ssnsetup(struct smb_ctx *ctx,
328*10023SGordon.Ross@Sun.COM 	struct mbdata *mbc1, struct mbdata *mbc2,
329*10023SGordon.Ross@Sun.COM 	uint32_t *statusp, uint16_t *actionp)
330*10023SGordon.Ross@Sun.COM {
331*10023SGordon.Ross@Sun.COM 	static const char NativeOS[] = "Solaris";
332*10023SGordon.Ross@Sun.COM 	static const char LanMan[] = "NETSMB";
333*10023SGordon.Ross@Sun.COM 	struct smb_sopt *sv = &ctx->ct_sopt;
334*10023SGordon.Ross@Sun.COM 	struct smb_iods *is = &ctx->ct_iods;
335*10023SGordon.Ross@Sun.COM 	struct smb_rq	*rqp = NULL;
336*10023SGordon.Ross@Sun.COM 	struct mbdata	*mbp;
337*10023SGordon.Ross@Sun.COM 	struct mbuf	*m;
338*10023SGordon.Ross@Sun.COM 	int err, uc;
339*10023SGordon.Ross@Sun.COM 	uint32_t caps;
340*10023SGordon.Ross@Sun.COM 	uint16_t bc, len1, len2, sblen;
341*10023SGordon.Ross@Sun.COM 	uint8_t wc;
342*10023SGordon.Ross@Sun.COM 
343*10023SGordon.Ross@Sun.COM 	/*
344*10023SGordon.Ross@Sun.COM 	 * Some of the "capability" bits we offer will be copied
345*10023SGordon.Ross@Sun.COM 	 * from those offered by the server, with a mask applied.
346*10023SGordon.Ross@Sun.COM 	 * This is the mask of capabilies copied from the server.
347*10023SGordon.Ross@Sun.COM 	 * Some others get special handling below.
348*10023SGordon.Ross@Sun.COM 	 */
349*10023SGordon.Ross@Sun.COM 	static const uint32_t caps_mask =
350*10023SGordon.Ross@Sun.COM 	    SMB_CAP_UNICODE |
351*10023SGordon.Ross@Sun.COM 	    SMB_CAP_LARGE_FILES |
352*10023SGordon.Ross@Sun.COM 	    SMB_CAP_NT_SMBS |
353*10023SGordon.Ross@Sun.COM 	    SMB_CAP_STATUS32 |
354*10023SGordon.Ross@Sun.COM 	    SMB_CAP_EXT_SECURITY;
355*10023SGordon.Ross@Sun.COM 
356*10023SGordon.Ross@Sun.COM 	caps = ctx->ct_sopt.sv_caps & caps_mask;
357*10023SGordon.Ross@Sun.COM 	uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
358*10023SGordon.Ross@Sun.COM 
359*10023SGordon.Ross@Sun.COM 	err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
360*10023SGordon.Ross@Sun.COM 	if (err)
361*10023SGordon.Ross@Sun.COM 		goto out;
362*10023SGordon.Ross@Sun.COM 
363*10023SGordon.Ross@Sun.COM 	/*
364*10023SGordon.Ross@Sun.COM 	 * Build the SMB request.
365*10023SGordon.Ross@Sun.COM 	 */
366*10023SGordon.Ross@Sun.COM 	mbp = &rqp->rq_rq;
367*10023SGordon.Ross@Sun.COM 	smb_rq_wstart(rqp);
368*10023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, 0xff);		/* 0: AndXCommand */
369*10023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, 0);		/* 1: AndXOffset */
370*10023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, sv->sv_maxtx);	/* 2: MaxBufferSize */
371*10023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, sv->sv_maxmux);	/* 3: MaxMpxCount */
372*10023SGordon.Ross@Sun.COM 	mb_put_uint16le(mbp, 1);		/* 4: VcNumber */
373*10023SGordon.Ross@Sun.COM 	mb_put_uint32le(mbp, sv->sv_skey);	/* 5,6: Session Key */
374*10023SGordon.Ross@Sun.COM 
375*10023SGordon.Ross@Sun.COM 	if (caps & SMB_CAP_EXT_SECURITY) {
376*10023SGordon.Ross@Sun.COM 		len1 = mbc1 ? mbc1->mb_count : 0;
377*10023SGordon.Ross@Sun.COM 		mb_put_uint16le(mbp, len1);	/* 7: Sec. Blob Len */
378*10023SGordon.Ross@Sun.COM 		mb_put_uint32le(mbp, 0);	/* 8,9: reserved */
379*10023SGordon.Ross@Sun.COM 		mb_put_uint32le(mbp, caps);	/* 10,11: Capabilities */
380*10023SGordon.Ross@Sun.COM 		smb_rq_wend(rqp);		/* 12: Byte Count */
381*10023SGordon.Ross@Sun.COM 		smb_rq_bstart(rqp);
382*10023SGordon.Ross@Sun.COM 		if (mbc1 && mbc1->mb_top) {
383*10023SGordon.Ross@Sun.COM 			mb_put_mbuf(mbp, mbc1->mb_top);	/* sec. blob */
384*10023SGordon.Ross@Sun.COM 			mbc1->mb_top = NULL; /* consumed */
385*10023SGordon.Ross@Sun.COM 		}
386*10023SGordon.Ross@Sun.COM 		/* mbc2 is required below */
387*10023SGordon.Ross@Sun.COM 		if (mbc2 == NULL) {
388*10023SGordon.Ross@Sun.COM 			err = EINVAL;
389*10023SGordon.Ross@Sun.COM 			goto out;
390*10023SGordon.Ross@Sun.COM 		}
391*10023SGordon.Ross@Sun.COM 	} else {
392*10023SGordon.Ross@Sun.COM 		len1 = mbc1 ? mbc1->mb_count : 0;
393*10023SGordon.Ross@Sun.COM 		len2 = mbc2 ? mbc2->mb_count : 0;
394*10023SGordon.Ross@Sun.COM 		mb_put_uint16le(mbp, len1);	/* 7: LM pass. len */
395*10023SGordon.Ross@Sun.COM 		mb_put_uint16le(mbp, len2);	/* 8: NT pass. len */
396*10023SGordon.Ross@Sun.COM 		mb_put_uint32le(mbp, 0);	/* 9,10: reserved */
397*10023SGordon.Ross@Sun.COM 		mb_put_uint32le(mbp, caps);	/* 11,12: Capabilities */
398*10023SGordon.Ross@Sun.COM 		smb_rq_wend(rqp);		/* 13: Byte Count */
399*10023SGordon.Ross@Sun.COM 		smb_rq_bstart(rqp);
400*10023SGordon.Ross@Sun.COM 		if (mbc1 && mbc1->mb_top) {
401*10023SGordon.Ross@Sun.COM 			mb_put_mbuf(mbp, mbc1->mb_top);	/* LM password */
402*10023SGordon.Ross@Sun.COM 			mbc1->mb_top = NULL; /* consumed */
403*10023SGordon.Ross@Sun.COM 		}
404*10023SGordon.Ross@Sun.COM 		if (mbc2 && mbc2->mb_top) {
405*10023SGordon.Ross@Sun.COM 			mb_put_mbuf(mbp, mbc2->mb_top);	/* NT password */
406*10023SGordon.Ross@Sun.COM 			mbc2->mb_top = NULL; /* consumed */
407*10023SGordon.Ross@Sun.COM 		}
408*10023SGordon.Ross@Sun.COM 		mb_put_dstring(mbp, ctx->ct_user, uc);
409*10023SGordon.Ross@Sun.COM 		mb_put_dstring(mbp, ctx->ct_domain, uc);
410*10023SGordon.Ross@Sun.COM 	}
411*10023SGordon.Ross@Sun.COM 	mb_put_dstring(mbp, NativeOS, uc);
412*10023SGordon.Ross@Sun.COM 	mb_put_dstring(mbp, LanMan, uc);
413*10023SGordon.Ross@Sun.COM 	smb_rq_bend(rqp);
414*10023SGordon.Ross@Sun.COM 
415*10023SGordon.Ross@Sun.COM 	err = smb_rq_internal(ctx, rqp);
416*10023SGordon.Ross@Sun.COM 	if (err)
417*10023SGordon.Ross@Sun.COM 		goto out;
418*10023SGordon.Ross@Sun.COM 
419*10023SGordon.Ross@Sun.COM 	if (statusp)
420*10023SGordon.Ross@Sun.COM 		*statusp = rqp->rq_status;
421*10023SGordon.Ross@Sun.COM 
422*10023SGordon.Ross@Sun.COM 	/*
423*10023SGordon.Ross@Sun.COM 	 * If we have a real error, the response probably has
424*10023SGordon.Ross@Sun.COM 	 * no more data, so don't try to parse any more.
425*10023SGordon.Ross@Sun.COM 	 * Note: err=0, means rq_status is valid.
426*10023SGordon.Ross@Sun.COM 	 */
427*10023SGordon.Ross@Sun.COM 	if (rqp->rq_status != 0 &&
428*10023SGordon.Ross@Sun.COM 	    rqp->rq_status != STATUS_MORE_PROCESSING_REQUIRED) {
429*10023SGordon.Ross@Sun.COM 		goto out;
430*10023SGordon.Ross@Sun.COM 	}
431*10023SGordon.Ross@Sun.COM 
432*10023SGordon.Ross@Sun.COM 	/*
433*10023SGordon.Ross@Sun.COM 	 * Parse the reply
434*10023SGordon.Ross@Sun.COM 	 */
435*10023SGordon.Ross@Sun.COM 	uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
436*10023SGordon.Ross@Sun.COM 	is->is_smbuid = rqp->rq_uid;
437*10023SGordon.Ross@Sun.COM 	mbp = &rqp->rq_rp;
438*10023SGordon.Ross@Sun.COM 
439*10023SGordon.Ross@Sun.COM 	err = mb_get_uint8(mbp, &wc);
440*10023SGordon.Ross@Sun.COM 	if (err)
441*10023SGordon.Ross@Sun.COM 		goto out;
442*10023SGordon.Ross@Sun.COM 
443*10023SGordon.Ross@Sun.COM 	err = EBADRPC; /* for any problems in this section */
444*10023SGordon.Ross@Sun.COM 	if (caps & SMB_CAP_EXT_SECURITY) {
445*10023SGordon.Ross@Sun.COM 		if (wc != 4)
446*10023SGordon.Ross@Sun.COM 			goto out;
447*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, NULL);	/* secondary cmd */
448*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, NULL);	/* andxoffset */
449*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, actionp);	/* action */
450*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, &sblen);	/* sec. blob len */
451*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, &bc);	/* byte count */
452*10023SGordon.Ross@Sun.COM 		/*
453*10023SGordon.Ross@Sun.COM 		 * Get the security blob, after
454*10023SGordon.Ross@Sun.COM 		 * sanity-checking the length.
455*10023SGordon.Ross@Sun.COM 		 */
456*10023SGordon.Ross@Sun.COM 		if (sblen == 0 || bc < sblen)
457*10023SGordon.Ross@Sun.COM 			goto out;
458*10023SGordon.Ross@Sun.COM 		err = mb_get_mbuf(mbp, sblen, &m);
459*10023SGordon.Ross@Sun.COM 		if (err)
460*10023SGordon.Ross@Sun.COM 			goto out;
461*10023SGordon.Ross@Sun.COM 		mb_initm(mbc2, m);
462*10023SGordon.Ross@Sun.COM 		mbc2->mb_count = sblen;
463*10023SGordon.Ross@Sun.COM 	} else {
464*10023SGordon.Ross@Sun.COM 		if (wc != 3)
465*10023SGordon.Ross@Sun.COM 			goto out;
466*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, NULL);	/* secondary cmd */
467*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, NULL);	/* andxoffset */
468*10023SGordon.Ross@Sun.COM 		mb_get_uint16le(mbp, actionp);	/* action */
469*10023SGordon.Ross@Sun.COM 		err = mb_get_uint16le(mbp, &bc); /* byte count */
470*10023SGordon.Ross@Sun.COM 		if (err)
471*10023SGordon.Ross@Sun.COM 			goto out;
472*10023SGordon.Ross@Sun.COM 	}
473*10023SGordon.Ross@Sun.COM 
474*10023SGordon.Ross@Sun.COM 	/*
475*10023SGordon.Ross@Sun.COM 	 * Native OS, LANMGR, & Domain follow here.
476*10023SGordon.Ross@Sun.COM 	 * Parse these strings and store for later.
477*10023SGordon.Ross@Sun.COM 	 * If unicode, they should be aligned.
478*10023SGordon.Ross@Sun.COM 	 *
479*10023SGordon.Ross@Sun.COM 	 * Note that with Extended security, we may use
480*10023SGordon.Ross@Sun.COM 	 * multiple calls to this function.  Only parse
481*10023SGordon.Ross@Sun.COM 	 * these strings on the last one (status == 0).
482*10023SGordon.Ross@Sun.COM 	 * Ditto for the CAP_LARGE work-around.
483*10023SGordon.Ross@Sun.COM 	 */
484*10023SGordon.Ross@Sun.COM 	if (rqp->rq_status != 0)
485*10023SGordon.Ross@Sun.COM 		goto out;
486*10023SGordon.Ross@Sun.COM 
487*10023SGordon.Ross@Sun.COM 	/* Ignore any parsing errors for these strings. */
488*10023SGordon.Ross@Sun.COM 	err = mb_get_string(mbp, &ctx->ct_srv_OS, uc);
489*10023SGordon.Ross@Sun.COM 	DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
490*10023SGordon.Ross@Sun.COM 	err = mb_get_string(mbp, &ctx->ct_srv_LM, uc);
491*10023SGordon.Ross@Sun.COM 	DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
492*10023SGordon.Ross@Sun.COM 	/*
493*10023SGordon.Ross@Sun.COM 	 * There's sometimes a server domain folloing
494*10023SGordon.Ross@Sun.COM 	 * at this point, but we don't need it.
495*10023SGordon.Ross@Sun.COM 	 */
496*10023SGordon.Ross@Sun.COM 
497*10023SGordon.Ross@Sun.COM 	/* Success! (See Ignore any ... above) */
498*10023SGordon.Ross@Sun.COM 	err = 0;
499*10023SGordon.Ross@Sun.COM 
500*10023SGordon.Ross@Sun.COM 	/*
501*10023SGordon.Ross@Sun.COM 	 * Windows systems don't suport CAP_LARGE_READX,WRITEX
502*10023SGordon.Ross@Sun.COM 	 * when signing is enabled, so adjust sv_caps.
503*10023SGordon.Ross@Sun.COM 	 */
504*10023SGordon.Ross@Sun.COM 	if (ctx->ct_srv_OS &&
505*10023SGordon.Ross@Sun.COM 	    0 == strncmp(ctx->ct_srv_OS, "Windows ", 8)) {
506*10023SGordon.Ross@Sun.COM 		DPRINT("Server is Windows");
507*10023SGordon.Ross@Sun.COM 		if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
508*10023SGordon.Ross@Sun.COM 			DPRINT("disable CAP_LARGE_(r/w)");
509*10023SGordon.Ross@Sun.COM 			ctx->ct_sopt.sv_caps &=
510*10023SGordon.Ross@Sun.COM 			    ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
511*10023SGordon.Ross@Sun.COM 		}
512*10023SGordon.Ross@Sun.COM 	}
513*10023SGordon.Ross@Sun.COM 
514*10023SGordon.Ross@Sun.COM out:
515*10023SGordon.Ross@Sun.COM 	if (rqp)
516*10023SGordon.Ross@Sun.COM 		smb_rq_done(rqp);
517*10023SGordon.Ross@Sun.COM 
518*10023SGordon.Ross@Sun.COM 	return (err);
519*10023SGordon.Ross@Sun.COM }
520