xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_ntlmssp.c (revision 12b65585e720714b31036daaa2b30eb76014048e)
1*12b65585SGordon Ross /*
2*12b65585SGordon Ross  * This file and its contents are supplied under the terms of the
3*12b65585SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4*12b65585SGordon Ross  * You may only use this file in accordance with the terms of version
5*12b65585SGordon Ross  * 1.0 of the CDDL.
6*12b65585SGordon Ross  *
7*12b65585SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8*12b65585SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9*12b65585SGordon Ross  * http://www.illumos.org/license/CDDL.
10*12b65585SGordon Ross  */
11*12b65585SGordon Ross 
12*12b65585SGordon Ross /*
13*12b65585SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14*12b65585SGordon Ross  */
15*12b65585SGordon Ross 
16*12b65585SGordon Ross /*
17*12b65585SGordon Ross  * SPNEGO back-end for NTLMSSP.  See [MS-NLMP]
18*12b65585SGordon Ross  */
19*12b65585SGordon Ross 
20*12b65585SGordon Ross #include <sys/types.h>
21*12b65585SGordon Ross #include <sys/byteorder.h>
22*12b65585SGordon Ross #include <strings.h>
23*12b65585SGordon Ross #include "smbd.h"
24*12b65585SGordon Ross #include "smbd_authsvc.h"
25*12b65585SGordon Ross #include "netsmb/ntlmssp.h"
26*12b65585SGordon Ross #include <assert.h>
27*12b65585SGordon Ross 
28*12b65585SGordon Ross /* A shorter alias for a crazy long name from [MS-NLMP] */
29*12b65585SGordon Ross #define	NTLMSSP_NEGOTIATE_NTLM2 \
30*12b65585SGordon Ross 	NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
31*12b65585SGordon Ross 
32*12b65585SGordon Ross /* Need this in a header somewhere */
33*12b65585SGordon Ross #ifdef _LITTLE_ENDIAN
34*12b65585SGordon Ross /* little-endian values on little-endian */
35*12b65585SGordon Ross #define	htolel(x)	((uint32_t)(x))
36*12b65585SGordon Ross #define	letohl(x)	((uint32_t)(x))
37*12b65585SGordon Ross #else	/* (BYTE_ORDER == LITTLE_ENDIAN) */
38*12b65585SGordon Ross /* little-endian values on big-endian (swap) */
39*12b65585SGordon Ross #define	letohl(x) 	BSWAP_32(x)
40*12b65585SGordon Ross #define	htolel(x) 	BSWAP_32(x)
41*12b65585SGordon Ross #endif	/* (BYTE_ORDER == LITTLE_ENDIAN) */
42*12b65585SGordon Ross 
43*12b65585SGordon Ross typedef struct ntlmssp_backend {
44*12b65585SGordon Ross 	uint32_t expect_type;
45*12b65585SGordon Ross 	uint32_t clnt_flags;
46*12b65585SGordon Ross 	uint32_t srv_flags;
47*12b65585SGordon Ross 	char srv_challenge[8];
48*12b65585SGordon Ross } ntlmssp_backend_t;
49*12b65585SGordon Ross 
50*12b65585SGordon Ross struct genhdr {
51*12b65585SGordon Ross 	char h_id[8];	/* "NTLMSSP" */
52*12b65585SGordon Ross 	uint32_t h_type;
53*12b65585SGordon Ross };
54*12b65585SGordon Ross 
55*12b65585SGordon Ross struct sec_buf {
56*12b65585SGordon Ross 	uint16_t sb_length;
57*12b65585SGordon Ross 	uint16_t sb_maxlen;
58*12b65585SGordon Ross 	uint32_t sb_offset;
59*12b65585SGordon Ross };
60*12b65585SGordon Ross 
61*12b65585SGordon Ross struct nego_hdr {
62*12b65585SGordon Ross 	char h_id[8];
63*12b65585SGordon Ross 	uint32_t h_type;
64*12b65585SGordon Ross 	uint32_t h_flags;
65*12b65585SGordon Ross 	/* workstation domain, name (place holders) */
66*12b65585SGordon Ross 	uint16_t ws_dom[4];
67*12b65585SGordon Ross 	uint16_t ws_name[4];
68*12b65585SGordon Ross };
69*12b65585SGordon Ross 
70*12b65585SGordon Ross struct auth_hdr {
71*12b65585SGordon Ross 	char h_id[8];
72*12b65585SGordon Ross 	uint32_t h_type;
73*12b65585SGordon Ross 	struct sec_buf h_lm_resp;
74*12b65585SGordon Ross 	struct sec_buf h_nt_resp;
75*12b65585SGordon Ross 	struct sec_buf h_domain;
76*12b65585SGordon Ross 	struct sec_buf h_user;
77*12b65585SGordon Ross 	struct sec_buf h_wksta;
78*12b65585SGordon Ross 	struct sec_buf h_essn_key; /* encrypted session key */
79*12b65585SGordon Ross 	uint32_t h_flags;
80*12b65585SGordon Ross 	/* Version struct (optional) */
81*12b65585SGordon Ross 	/* MIC hash (optional) */
82*12b65585SGordon Ross };
83*12b65585SGordon Ross 
84*12b65585SGordon Ross /* Allow turning these off for debugging, etc. */
85*12b65585SGordon Ross int smbd_signing_enabled = 1;
86*12b65585SGordon Ross 
87*12b65585SGordon Ross int smbd_constant_challenge = 0;
88*12b65585SGordon Ross static uint8_t constant_chal[8] = {
89*12b65585SGordon Ross     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
90*12b65585SGordon Ross 
91*12b65585SGordon Ross static int smbd_ntlmssp_negotiate(authsvc_context_t *);
92*12b65585SGordon Ross static int smbd_ntlmssp_authenticate(authsvc_context_t *);
93*12b65585SGordon Ross static int encode_avpair_str(smb_msgbuf_t *, uint16_t, char *);
94*12b65585SGordon Ross static int decode_secbuf_bin(smb_msgbuf_t *, struct sec_buf *, void **);
95*12b65585SGordon Ross static int decode_secbuf_str(smb_msgbuf_t *, struct sec_buf *, char **);
96*12b65585SGordon Ross 
97*12b65585SGordon Ross /*
98*12b65585SGordon Ross  * Initialize this context for NTLMSSP, if possible.
99*12b65585SGordon Ross  */
100*12b65585SGordon Ross int
101*12b65585SGordon Ross smbd_ntlmssp_init(authsvc_context_t *ctx)
102*12b65585SGordon Ross {
103*12b65585SGordon Ross 	ntlmssp_backend_t *be;
104*12b65585SGordon Ross 
105*12b65585SGordon Ross 	be = malloc(sizeof (*be));
106*12b65585SGordon Ross 	if (be == 0)
107*12b65585SGordon Ross 		return (NT_STATUS_NO_MEMORY);
108*12b65585SGordon Ross 	bzero(be, sizeof (*be));
109*12b65585SGordon Ross 	be->expect_type = NTLMSSP_MSGTYPE_NEGOTIATE;
110*12b65585SGordon Ross 	ctx->ctx_backend = be;
111*12b65585SGordon Ross 
112*12b65585SGordon Ross 	return (0);
113*12b65585SGordon Ross }
114*12b65585SGordon Ross 
115*12b65585SGordon Ross void
116*12b65585SGordon Ross smbd_ntlmssp_fini(authsvc_context_t *ctx)
117*12b65585SGordon Ross {
118*12b65585SGordon Ross 	free(ctx->ctx_backend);
119*12b65585SGordon Ross }
120*12b65585SGordon Ross 
121*12b65585SGordon Ross /*
122*12b65585SGordon Ross  * Handle an auth message
123*12b65585SGordon Ross  */
124*12b65585SGordon Ross int
125*12b65585SGordon Ross smbd_ntlmssp_work(authsvc_context_t *ctx)
126*12b65585SGordon Ross {
127*12b65585SGordon Ross 	struct genhdr *ihdr = ctx->ctx_ibodybuf;
128*12b65585SGordon Ross 	ntlmssp_backend_t *be = ctx->ctx_backend;
129*12b65585SGordon Ross 	uint32_t mtype;
130*12b65585SGordon Ross 	int rc;
131*12b65585SGordon Ross 
132*12b65585SGordon Ross 	if (ctx->ctx_ibodylen < sizeof (*ihdr))
133*12b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
134*12b65585SGordon Ross 
135*12b65585SGordon Ross 	if (bcmp(ihdr->h_id, "NTLMSSP", 8))
136*12b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
137*12b65585SGordon Ross 	mtype = letohl(ihdr->h_type);
138*12b65585SGordon Ross 	if (mtype != be->expect_type)
139*12b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
140*12b65585SGordon Ross 
141*12b65585SGordon Ross 	switch (mtype) {
142*12b65585SGordon Ross 	case NTLMSSP_MSGTYPE_NEGOTIATE:
143*12b65585SGordon Ross 		ctx->ctx_orawtype = LSA_MTYPE_ES_CONT;
144*12b65585SGordon Ross 		rc = smbd_ntlmssp_negotiate(ctx);
145*12b65585SGordon Ross 		break;
146*12b65585SGordon Ross 	case NTLMSSP_MSGTYPE_AUTHENTICATE:
147*12b65585SGordon Ross 		ctx->ctx_orawtype = LSA_MTYPE_ES_DONE;
148*12b65585SGordon Ross 		rc = smbd_ntlmssp_authenticate(ctx);
149*12b65585SGordon Ross 		break;
150*12b65585SGordon Ross 
151*12b65585SGordon Ross 	default:
152*12b65585SGordon Ross 	case NTLMSSP_MSGTYPE_CHALLENGE:
153*12b65585SGordon Ross 		/* Sent by servers, not received. */
154*12b65585SGordon Ross 		rc = NT_STATUS_INVALID_PARAMETER;
155*12b65585SGordon Ross 		break;
156*12b65585SGordon Ross 	}
157*12b65585SGordon Ross 
158*12b65585SGordon Ross 	return (rc);
159*12b65585SGordon Ross }
160*12b65585SGordon Ross 
161*12b65585SGordon Ross #if (MAXHOSTNAMELEN < NETBIOS_NAME_SZ)
162*12b65585SGordon Ross #error "MAXHOSTNAMELEN < NETBIOS_NAME_SZ"
163*12b65585SGordon Ross #endif
164*12b65585SGordon Ross 
165*12b65585SGordon Ross /*
166*12b65585SGordon Ross  * Handle an NTLMSSP_MSGTYPE_NEGOTIATE message, and reply
167*12b65585SGordon Ross  * with an NTLMSSP_MSGTYPE_CHALLENGE message.
168*12b65585SGordon Ross  * See: [MS-NLMP] 2.2.1.1, 3.2.5.1.1
169*12b65585SGordon Ross  */
170*12b65585SGordon Ross static int
171*12b65585SGordon Ross smbd_ntlmssp_negotiate(authsvc_context_t *ctx)
172*12b65585SGordon Ross {
173*12b65585SGordon Ross 	char tmp_name[MAXHOSTNAMELEN];
174*12b65585SGordon Ross 	ntlmssp_backend_t *be = ctx->ctx_backend;
175*12b65585SGordon Ross 	struct nego_hdr *ihdr = ctx->ctx_ibodybuf;
176*12b65585SGordon Ross 	smb_msgbuf_t mb;
177*12b65585SGordon Ross 	uint8_t *save_scan;
178*12b65585SGordon Ross 	int secmode;
179*12b65585SGordon Ross 	int mbflags;
180*12b65585SGordon Ross 	int rc;
181*12b65585SGordon Ross 	size_t var_start, var_end;
182*12b65585SGordon Ross 	uint16_t var_size;
183*12b65585SGordon Ross 
184*12b65585SGordon Ross 	if (ctx->ctx_ibodylen < sizeof (*ihdr))
185*12b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
186*12b65585SGordon Ross 	be->clnt_flags = letohl(ihdr->h_flags);
187*12b65585SGordon Ross 
188*12b65585SGordon Ross 	/*
189*12b65585SGordon Ross 	 * Looks like we can ignore ws_dom, ws_name.
190*12b65585SGordon Ross 	 * Otherwise would parse those here.
191*12b65585SGordon Ross 	 */
192*12b65585SGordon Ross 
193*12b65585SGordon Ross 	secmode = smb_config_get_secmode();
194*12b65585SGordon Ross 	if (smbd_constant_challenge) {
195*12b65585SGordon Ross 		(void) memcpy(be->srv_challenge, constant_chal,
196*12b65585SGordon Ross 		    sizeof (be->srv_challenge));
197*12b65585SGordon Ross 	} else {
198*12b65585SGordon Ross 		randomize(be->srv_challenge, sizeof (be->srv_challenge));
199*12b65585SGordon Ross 	}
200*12b65585SGordon Ross 
201*12b65585SGordon Ross 	/*
202*12b65585SGordon Ross 	 * Compute srv_flags
203*12b65585SGordon Ross 	 */
204*12b65585SGordon Ross 	be->srv_flags =
205*12b65585SGordon Ross 	    NTLMSSP_REQUEST_TARGET |
206*12b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_NTLM |
207*12b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_TARGET_INFO;
208*12b65585SGordon Ross 	be->srv_flags |= be->clnt_flags & (
209*12b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_NTLM2 |
210*12b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_128 |
211*12b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_KEY_EXCH |
212*12b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_56);
213*12b65585SGordon Ross 
214*12b65585SGordon Ross 	if (smbd_signing_enabled) {
215*12b65585SGordon Ross 		be->srv_flags |= be->clnt_flags & (
216*12b65585SGordon Ross 		    NTLMSSP_NEGOTIATE_SIGN |
217*12b65585SGordon Ross 		    NTLMSSP_NEGOTIATE_SEAL |
218*12b65585SGordon Ross 		    NTLMSSP_NEGOTIATE_ALWAYS_SIGN);
219*12b65585SGordon Ross 	}
220*12b65585SGordon Ross 
221*12b65585SGordon Ross 	if (be->clnt_flags & NTLMSSP_NEGOTIATE_UNICODE)
222*12b65585SGordon Ross 		be->srv_flags |= NTLMSSP_NEGOTIATE_UNICODE;
223*12b65585SGordon Ross 	else if (be->clnt_flags & NTLMSSP_NEGOTIATE_OEM)
224*12b65585SGordon Ross 		be->srv_flags |= NTLMSSP_NEGOTIATE_OEM;
225*12b65585SGordon Ross 
226*12b65585SGordon Ross 	/* LM Key is mutually exclusive with NTLM2 */
227*12b65585SGordon Ross 	if ((be->srv_flags & NTLMSSP_NEGOTIATE_NTLM2) == 0 &&
228*12b65585SGordon Ross 	    (be->clnt_flags & NTLMSSP_NEGOTIATE_LM_KEY) != 0)
229*12b65585SGordon Ross 		be->srv_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
230*12b65585SGordon Ross 
231*12b65585SGordon Ross 	/* Get our "target name" */
232*12b65585SGordon Ross 	if (secmode == SMB_SECMODE_DOMAIN) {
233*12b65585SGordon Ross 		be->srv_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
234*12b65585SGordon Ross 		rc = smb_getdomainname(tmp_name, NETBIOS_NAME_SZ);
235*12b65585SGordon Ross 	} else {
236*12b65585SGordon Ross 		be->srv_flags |= NTLMSSP_TARGET_TYPE_SERVER;
237*12b65585SGordon Ross 		rc = smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ);
238*12b65585SGordon Ross 	}
239*12b65585SGordon Ross 	if (rc)
240*12b65585SGordon Ross 		goto errout;
241*12b65585SGordon Ross 
242*12b65585SGordon Ross 	/*
243*12b65585SGordon Ross 	 * Build the NTLMSSP_MSGTYPE_CHALLENGE message.
244*12b65585SGordon Ross 	 */
245*12b65585SGordon Ross 	mbflags = SMB_MSGBUF_NOTERM;
246*12b65585SGordon Ross 	if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE)
247*12b65585SGordon Ross 		mbflags |= SMB_MSGBUF_UNICODE;
248*12b65585SGordon Ross 	smb_msgbuf_init(&mb, ctx->ctx_obodybuf, ctx->ctx_obodylen, mbflags);
249*12b65585SGordon Ross 
250*12b65585SGordon Ross 	/*
251*12b65585SGordon Ross 	 * Fixed size parts
252*12b65585SGordon Ross 	 */
253*12b65585SGordon Ross 	rc = smb_msgbuf_encode(
254*12b65585SGordon Ross 	    &mb, "8clwwll8cllwwl",	/* offset, name (fmt) */
255*12b65585SGordon Ross 	    "NTLMSSP",			/* 0: signature (8c) */
256*12b65585SGordon Ross 	    NTLMSSP_MSGTYPE_CHALLENGE,	/* 8: type	(l) */
257*12b65585SGordon Ross 	    0, 0, 0,	/* filled later:   12: target name (wwl) */
258*12b65585SGordon Ross 	    be->srv_flags,		/* 20: flags	(l) */
259*12b65585SGordon Ross 	    be->srv_challenge,		/* 24: 		(8c) */
260*12b65585SGordon Ross 	    0, 0,			/* 32: reserved (ll) */
261*12b65585SGordon Ross 	    0, 0, 0);	/* filled later:   40: target info (wwl) */
262*12b65585SGordon Ross #define	TARGET_NAME_OFFSET	12
263*12b65585SGordon Ross #define	TARGET_INFO_OFFSET	40
264*12b65585SGordon Ross 	if (rc < 0)
265*12b65585SGordon Ross 		goto errout;
266*12b65585SGordon Ross 
267*12b65585SGordon Ross 	/*
268*12b65585SGordon Ross 	 * Variable length parts.
269*12b65585SGordon Ross 	 *
270*12b65585SGordon Ross 	 * Target name
271*12b65585SGordon Ross 	 */
272*12b65585SGordon Ross 	var_start = smb_msgbuf_used(&mb);
273*12b65585SGordon Ross 	rc = smb_msgbuf_encode(&mb, "u", tmp_name);
274*12b65585SGordon Ross 	var_end = smb_msgbuf_used(&mb);
275*12b65585SGordon Ross 	var_size = (uint16_t)(var_end - var_start);
276*12b65585SGordon Ross 	if (rc < 0)
277*12b65585SGordon Ross 		goto errout;
278*12b65585SGordon Ross 
279*12b65585SGordon Ross 	/* overwrite target name offset+lengths */
280*12b65585SGordon Ross 	save_scan = mb.scan;
281*12b65585SGordon Ross 	mb.scan = mb.base + TARGET_NAME_OFFSET;
282*12b65585SGordon Ross 	(void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start);
283*12b65585SGordon Ross 	mb.scan = save_scan;
284*12b65585SGordon Ross 
285*12b65585SGordon Ross 	/*
286*12b65585SGordon Ross 	 * Target info (AvPairList)
287*12b65585SGordon Ross 	 *
288*12b65585SGordon Ross 	 * These AV pairs are like our name/value pairs, but have
289*12b65585SGordon Ross 	 * numeric identifiers instead of names.  There are many
290*12b65585SGordon Ross 	 * of these, but we put only the four expected by Windows:
291*12b65585SGordon Ross 	 *	NetBIOS computer name
292*12b65585SGordon Ross 	 *	NetBIOS domain name
293*12b65585SGordon Ross 	 *	DNS computer name
294*12b65585SGordon Ross 	 *	DNS domain name
295*12b65585SGordon Ross 	 * Note that "domain" above (even "DNS domain") refers to
296*12b65585SGordon Ross 	 * the AD domain of which we're a member, which may be
297*12b65585SGordon Ross 	 * _different_ from the configured DNS domain.
298*12b65585SGordon Ross 	 *
299*12b65585SGordon Ross 	 * Also note that in "workgroup" mode (not a domain member)
300*12b65585SGordon Ross 	 * all "domain" fields should be set to the same values as
301*12b65585SGordon Ross 	 * the "computer" fields ("bare" host name, not FQDN).
302*12b65585SGordon Ross 	 */
303*12b65585SGordon Ross 	var_start = smb_msgbuf_used(&mb);
304*12b65585SGordon Ross 
305*12b65585SGordon Ross 	/* NetBIOS Computer Name */
306*12b65585SGordon Ross 	if (smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ))
307*12b65585SGordon Ross 		goto errout;
308*12b65585SGordon Ross 	if (encode_avpair_str(&mb, MsvAvNbComputerName, tmp_name) < 0)
309*12b65585SGordon Ross 		goto errout;
310*12b65585SGordon Ross 
311*12b65585SGordon Ross 	if (secmode != SMB_SECMODE_DOMAIN) {
312*12b65585SGordon Ross 		/*
313*12b65585SGordon Ross 		 * Workgroup mode.  Set all to hostname.
314*12b65585SGordon Ross 		 * tmp_name = netbios hostname from above.
315*12b65585SGordon Ross 		 */
316*12b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0)
317*12b65585SGordon Ross 			goto errout;
318*12b65585SGordon Ross 		/*
319*12b65585SGordon Ross 		 * Want the bare computer name here (not FQDN).
320*12b65585SGordon Ross 		 */
321*12b65585SGordon Ross 		if (smb_gethostname(tmp_name, MAXHOSTNAMELEN, SMB_CASE_LOWER))
322*12b65585SGordon Ross 			goto errout;
323*12b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0)
324*12b65585SGordon Ross 			goto errout;
325*12b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0)
326*12b65585SGordon Ross 			goto errout;
327*12b65585SGordon Ross 	} else {
328*12b65585SGordon Ross 		/*
329*12b65585SGordon Ross 		 * Domain mode.  Use real host and domain values.
330*12b65585SGordon Ross 		 */
331*12b65585SGordon Ross 
332*12b65585SGordon Ross 		/* NetBIOS Domain Name */
333*12b65585SGordon Ross 		if (smb_getdomainname(tmp_name, NETBIOS_NAME_SZ))
334*12b65585SGordon Ross 			goto errout;
335*12b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0)
336*12b65585SGordon Ross 			goto errout;
337*12b65585SGordon Ross 
338*12b65585SGordon Ross 		/* DNS Computer Name */
339*12b65585SGordon Ross 		if (smb_getfqhostname(tmp_name, MAXHOSTNAMELEN))
340*12b65585SGordon Ross 			goto errout;
341*12b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0)
342*12b65585SGordon Ross 			goto errout;
343*12b65585SGordon Ross 
344*12b65585SGordon Ross 		/* DNS Domain Name */
345*12b65585SGordon Ross 		if (smb_getfqdomainname(tmp_name, MAXHOSTNAMELEN))
346*12b65585SGordon Ross 			goto errout;
347*12b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0)
348*12b65585SGordon Ross 			goto errout;
349*12b65585SGordon Ross 	}
350*12b65585SGordon Ross 
351*12b65585SGordon Ross 	/* End marker */
352*12b65585SGordon Ross 	if (smb_msgbuf_encode(&mb, "ww", MsvAvEOL, 0) < 0)
353*12b65585SGordon Ross 		goto errout;
354*12b65585SGordon Ross 	var_end = smb_msgbuf_used(&mb);
355*12b65585SGordon Ross 	var_size = (uint16_t)(var_end - var_start);
356*12b65585SGordon Ross 
357*12b65585SGordon Ross 	/* overwrite target  offset+lengths */
358*12b65585SGordon Ross 	save_scan = mb.scan;
359*12b65585SGordon Ross 	mb.scan = mb.base + TARGET_INFO_OFFSET;
360*12b65585SGordon Ross 	(void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start);
361*12b65585SGordon Ross 	mb.scan = save_scan;
362*12b65585SGordon Ross 
363*12b65585SGordon Ross 	ctx->ctx_obodylen = smb_msgbuf_used(&mb);
364*12b65585SGordon Ross 	smb_msgbuf_term(&mb);
365*12b65585SGordon Ross 
366*12b65585SGordon Ross 	be->expect_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
367*12b65585SGordon Ross 
368*12b65585SGordon Ross 	return (0);
369*12b65585SGordon Ross 
370*12b65585SGordon Ross errout:
371*12b65585SGordon Ross 	smb_msgbuf_term(&mb);
372*12b65585SGordon Ross 	return (NT_STATUS_INTERNAL_ERROR);
373*12b65585SGordon Ross }
374*12b65585SGordon Ross 
375*12b65585SGordon Ross static int
376*12b65585SGordon Ross encode_avpair_str(smb_msgbuf_t *mb, uint16_t AvId, char *name)
377*12b65585SGordon Ross {
378*12b65585SGordon Ross 	int rc;
379*12b65585SGordon Ross 	uint16_t len;
380*12b65585SGordon Ross 
381*12b65585SGordon Ross 	len = smb_wcequiv_strlen(name);
382*12b65585SGordon Ross 	rc = smb_msgbuf_encode(mb, "wwU", AvId, len, name);
383*12b65585SGordon Ross 	return (rc);
384*12b65585SGordon Ross }
385*12b65585SGordon Ross 
386*12b65585SGordon Ross /*
387*12b65585SGordon Ross  * Handle an NTLMSSP_MSGTYPE_AUTHENTICATE message.
388*12b65585SGordon Ross  * See: [MS-NLMP] 2.2.1.3, 3.2.5.1.2
389*12b65585SGordon Ross  */
390*12b65585SGordon Ross static int
391*12b65585SGordon Ross smbd_ntlmssp_authenticate(authsvc_context_t *ctx)
392*12b65585SGordon Ross {
393*12b65585SGordon Ross 	struct auth_hdr hdr;
394*12b65585SGordon Ross 	smb_msgbuf_t mb;
395*12b65585SGordon Ross 	smb_logon_t	user_info;
396*12b65585SGordon Ross 	smb_token_t	*token = NULL;
397*12b65585SGordon Ross 	ntlmssp_backend_t *be = ctx->ctx_backend;
398*12b65585SGordon Ross 	void *lm_resp;
399*12b65585SGordon Ross 	void *nt_resp;
400*12b65585SGordon Ross 	char *domain;
401*12b65585SGordon Ross 	char *user;
402*12b65585SGordon Ross 	char *wksta;
403*12b65585SGordon Ross 	void *essn_key;	/* encrypted session key (optional) */
404*12b65585SGordon Ross 	int mbflags;
405*12b65585SGordon Ross 	uint_t status = NT_STATUS_INTERNAL_ERROR;
406*12b65585SGordon Ross 	char combined_challenge[SMBAUTH_CHAL_SZ];
407*12b65585SGordon Ross 	unsigned char kxkey[SMBAUTH_HASH_SZ];
408*12b65585SGordon Ross 	boolean_t ntlm_v1x = B_FALSE;
409*12b65585SGordon Ross 
410*12b65585SGordon Ross 	bzero(&user_info, sizeof (user_info));
411*12b65585SGordon Ross 
412*12b65585SGordon Ross 	/*
413*12b65585SGordon Ross 	 * Parse the NTLMSSP_MSGTYPE_AUTHENTICATE message.
414*12b65585SGordon Ross 	 */
415*12b65585SGordon Ross 	if (ctx->ctx_ibodylen < sizeof (hdr))
416*12b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
417*12b65585SGordon Ross 	mbflags = SMB_MSGBUF_NOTERM;
418*12b65585SGordon Ross 	if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE)
419*12b65585SGordon Ross 		mbflags |= SMB_MSGBUF_UNICODE;
420*12b65585SGordon Ross 	smb_msgbuf_init(&mb, ctx->ctx_ibodybuf, ctx->ctx_ibodylen, mbflags);
421*12b65585SGordon Ross 	bzero(&hdr, sizeof (hdr));
422*12b65585SGordon Ross 
423*12b65585SGordon Ross 	if (smb_msgbuf_decode(&mb, "12.") < 0)
424*12b65585SGordon Ross 		goto errout;
425*12b65585SGordon Ross 	if (decode_secbuf_bin(&mb, &hdr.h_lm_resp, &lm_resp) < 0)
426*12b65585SGordon Ross 		goto errout;
427*12b65585SGordon Ross 	if (decode_secbuf_bin(&mb, &hdr.h_nt_resp, &nt_resp) < 0)
428*12b65585SGordon Ross 		goto errout;
429*12b65585SGordon Ross 	if (decode_secbuf_str(&mb, &hdr.h_domain, &domain) < 0)
430*12b65585SGordon Ross 		goto errout;
431*12b65585SGordon Ross 	if (decode_secbuf_str(&mb, &hdr.h_user, &user) < 0)
432*12b65585SGordon Ross 		goto errout;
433*12b65585SGordon Ross 	if (decode_secbuf_str(&mb, &hdr.h_wksta, &wksta) < 0)
434*12b65585SGordon Ross 		goto errout;
435*12b65585SGordon Ross 	if (decode_secbuf_bin(&mb, &hdr.h_essn_key, &essn_key) < 0)
436*12b65585SGordon Ross 		goto errout;
437*12b65585SGordon Ross 	if (smb_msgbuf_decode(&mb, "l", &be->clnt_flags) < 0)
438*12b65585SGordon Ross 		goto errout;
439*12b65585SGordon Ross 
440*12b65585SGordon Ross 	if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
441*12b65585SGordon Ross 		if (hdr.h_essn_key.sb_length < 16 || essn_key == NULL)
442*12b65585SGordon Ross 			goto errout;
443*12b65585SGordon Ross 	}
444*12b65585SGordon Ross 
445*12b65585SGordon Ross 	user_info.lg_level = NETR_NETWORK_LOGON;
446*12b65585SGordon Ross 	user_info.lg_flags = 0;
447*12b65585SGordon Ross 
448*12b65585SGordon Ross 	user_info.lg_ntlm_flags = be->clnt_flags;
449*12b65585SGordon Ross 	user_info.lg_username = (user) ? user : "";
450*12b65585SGordon Ross 	user_info.lg_domain = (domain) ? domain : "";
451*12b65585SGordon Ross 	user_info.lg_workstation = (wksta) ? wksta : "";
452*12b65585SGordon Ross 
453*12b65585SGordon Ross 	user_info.lg_clnt_ipaddr =
454*12b65585SGordon Ross 	    ctx->ctx_clinfo.lci_clnt_ipaddr;
455*12b65585SGordon Ross 	user_info.lg_local_port = 445;
456*12b65585SGordon Ross 
457*12b65585SGordon Ross 	user_info.lg_challenge_key.len = SMBAUTH_CHAL_SZ;
458*12b65585SGordon Ross 	user_info.lg_challenge_key.val = (uint8_t *)be->srv_challenge;
459*12b65585SGordon Ross 
460*12b65585SGordon Ross 	user_info.lg_nt_password.len = hdr.h_nt_resp.sb_length;
461*12b65585SGordon Ross 	user_info.lg_nt_password.val = nt_resp;
462*12b65585SGordon Ross 
463*12b65585SGordon Ross 	user_info.lg_lm_password.len = hdr.h_lm_resp.sb_length;
464*12b65585SGordon Ross 	user_info.lg_lm_password.val = lm_resp;
465*12b65585SGordon Ross 
466*12b65585SGordon Ross 	user_info.lg_native_os = ctx->ctx_clinfo.lci_native_os;
467*12b65585SGordon Ross 	user_info.lg_native_lm = ctx->ctx_clinfo.lci_native_lm;
468*12b65585SGordon Ross 
469*12b65585SGordon Ross 	/*
470*12b65585SGordon Ross 	 * If we're doing extended session security, the challenge
471*12b65585SGordon Ross 	 * this OWF was computed with is different. [MS-NLMP 3.3.1]
472*12b65585SGordon Ross 	 * It's: MD5(concat(ServerChallenge,ClientChallenge))
473*12b65585SGordon Ross 	 * where the ClientChallenge is in the LM resp. field.
474*12b65585SGordon Ross 	 */
475*12b65585SGordon Ross 	if (user_info.lg_nt_password.len == SMBAUTH_LM_RESP_SZ &&
476*12b65585SGordon Ross 	    user_info.lg_lm_password.len >= SMBAUTH_CHAL_SZ &&
477*12b65585SGordon Ross 	    (be->clnt_flags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {
478*12b65585SGordon Ross 		smb_auth_ntlm2_mkchallenge(combined_challenge,
479*12b65585SGordon Ross 		    be->srv_challenge, lm_resp);
480*12b65585SGordon Ross 		user_info.lg_challenge_key.val =
481*12b65585SGordon Ross 		    (uint8_t *)combined_challenge;
482*12b65585SGordon Ross 		user_info.lg_lm_password.len = 0;
483*12b65585SGordon Ross 		ntlm_v1x = B_TRUE;
484*12b65585SGordon Ross 	}
485*12b65585SGordon Ross 
486*12b65585SGordon Ross 	/*
487*12b65585SGordon Ross 	 * This (indirectly) calls smb_auth_validate() to
488*12b65585SGordon Ross 	 * check that the client gave us a valid hash.
489*12b65585SGordon Ross 	 */
490*12b65585SGordon Ross 	token = smbd_user_auth_logon(&user_info);
491*12b65585SGordon Ross 	if (token == NULL) {
492*12b65585SGordon Ross 		status = NT_STATUS_ACCESS_DENIED;
493*12b65585SGordon Ross 		goto errout;
494*12b65585SGordon Ross 	}
495*12b65585SGordon Ross 
496*12b65585SGordon Ross 	if (token->tkn_ssnkey.val != NULL &&
497*12b65585SGordon Ross 	    token->tkn_ssnkey.len == SMBAUTH_HASH_SZ) {
498*12b65585SGordon Ross 
499*12b65585SGordon Ross 		/*
500*12b65585SGordon Ross 		 * At this point, token->tkn_session_key is the
501*12b65585SGordon Ross 		 * "Session Base Key" [MS-NLMP] 3.2.5.1.2
502*12b65585SGordon Ross 		 * Compute the final session key.  First need the
503*12b65585SGordon Ross 		 * "Key Exchange Key" [MS-NLMP] 3.4.5.1
504*12b65585SGordon Ross 		 */
505*12b65585SGordon Ross 		if (ntlm_v1x) {
506*12b65585SGordon Ross 			smb_auth_ntlm2_kxkey(kxkey,
507*12b65585SGordon Ross 			    be->srv_challenge, lm_resp,
508*12b65585SGordon Ross 			    token->tkn_ssnkey.val);
509*12b65585SGordon Ross 		} else {
510*12b65585SGordon Ross 			/* KXKEY is the Session Base Key. */
511*12b65585SGordon Ross 			(void) memcpy(kxkey, token->tkn_ssnkey.val,
512*12b65585SGordon Ross 			    SMBAUTH_HASH_SZ);
513*12b65585SGordon Ross 		}
514*12b65585SGordon Ross 
515*12b65585SGordon Ross 		/*
516*12b65585SGordon Ross 		 * If the client give us an encrypted session key,
517*12b65585SGordon Ross 		 * decrypt it (RC4) using the "key exchange key".
518*12b65585SGordon Ross 		 */
519*12b65585SGordon Ross 		if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
520*12b65585SGordon Ross 			/* RC4 args: result, key, data */
521*12b65585SGordon Ross 			(void) smb_auth_RC4(token->tkn_ssnkey.val,
522*12b65585SGordon Ross 			    SMBAUTH_HASH_SZ, kxkey, SMBAUTH_HASH_SZ,
523*12b65585SGordon Ross 			    essn_key, hdr.h_essn_key.sb_length);
524*12b65585SGordon Ross 		} else {
525*12b65585SGordon Ross 			/* Final key is the KXKEY */
526*12b65585SGordon Ross 			(void) memcpy(token->tkn_ssnkey.val, kxkey,
527*12b65585SGordon Ross 			    SMBAUTH_HASH_SZ);
528*12b65585SGordon Ross 		}
529*12b65585SGordon Ross 	}
530*12b65585SGordon Ross 
531*12b65585SGordon Ross 	ctx->ctx_token = token;
532*12b65585SGordon Ross 	ctx->ctx_obodylen = 0;
533*12b65585SGordon Ross 
534*12b65585SGordon Ross 	smb_msgbuf_term(&mb);
535*12b65585SGordon Ross 	return (0);
536*12b65585SGordon Ross 
537*12b65585SGordon Ross errout:
538*12b65585SGordon Ross 	smb_msgbuf_term(&mb);
539*12b65585SGordon Ross 	return (status);
540*12b65585SGordon Ross }
541*12b65585SGordon Ross 
542*12b65585SGordon Ross static int
543*12b65585SGordon Ross decode_secbuf_bin(smb_msgbuf_t *mb, struct sec_buf *sb, void **binp)
544*12b65585SGordon Ross {
545*12b65585SGordon Ross 	int rc;
546*12b65585SGordon Ross 
547*12b65585SGordon Ross 	*binp = NULL;
548*12b65585SGordon Ross 	rc = smb_msgbuf_decode(
549*12b65585SGordon Ross 	    mb, "wwl",
550*12b65585SGordon Ross 	    &sb->sb_length,
551*12b65585SGordon Ross 	    &sb->sb_maxlen,
552*12b65585SGordon Ross 	    &sb->sb_offset);
553*12b65585SGordon Ross 	if (rc < 0)
554*12b65585SGordon Ross 		return (rc);
555*12b65585SGordon Ross 
556*12b65585SGordon Ross 	if (sb->sb_offset > mb->max)
557*12b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
558*12b65585SGordon Ross 	if (sb->sb_length > (mb->max - sb->sb_offset))
559*12b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
560*12b65585SGordon Ross 	if (sb->sb_length == 0)
561*12b65585SGordon Ross 		return (rc);
562*12b65585SGordon Ross 
563*12b65585SGordon Ross 	*binp = mb->base + sb->sb_offset;
564*12b65585SGordon Ross 	return (0);
565*12b65585SGordon Ross }
566*12b65585SGordon Ross 
567*12b65585SGordon Ross static int
568*12b65585SGordon Ross decode_secbuf_str(smb_msgbuf_t *mb, struct sec_buf *sb, char **cpp)
569*12b65585SGordon Ross {
570*12b65585SGordon Ross 	uint8_t *save_scan;
571*12b65585SGordon Ross 	int rc;
572*12b65585SGordon Ross 
573*12b65585SGordon Ross 	*cpp = NULL;
574*12b65585SGordon Ross 	rc = smb_msgbuf_decode(
575*12b65585SGordon Ross 	    mb, "wwl",
576*12b65585SGordon Ross 	    &sb->sb_length,
577*12b65585SGordon Ross 	    &sb->sb_maxlen,
578*12b65585SGordon Ross 	    &sb->sb_offset);
579*12b65585SGordon Ross 	if (rc < 0)
580*12b65585SGordon Ross 		return (rc);
581*12b65585SGordon Ross 
582*12b65585SGordon Ross 	if (sb->sb_offset > mb->max)
583*12b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
584*12b65585SGordon Ross 	if (sb->sb_length > (mb->max - sb->sb_offset))
585*12b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
586*12b65585SGordon Ross 	if (sb->sb_length == 0)
587*12b65585SGordon Ross 		return (rc);
588*12b65585SGordon Ross 
589*12b65585SGordon Ross 	save_scan = mb->scan;
590*12b65585SGordon Ross 	mb->scan = mb->base + sb->sb_offset;
591*12b65585SGordon Ross 	rc = smb_msgbuf_decode(mb, "#u", (int)sb->sb_length, cpp);
592*12b65585SGordon Ross 	mb->scan = save_scan;
593*12b65585SGordon Ross 
594*12b65585SGordon Ross 	return (rc);
595*12b65585SGordon Ross }
596