112b65585SGordon Ross /*
212b65585SGordon Ross  * This file and its contents are supplied under the terms of the
312b65585SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
412b65585SGordon Ross  * You may only use this file in accordance with the terms of version
512b65585SGordon Ross  * 1.0 of the CDDL.
612b65585SGordon Ross  *
712b65585SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
812b65585SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
912b65585SGordon Ross  * http://www.illumos.org/license/CDDL.
1012b65585SGordon Ross  */
1112b65585SGordon Ross 
1212b65585SGordon Ross /*
13*975041ddSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
1412b65585SGordon Ross  */
1512b65585SGordon Ross 
1612b65585SGordon Ross /*
1712b65585SGordon Ross  * SPNEGO back-end for NTLMSSP.  See [MS-NLMP]
1812b65585SGordon Ross  */
1912b65585SGordon Ross 
2012b65585SGordon Ross #include <sys/types.h>
2112b65585SGordon Ross #include <sys/byteorder.h>
2212b65585SGordon Ross #include <strings.h>
2312b65585SGordon Ross #include "smbd.h"
2412b65585SGordon Ross #include "smbd_authsvc.h"
2512b65585SGordon Ross #include "netsmb/ntlmssp.h"
2612b65585SGordon Ross #include <assert.h>
2712b65585SGordon Ross 
2812b65585SGordon Ross /* A shorter alias for a crazy long name from [MS-NLMP] */
2912b65585SGordon Ross #define	NTLMSSP_NEGOTIATE_NTLM2 \
3012b65585SGordon Ross 	NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
3112b65585SGordon Ross 
3212b65585SGordon Ross /* Need this in a header somewhere */
3312b65585SGordon Ross #ifdef _LITTLE_ENDIAN
3412b65585SGordon Ross /* little-endian values on little-endian */
3512b65585SGordon Ross #define	htolel(x)	((uint32_t)(x))
3612b65585SGordon Ross #define	letohl(x)	((uint32_t)(x))
3712b65585SGordon Ross #else	/* (BYTE_ORDER == LITTLE_ENDIAN) */
3812b65585SGordon Ross /* little-endian values on big-endian (swap) */
39*975041ddSGordon Ross #define	letohl(x)	BSWAP_32(x)
40*975041ddSGordon Ross #define	htolel(x)	BSWAP_32(x)
4112b65585SGordon Ross #endif	/* (BYTE_ORDER == LITTLE_ENDIAN) */
4212b65585SGordon Ross 
4312b65585SGordon Ross typedef struct ntlmssp_backend {
4412b65585SGordon Ross 	uint32_t expect_type;
4512b65585SGordon Ross 	uint32_t clnt_flags;
4612b65585SGordon Ross 	uint32_t srv_flags;
4712b65585SGordon Ross 	char srv_challenge[8];
4812b65585SGordon Ross } ntlmssp_backend_t;
4912b65585SGordon Ross 
5012b65585SGordon Ross struct genhdr {
5112b65585SGordon Ross 	char h_id[8];	/* "NTLMSSP" */
5212b65585SGordon Ross 	uint32_t h_type;
5312b65585SGordon Ross };
5412b65585SGordon Ross 
5512b65585SGordon Ross struct sec_buf {
5612b65585SGordon Ross 	uint16_t sb_length;
5712b65585SGordon Ross 	uint16_t sb_maxlen;
5812b65585SGordon Ross 	uint32_t sb_offset;
5912b65585SGordon Ross };
6012b65585SGordon Ross 
6112b65585SGordon Ross struct nego_hdr {
6212b65585SGordon Ross 	char h_id[8];
6312b65585SGordon Ross 	uint32_t h_type;
6412b65585SGordon Ross 	uint32_t h_flags;
6512b65585SGordon Ross 	/* workstation domain, name (place holders) */
6612b65585SGordon Ross 	uint16_t ws_dom[4];
6712b65585SGordon Ross 	uint16_t ws_name[4];
6812b65585SGordon Ross };
6912b65585SGordon Ross 
7012b65585SGordon Ross struct auth_hdr {
7112b65585SGordon Ross 	char h_id[8];
7212b65585SGordon Ross 	uint32_t h_type;
7312b65585SGordon Ross 	struct sec_buf h_lm_resp;
7412b65585SGordon Ross 	struct sec_buf h_nt_resp;
7512b65585SGordon Ross 	struct sec_buf h_domain;
7612b65585SGordon Ross 	struct sec_buf h_user;
7712b65585SGordon Ross 	struct sec_buf h_wksta;
7812b65585SGordon Ross 	struct sec_buf h_essn_key; /* encrypted session key */
7912b65585SGordon Ross 	uint32_t h_flags;
8012b65585SGordon Ross 	/* Version struct (optional) */
8112b65585SGordon Ross 	/* MIC hash (optional) */
8212b65585SGordon Ross };
8312b65585SGordon Ross 
8412b65585SGordon Ross /* Allow turning these off for debugging, etc. */
8512b65585SGordon Ross int smbd_signing_enabled = 1;
8612b65585SGordon Ross 
8712b65585SGordon Ross int smbd_constant_challenge = 0;
8812b65585SGordon Ross static uint8_t constant_chal[8] = {
8912b65585SGordon Ross     0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
9012b65585SGordon Ross 
9112b65585SGordon Ross static int smbd_ntlmssp_negotiate(authsvc_context_t *);
9212b65585SGordon Ross static int smbd_ntlmssp_authenticate(authsvc_context_t *);
9312b65585SGordon Ross static int encode_avpair_str(smb_msgbuf_t *, uint16_t, char *);
9412b65585SGordon Ross static int decode_secbuf_bin(smb_msgbuf_t *, struct sec_buf *, void **);
9512b65585SGordon Ross static int decode_secbuf_str(smb_msgbuf_t *, struct sec_buf *, char **);
9612b65585SGordon Ross 
9712b65585SGordon Ross /*
9812b65585SGordon Ross  * Initialize this context for NTLMSSP, if possible.
9912b65585SGordon Ross  */
10012b65585SGordon Ross int
smbd_ntlmssp_init(authsvc_context_t * ctx)10112b65585SGordon Ross smbd_ntlmssp_init(authsvc_context_t *ctx)
10212b65585SGordon Ross {
10312b65585SGordon Ross 	ntlmssp_backend_t *be;
10412b65585SGordon Ross 
10512b65585SGordon Ross 	be = malloc(sizeof (*be));
10612b65585SGordon Ross 	if (be == 0)
10712b65585SGordon Ross 		return (NT_STATUS_NO_MEMORY);
10812b65585SGordon Ross 	bzero(be, sizeof (*be));
10912b65585SGordon Ross 	be->expect_type = NTLMSSP_MSGTYPE_NEGOTIATE;
11012b65585SGordon Ross 	ctx->ctx_backend = be;
11112b65585SGordon Ross 
11212b65585SGordon Ross 	return (0);
11312b65585SGordon Ross }
11412b65585SGordon Ross 
11512b65585SGordon Ross void
smbd_ntlmssp_fini(authsvc_context_t * ctx)11612b65585SGordon Ross smbd_ntlmssp_fini(authsvc_context_t *ctx)
11712b65585SGordon Ross {
11812b65585SGordon Ross 	free(ctx->ctx_backend);
11912b65585SGordon Ross }
12012b65585SGordon Ross 
12112b65585SGordon Ross /*
12212b65585SGordon Ross  * Handle an auth message
12312b65585SGordon Ross  */
12412b65585SGordon Ross int
smbd_ntlmssp_work(authsvc_context_t * ctx)12512b65585SGordon Ross smbd_ntlmssp_work(authsvc_context_t *ctx)
12612b65585SGordon Ross {
12712b65585SGordon Ross 	struct genhdr *ihdr = ctx->ctx_ibodybuf;
12812b65585SGordon Ross 	ntlmssp_backend_t *be = ctx->ctx_backend;
12912b65585SGordon Ross 	uint32_t mtype;
13012b65585SGordon Ross 	int rc;
13112b65585SGordon Ross 
13212b65585SGordon Ross 	if (ctx->ctx_ibodylen < sizeof (*ihdr))
13312b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
13412b65585SGordon Ross 
13512b65585SGordon Ross 	if (bcmp(ihdr->h_id, "NTLMSSP", 8))
13612b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
13712b65585SGordon Ross 	mtype = letohl(ihdr->h_type);
13812b65585SGordon Ross 	if (mtype != be->expect_type)
13912b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
14012b65585SGordon Ross 
14112b65585SGordon Ross 	switch (mtype) {
14212b65585SGordon Ross 	case NTLMSSP_MSGTYPE_NEGOTIATE:
14312b65585SGordon Ross 		ctx->ctx_orawtype = LSA_MTYPE_ES_CONT;
14412b65585SGordon Ross 		rc = smbd_ntlmssp_negotiate(ctx);
14512b65585SGordon Ross 		break;
14612b65585SGordon Ross 	case NTLMSSP_MSGTYPE_AUTHENTICATE:
14712b65585SGordon Ross 		ctx->ctx_orawtype = LSA_MTYPE_ES_DONE;
14812b65585SGordon Ross 		rc = smbd_ntlmssp_authenticate(ctx);
14912b65585SGordon Ross 		break;
15012b65585SGordon Ross 
15112b65585SGordon Ross 	default:
15212b65585SGordon Ross 	case NTLMSSP_MSGTYPE_CHALLENGE:
15312b65585SGordon Ross 		/* Sent by servers, not received. */
15412b65585SGordon Ross 		rc = NT_STATUS_INVALID_PARAMETER;
15512b65585SGordon Ross 		break;
15612b65585SGordon Ross 	}
15712b65585SGordon Ross 
15812b65585SGordon Ross 	return (rc);
15912b65585SGordon Ross }
16012b65585SGordon Ross 
16112b65585SGordon Ross #if (MAXHOSTNAMELEN < NETBIOS_NAME_SZ)
16212b65585SGordon Ross #error "MAXHOSTNAMELEN < NETBIOS_NAME_SZ"
16312b65585SGordon Ross #endif
16412b65585SGordon Ross 
16512b65585SGordon Ross /*
16612b65585SGordon Ross  * Handle an NTLMSSP_MSGTYPE_NEGOTIATE message, and reply
16712b65585SGordon Ross  * with an NTLMSSP_MSGTYPE_CHALLENGE message.
16812b65585SGordon Ross  * See: [MS-NLMP] 2.2.1.1, 3.2.5.1.1
16912b65585SGordon Ross  */
17012b65585SGordon Ross static int
smbd_ntlmssp_negotiate(authsvc_context_t * ctx)17112b65585SGordon Ross smbd_ntlmssp_negotiate(authsvc_context_t *ctx)
17212b65585SGordon Ross {
17312b65585SGordon Ross 	char tmp_name[MAXHOSTNAMELEN];
17412b65585SGordon Ross 	ntlmssp_backend_t *be = ctx->ctx_backend;
17512b65585SGordon Ross 	struct nego_hdr *ihdr = ctx->ctx_ibodybuf;
17612b65585SGordon Ross 	smb_msgbuf_t mb;
17712b65585SGordon Ross 	uint8_t *save_scan;
17812b65585SGordon Ross 	int secmode;
17912b65585SGordon Ross 	int mbflags;
18012b65585SGordon Ross 	int rc;
18112b65585SGordon Ross 	size_t var_start, var_end;
18212b65585SGordon Ross 	uint16_t var_size;
18312b65585SGordon Ross 
18412b65585SGordon Ross 	if (ctx->ctx_ibodylen < sizeof (*ihdr))
18512b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
18612b65585SGordon Ross 	be->clnt_flags = letohl(ihdr->h_flags);
18712b65585SGordon Ross 
18812b65585SGordon Ross 	/*
18912b65585SGordon Ross 	 * Looks like we can ignore ws_dom, ws_name.
19012b65585SGordon Ross 	 * Otherwise would parse those here.
19112b65585SGordon Ross 	 */
19212b65585SGordon Ross 
19312b65585SGordon Ross 	secmode = smb_config_get_secmode();
19412b65585SGordon Ross 	if (smbd_constant_challenge) {
19512b65585SGordon Ross 		(void) memcpy(be->srv_challenge, constant_chal,
19612b65585SGordon Ross 		    sizeof (be->srv_challenge));
19712b65585SGordon Ross 	} else {
19812b65585SGordon Ross 		randomize(be->srv_challenge, sizeof (be->srv_challenge));
19912b65585SGordon Ross 	}
20012b65585SGordon Ross 
20112b65585SGordon Ross 	/*
20212b65585SGordon Ross 	 * Compute srv_flags
20312b65585SGordon Ross 	 */
20412b65585SGordon Ross 	be->srv_flags =
20512b65585SGordon Ross 	    NTLMSSP_REQUEST_TARGET |
20612b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_NTLM |
20712b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_TARGET_INFO;
20812b65585SGordon Ross 	be->srv_flags |= be->clnt_flags & (
20912b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_NTLM2 |
21012b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_128 |
21112b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_KEY_EXCH |
21212b65585SGordon Ross 	    NTLMSSP_NEGOTIATE_56);
21312b65585SGordon Ross 
21412b65585SGordon Ross 	if (smbd_signing_enabled) {
21512b65585SGordon Ross 		be->srv_flags |= be->clnt_flags & (
21612b65585SGordon Ross 		    NTLMSSP_NEGOTIATE_SIGN |
21712b65585SGordon Ross 		    NTLMSSP_NEGOTIATE_SEAL |
21812b65585SGordon Ross 		    NTLMSSP_NEGOTIATE_ALWAYS_SIGN);
21912b65585SGordon Ross 	}
22012b65585SGordon Ross 
22112b65585SGordon Ross 	if (be->clnt_flags & NTLMSSP_NEGOTIATE_UNICODE)
22212b65585SGordon Ross 		be->srv_flags |= NTLMSSP_NEGOTIATE_UNICODE;
22312b65585SGordon Ross 	else if (be->clnt_flags & NTLMSSP_NEGOTIATE_OEM)
22412b65585SGordon Ross 		be->srv_flags |= NTLMSSP_NEGOTIATE_OEM;
22512b65585SGordon Ross 
22612b65585SGordon Ross 	/* LM Key is mutually exclusive with NTLM2 */
22712b65585SGordon Ross 	if ((be->srv_flags & NTLMSSP_NEGOTIATE_NTLM2) == 0 &&
22812b65585SGordon Ross 	    (be->clnt_flags & NTLMSSP_NEGOTIATE_LM_KEY) != 0)
22912b65585SGordon Ross 		be->srv_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
23012b65585SGordon Ross 
23112b65585SGordon Ross 	/* Get our "target name" */
23212b65585SGordon Ross 	if (secmode == SMB_SECMODE_DOMAIN) {
23312b65585SGordon Ross 		be->srv_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
23412b65585SGordon Ross 		rc = smb_getdomainname(tmp_name, NETBIOS_NAME_SZ);
23512b65585SGordon Ross 	} else {
23612b65585SGordon Ross 		be->srv_flags |= NTLMSSP_TARGET_TYPE_SERVER;
23712b65585SGordon Ross 		rc = smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ);
23812b65585SGordon Ross 	}
23912b65585SGordon Ross 	if (rc)
24012b65585SGordon Ross 		goto errout;
24112b65585SGordon Ross 
24212b65585SGordon Ross 	/*
24312b65585SGordon Ross 	 * Build the NTLMSSP_MSGTYPE_CHALLENGE message.
24412b65585SGordon Ross 	 */
24512b65585SGordon Ross 	mbflags = SMB_MSGBUF_NOTERM;
24612b65585SGordon Ross 	if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE)
24712b65585SGordon Ross 		mbflags |= SMB_MSGBUF_UNICODE;
24812b65585SGordon Ross 	smb_msgbuf_init(&mb, ctx->ctx_obodybuf, ctx->ctx_obodylen, mbflags);
24912b65585SGordon Ross 
25012b65585SGordon Ross 	/*
25112b65585SGordon Ross 	 * Fixed size parts
25212b65585SGordon Ross 	 */
25312b65585SGordon Ross 	rc = smb_msgbuf_encode(
25412b65585SGordon Ross 	    &mb, "8clwwll8cllwwl",	/* offset, name (fmt) */
25512b65585SGordon Ross 	    "NTLMSSP",			/* 0: signature (8c) */
25612b65585SGordon Ross 	    NTLMSSP_MSGTYPE_CHALLENGE,	/* 8: type	(l) */
25712b65585SGordon Ross 	    0, 0, 0,	/* filled later:   12: target name (wwl) */
25812b65585SGordon Ross 	    be->srv_flags,		/* 20: flags	(l) */
259*975041ddSGordon Ross 	    be->srv_challenge,		/* 24:		(8c) */
26012b65585SGordon Ross 	    0, 0,			/* 32: reserved (ll) */
26112b65585SGordon Ross 	    0, 0, 0);	/* filled later:   40: target info (wwl) */
26212b65585SGordon Ross #define	TARGET_NAME_OFFSET	12
26312b65585SGordon Ross #define	TARGET_INFO_OFFSET	40
26412b65585SGordon Ross 	if (rc < 0)
26512b65585SGordon Ross 		goto errout;
26612b65585SGordon Ross 
26712b65585SGordon Ross 	/*
26812b65585SGordon Ross 	 * Variable length parts.
26912b65585SGordon Ross 	 *
27012b65585SGordon Ross 	 * Target name
27112b65585SGordon Ross 	 */
27212b65585SGordon Ross 	var_start = smb_msgbuf_used(&mb);
27312b65585SGordon Ross 	rc = smb_msgbuf_encode(&mb, "u", tmp_name);
27412b65585SGordon Ross 	var_end = smb_msgbuf_used(&mb);
27512b65585SGordon Ross 	var_size = (uint16_t)(var_end - var_start);
27612b65585SGordon Ross 	if (rc < 0)
27712b65585SGordon Ross 		goto errout;
27812b65585SGordon Ross 
27912b65585SGordon Ross 	/* overwrite target name offset+lengths */
28012b65585SGordon Ross 	save_scan = mb.scan;
28112b65585SGordon Ross 	mb.scan = mb.base + TARGET_NAME_OFFSET;
28212b65585SGordon Ross 	(void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start);
28312b65585SGordon Ross 	mb.scan = save_scan;
28412b65585SGordon Ross 
28512b65585SGordon Ross 	/*
28612b65585SGordon Ross 	 * Target info (AvPairList)
28712b65585SGordon Ross 	 *
28812b65585SGordon Ross 	 * These AV pairs are like our name/value pairs, but have
28912b65585SGordon Ross 	 * numeric identifiers instead of names.  There are many
29012b65585SGordon Ross 	 * of these, but we put only the four expected by Windows:
29112b65585SGordon Ross 	 *	NetBIOS computer name
29212b65585SGordon Ross 	 *	NetBIOS domain name
29312b65585SGordon Ross 	 *	DNS computer name
29412b65585SGordon Ross 	 *	DNS domain name
29512b65585SGordon Ross 	 * Note that "domain" above (even "DNS domain") refers to
29612b65585SGordon Ross 	 * the AD domain of which we're a member, which may be
29712b65585SGordon Ross 	 * _different_ from the configured DNS domain.
29812b65585SGordon Ross 	 *
29912b65585SGordon Ross 	 * Also note that in "workgroup" mode (not a domain member)
30012b65585SGordon Ross 	 * all "domain" fields should be set to the same values as
30112b65585SGordon Ross 	 * the "computer" fields ("bare" host name, not FQDN).
30212b65585SGordon Ross 	 */
30312b65585SGordon Ross 	var_start = smb_msgbuf_used(&mb);
30412b65585SGordon Ross 
30512b65585SGordon Ross 	/* NetBIOS Computer Name */
30612b65585SGordon Ross 	if (smb_getnetbiosname(tmp_name, NETBIOS_NAME_SZ))
30712b65585SGordon Ross 		goto errout;
30812b65585SGordon Ross 	if (encode_avpair_str(&mb, MsvAvNbComputerName, tmp_name) < 0)
30912b65585SGordon Ross 		goto errout;
31012b65585SGordon Ross 
31112b65585SGordon Ross 	if (secmode != SMB_SECMODE_DOMAIN) {
31212b65585SGordon Ross 		/*
31312b65585SGordon Ross 		 * Workgroup mode.  Set all to hostname.
31412b65585SGordon Ross 		 * tmp_name = netbios hostname from above.
31512b65585SGordon Ross 		 */
31612b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0)
31712b65585SGordon Ross 			goto errout;
31812b65585SGordon Ross 		/*
31912b65585SGordon Ross 		 * Want the bare computer name here (not FQDN).
32012b65585SGordon Ross 		 */
32112b65585SGordon Ross 		if (smb_gethostname(tmp_name, MAXHOSTNAMELEN, SMB_CASE_LOWER))
32212b65585SGordon Ross 			goto errout;
32312b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0)
32412b65585SGordon Ross 			goto errout;
32512b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0)
32612b65585SGordon Ross 			goto errout;
32712b65585SGordon Ross 	} else {
32812b65585SGordon Ross 		/*
32912b65585SGordon Ross 		 * Domain mode.  Use real host and domain values.
33012b65585SGordon Ross 		 */
33112b65585SGordon Ross 
33212b65585SGordon Ross 		/* NetBIOS Domain Name */
33312b65585SGordon Ross 		if (smb_getdomainname(tmp_name, NETBIOS_NAME_SZ))
33412b65585SGordon Ross 			goto errout;
33512b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvNbDomainName, tmp_name) < 0)
33612b65585SGordon Ross 			goto errout;
33712b65585SGordon Ross 
33812b65585SGordon Ross 		/* DNS Computer Name */
33912b65585SGordon Ross 		if (smb_getfqhostname(tmp_name, MAXHOSTNAMELEN))
34012b65585SGordon Ross 			goto errout;
34112b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsComputerName, tmp_name) < 0)
34212b65585SGordon Ross 			goto errout;
34312b65585SGordon Ross 
34412b65585SGordon Ross 		/* DNS Domain Name */
34512b65585SGordon Ross 		if (smb_getfqdomainname(tmp_name, MAXHOSTNAMELEN))
34612b65585SGordon Ross 			goto errout;
34712b65585SGordon Ross 		if (encode_avpair_str(&mb, MsvAvDnsDomainName, tmp_name) < 0)
34812b65585SGordon Ross 			goto errout;
34912b65585SGordon Ross 	}
35012b65585SGordon Ross 
35112b65585SGordon Ross 	/* End marker */
35212b65585SGordon Ross 	if (smb_msgbuf_encode(&mb, "ww", MsvAvEOL, 0) < 0)
35312b65585SGordon Ross 		goto errout;
35412b65585SGordon Ross 	var_end = smb_msgbuf_used(&mb);
35512b65585SGordon Ross 	var_size = (uint16_t)(var_end - var_start);
35612b65585SGordon Ross 
35712b65585SGordon Ross 	/* overwrite target  offset+lengths */
35812b65585SGordon Ross 	save_scan = mb.scan;
35912b65585SGordon Ross 	mb.scan = mb.base + TARGET_INFO_OFFSET;
36012b65585SGordon Ross 	(void) smb_msgbuf_encode(&mb, "wwl", var_size, var_size, var_start);
36112b65585SGordon Ross 	mb.scan = save_scan;
36212b65585SGordon Ross 
36312b65585SGordon Ross 	ctx->ctx_obodylen = smb_msgbuf_used(&mb);
36412b65585SGordon Ross 	smb_msgbuf_term(&mb);
36512b65585SGordon Ross 
36612b65585SGordon Ross 	be->expect_type = NTLMSSP_MSGTYPE_AUTHENTICATE;
36712b65585SGordon Ross 
36812b65585SGordon Ross 	return (0);
36912b65585SGordon Ross 
37012b65585SGordon Ross errout:
37112b65585SGordon Ross 	smb_msgbuf_term(&mb);
37212b65585SGordon Ross 	return (NT_STATUS_INTERNAL_ERROR);
37312b65585SGordon Ross }
37412b65585SGordon Ross 
37512b65585SGordon Ross static int
encode_avpair_str(smb_msgbuf_t * mb,uint16_t AvId,char * name)37612b65585SGordon Ross encode_avpair_str(smb_msgbuf_t *mb, uint16_t AvId, char *name)
37712b65585SGordon Ross {
37812b65585SGordon Ross 	int rc;
37912b65585SGordon Ross 	uint16_t len;
38012b65585SGordon Ross 
38112b65585SGordon Ross 	len = smb_wcequiv_strlen(name);
38212b65585SGordon Ross 	rc = smb_msgbuf_encode(mb, "wwU", AvId, len, name);
38312b65585SGordon Ross 	return (rc);
38412b65585SGordon Ross }
38512b65585SGordon Ross 
38612b65585SGordon Ross /*
38712b65585SGordon Ross  * Handle an NTLMSSP_MSGTYPE_AUTHENTICATE message.
38812b65585SGordon Ross  * See: [MS-NLMP] 2.2.1.3, 3.2.5.1.2
38912b65585SGordon Ross  */
39012b65585SGordon Ross static int
smbd_ntlmssp_authenticate(authsvc_context_t * ctx)39112b65585SGordon Ross smbd_ntlmssp_authenticate(authsvc_context_t *ctx)
39212b65585SGordon Ross {
39312b65585SGordon Ross 	struct auth_hdr hdr;
39412b65585SGordon Ross 	smb_msgbuf_t mb;
39512b65585SGordon Ross 	smb_logon_t	user_info;
39612b65585SGordon Ross 	smb_token_t	*token = NULL;
39712b65585SGordon Ross 	ntlmssp_backend_t *be = ctx->ctx_backend;
39812b65585SGordon Ross 	void *lm_resp;
39912b65585SGordon Ross 	void *nt_resp;
40012b65585SGordon Ross 	char *domain;
40112b65585SGordon Ross 	char *user;
40212b65585SGordon Ross 	char *wksta;
40312b65585SGordon Ross 	void *essn_key;	/* encrypted session key (optional) */
40412b65585SGordon Ross 	int mbflags;
40512b65585SGordon Ross 	uint_t status = NT_STATUS_INTERNAL_ERROR;
40612b65585SGordon Ross 	char combined_challenge[SMBAUTH_CHAL_SZ];
40712b65585SGordon Ross 	unsigned char kxkey[SMBAUTH_HASH_SZ];
40812b65585SGordon Ross 	boolean_t ntlm_v1x = B_FALSE;
40912b65585SGordon Ross 
41012b65585SGordon Ross 	bzero(&user_info, sizeof (user_info));
41112b65585SGordon Ross 
41212b65585SGordon Ross 	/*
41312b65585SGordon Ross 	 * Parse the NTLMSSP_MSGTYPE_AUTHENTICATE message.
41412b65585SGordon Ross 	 */
41512b65585SGordon Ross 	if (ctx->ctx_ibodylen < sizeof (hdr))
41612b65585SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
41712b65585SGordon Ross 	mbflags = SMB_MSGBUF_NOTERM;
41812b65585SGordon Ross 	if (be->srv_flags & NTLMSSP_NEGOTIATE_UNICODE)
41912b65585SGordon Ross 		mbflags |= SMB_MSGBUF_UNICODE;
42012b65585SGordon Ross 	smb_msgbuf_init(&mb, ctx->ctx_ibodybuf, ctx->ctx_ibodylen, mbflags);
42112b65585SGordon Ross 	bzero(&hdr, sizeof (hdr));
42212b65585SGordon Ross 
42312b65585SGordon Ross 	if (smb_msgbuf_decode(&mb, "12.") < 0)
42412b65585SGordon Ross 		goto errout;
42512b65585SGordon Ross 	if (decode_secbuf_bin(&mb, &hdr.h_lm_resp, &lm_resp) < 0)
42612b65585SGordon Ross 		goto errout;
42712b65585SGordon Ross 	if (decode_secbuf_bin(&mb, &hdr.h_nt_resp, &nt_resp) < 0)
42812b65585SGordon Ross 		goto errout;
42912b65585SGordon Ross 	if (decode_secbuf_str(&mb, &hdr.h_domain, &domain) < 0)
43012b65585SGordon Ross 		goto errout;
43112b65585SGordon Ross 	if (decode_secbuf_str(&mb, &hdr.h_user, &user) < 0)
43212b65585SGordon Ross 		goto errout;
43312b65585SGordon Ross 	if (decode_secbuf_str(&mb, &hdr.h_wksta, &wksta) < 0)
43412b65585SGordon Ross 		goto errout;
43512b65585SGordon Ross 	if (decode_secbuf_bin(&mb, &hdr.h_essn_key, &essn_key) < 0)
43612b65585SGordon Ross 		goto errout;
43712b65585SGordon Ross 	if (smb_msgbuf_decode(&mb, "l", &be->clnt_flags) < 0)
43812b65585SGordon Ross 		goto errout;
43912b65585SGordon Ross 
44012b65585SGordon Ross 	if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
44112b65585SGordon Ross 		if (hdr.h_essn_key.sb_length < 16 || essn_key == NULL)
44212b65585SGordon Ross 			goto errout;
44312b65585SGordon Ross 	}
44412b65585SGordon Ross 
44512b65585SGordon Ross 	user_info.lg_level = NETR_NETWORK_LOGON;
44612b65585SGordon Ross 	user_info.lg_flags = 0;
44712b65585SGordon Ross 
44812b65585SGordon Ross 	user_info.lg_ntlm_flags = be->clnt_flags;
44912b65585SGordon Ross 	user_info.lg_username = (user) ? user : "";
45012b65585SGordon Ross 	user_info.lg_domain = (domain) ? domain : "";
45112b65585SGordon Ross 	user_info.lg_workstation = (wksta) ? wksta : "";
45212b65585SGordon Ross 
45312b65585SGordon Ross 	user_info.lg_clnt_ipaddr =
45412b65585SGordon Ross 	    ctx->ctx_clinfo.lci_clnt_ipaddr;
45512b65585SGordon Ross 	user_info.lg_local_port = 445;
45612b65585SGordon Ross 
45712b65585SGordon Ross 	user_info.lg_challenge_key.len = SMBAUTH_CHAL_SZ;
45812b65585SGordon Ross 	user_info.lg_challenge_key.val = (uint8_t *)be->srv_challenge;
45912b65585SGordon Ross 
46012b65585SGordon Ross 	user_info.lg_nt_password.len = hdr.h_nt_resp.sb_length;
46112b65585SGordon Ross 	user_info.lg_nt_password.val = nt_resp;
46212b65585SGordon Ross 
46312b65585SGordon Ross 	user_info.lg_lm_password.len = hdr.h_lm_resp.sb_length;
46412b65585SGordon Ross 	user_info.lg_lm_password.val = lm_resp;
46512b65585SGordon Ross 
46612b65585SGordon Ross 	user_info.lg_native_os = ctx->ctx_clinfo.lci_native_os;
46712b65585SGordon Ross 	user_info.lg_native_lm = ctx->ctx_clinfo.lci_native_lm;
46812b65585SGordon Ross 
46912b65585SGordon Ross 	/*
47012b65585SGordon Ross 	 * If we're doing extended session security, the challenge
47112b65585SGordon Ross 	 * this OWF was computed with is different. [MS-NLMP 3.3.1]
47212b65585SGordon Ross 	 * It's: MD5(concat(ServerChallenge,ClientChallenge))
47312b65585SGordon Ross 	 * where the ClientChallenge is in the LM resp. field.
47412b65585SGordon Ross 	 */
47512b65585SGordon Ross 	if (user_info.lg_nt_password.len == SMBAUTH_LM_RESP_SZ &&
47612b65585SGordon Ross 	    user_info.lg_lm_password.len >= SMBAUTH_CHAL_SZ &&
47712b65585SGordon Ross 	    (be->clnt_flags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {
47812b65585SGordon Ross 		smb_auth_ntlm2_mkchallenge(combined_challenge,
47912b65585SGordon Ross 		    be->srv_challenge, lm_resp);
48012b65585SGordon Ross 		user_info.lg_challenge_key.val =
48112b65585SGordon Ross 		    (uint8_t *)combined_challenge;
48212b65585SGordon Ross 		user_info.lg_lm_password.len = 0;
48312b65585SGordon Ross 		ntlm_v1x = B_TRUE;
48412b65585SGordon Ross 	}
48512b65585SGordon Ross 
48612b65585SGordon Ross 	/*
48712b65585SGordon Ross 	 * This (indirectly) calls smb_auth_validate() to
48812b65585SGordon Ross 	 * check that the client gave us a valid hash.
48912b65585SGordon Ross 	 */
49012b65585SGordon Ross 	token = smbd_user_auth_logon(&user_info);
49112b65585SGordon Ross 	if (token == NULL) {
492*975041ddSGordon Ross 		status = user_info.lg_status;
493*975041ddSGordon Ross 		if (status == 0) /* should not happen */
494*975041ddSGordon Ross 			status = NT_STATUS_INTERNAL_ERROR;
49512b65585SGordon Ross 		goto errout;
49612b65585SGordon Ross 	}
49712b65585SGordon Ross 
49812b65585SGordon Ross 	if (token->tkn_ssnkey.val != NULL &&
49912b65585SGordon Ross 	    token->tkn_ssnkey.len == SMBAUTH_HASH_SZ) {
50012b65585SGordon Ross 
50112b65585SGordon Ross 		/*
50212b65585SGordon Ross 		 * At this point, token->tkn_session_key is the
50312b65585SGordon Ross 		 * "Session Base Key" [MS-NLMP] 3.2.5.1.2
50412b65585SGordon Ross 		 * Compute the final session key.  First need the
50512b65585SGordon Ross 		 * "Key Exchange Key" [MS-NLMP] 3.4.5.1
50612b65585SGordon Ross 		 */
50712b65585SGordon Ross 		if (ntlm_v1x) {
50812b65585SGordon Ross 			smb_auth_ntlm2_kxkey(kxkey,
50912b65585SGordon Ross 			    be->srv_challenge, lm_resp,
51012b65585SGordon Ross 			    token->tkn_ssnkey.val);
51112b65585SGordon Ross 		} else {
51212b65585SGordon Ross 			/* KXKEY is the Session Base Key. */
51312b65585SGordon Ross 			(void) memcpy(kxkey, token->tkn_ssnkey.val,
51412b65585SGordon Ross 			    SMBAUTH_HASH_SZ);
51512b65585SGordon Ross 		}
51612b65585SGordon Ross 
51712b65585SGordon Ross 		/*
51812b65585SGordon Ross 		 * If the client give us an encrypted session key,
51912b65585SGordon Ross 		 * decrypt it (RC4) using the "key exchange key".
52012b65585SGordon Ross 		 */
52112b65585SGordon Ross 		if (be->clnt_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
52212b65585SGordon Ross 			/* RC4 args: result, key, data */
52312b65585SGordon Ross 			(void) smb_auth_RC4(token->tkn_ssnkey.val,
52412b65585SGordon Ross 			    SMBAUTH_HASH_SZ, kxkey, SMBAUTH_HASH_SZ,
52512b65585SGordon Ross 			    essn_key, hdr.h_essn_key.sb_length);
52612b65585SGordon Ross 		} else {
52712b65585SGordon Ross 			/* Final key is the KXKEY */
52812b65585SGordon Ross 			(void) memcpy(token->tkn_ssnkey.val, kxkey,
52912b65585SGordon Ross 			    SMBAUTH_HASH_SZ);
53012b65585SGordon Ross 		}
53112b65585SGordon Ross 	}
53212b65585SGordon Ross 
53312b65585SGordon Ross 	ctx->ctx_token = token;
53412b65585SGordon Ross 	ctx->ctx_obodylen = 0;
53512b65585SGordon Ross 
53612b65585SGordon Ross 	smb_msgbuf_term(&mb);
53712b65585SGordon Ross 	return (0);
53812b65585SGordon Ross 
53912b65585SGordon Ross errout:
54012b65585SGordon Ross 	smb_msgbuf_term(&mb);
54112b65585SGordon Ross 	return (status);
54212b65585SGordon Ross }
54312b65585SGordon Ross 
54412b65585SGordon Ross static int
decode_secbuf_bin(smb_msgbuf_t * mb,struct sec_buf * sb,void ** binp)54512b65585SGordon Ross decode_secbuf_bin(smb_msgbuf_t *mb, struct sec_buf *sb, void **binp)
54612b65585SGordon Ross {
54712b65585SGordon Ross 	int rc;
54812b65585SGordon Ross 
54912b65585SGordon Ross 	*binp = NULL;
55012b65585SGordon Ross 	rc = smb_msgbuf_decode(
55112b65585SGordon Ross 	    mb, "wwl",
55212b65585SGordon Ross 	    &sb->sb_length,
55312b65585SGordon Ross 	    &sb->sb_maxlen,
55412b65585SGordon Ross 	    &sb->sb_offset);
55512b65585SGordon Ross 	if (rc < 0)
55612b65585SGordon Ross 		return (rc);
55712b65585SGordon Ross 
55812b65585SGordon Ross 	if (sb->sb_offset > mb->max)
55912b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
56012b65585SGordon Ross 	if (sb->sb_length > (mb->max - sb->sb_offset))
56112b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
56212b65585SGordon Ross 	if (sb->sb_length == 0)
56312b65585SGordon Ross 		return (rc);
56412b65585SGordon Ross 
56512b65585SGordon Ross 	*binp = mb->base + sb->sb_offset;
56612b65585SGordon Ross 	return (0);
56712b65585SGordon Ross }
56812b65585SGordon Ross 
56912b65585SGordon Ross static int
decode_secbuf_str(smb_msgbuf_t * mb,struct sec_buf * sb,char ** cpp)57012b65585SGordon Ross decode_secbuf_str(smb_msgbuf_t *mb, struct sec_buf *sb, char **cpp)
57112b65585SGordon Ross {
57212b65585SGordon Ross 	uint8_t *save_scan;
57312b65585SGordon Ross 	int rc;
57412b65585SGordon Ross 
57512b65585SGordon Ross 	*cpp = NULL;
57612b65585SGordon Ross 	rc = smb_msgbuf_decode(
57712b65585SGordon Ross 	    mb, "wwl",
57812b65585SGordon Ross 	    &sb->sb_length,
57912b65585SGordon Ross 	    &sb->sb_maxlen,
58012b65585SGordon Ross 	    &sb->sb_offset);
58112b65585SGordon Ross 	if (rc < 0)
58212b65585SGordon Ross 		return (rc);
58312b65585SGordon Ross 
58412b65585SGordon Ross 	if (sb->sb_offset > mb->max)
58512b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
58612b65585SGordon Ross 	if (sb->sb_length > (mb->max - sb->sb_offset))
58712b65585SGordon Ross 		return (SMB_MSGBUF_UNDERFLOW);
58812b65585SGordon Ross 	if (sb->sb_length == 0)
58912b65585SGordon Ross 		return (rc);
59012b65585SGordon Ross 
59112b65585SGordon Ross 	save_scan = mb->scan;
59212b65585SGordon Ross 	mb->scan = mb->base + sb->sb_offset;
59312b65585SGordon Ross 	rc = smb_msgbuf_decode(mb, "#u", (int)sb->sb_length, cpp);
59412b65585SGordon Ross 	mb->scan = save_scan;
59512b65585SGordon Ross 
59612b65585SGordon Ross 	return (rc);
59712b65585SGordon Ross }
598