1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
2229bd2886SAlan Wright  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24*12b65585SGordon Ross  *
25*12b65585SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw #include <strings.h>
29da6c28aaSamw #include <stdlib.h>
30*12b65585SGordon Ross #include <syslog.h>
31*12b65585SGordon Ross #include <sys/md5.h>
32bbf6f00cSJordan Brown #include <smbsrv/string.h>
33da6c28aaSamw #include <smbsrv/libsmb.h>
34*12b65585SGordon Ross #include <netsmb/spnego.h>	/* libsmbfs */
351ed6b69aSGordon Ross #include <assert.h>
36da6c28aaSamw 
37*12b65585SGordon Ross #define	NTLM_CHAL_SZ	SMBAUTH_CHAL_SZ	/* challenge size */
38*12b65585SGordon Ross 
39*12b65585SGordon Ross /*
40*12b65585SGordon Ross  * Compute the combined (server+client) challenge per. [MS-NLMP 3.3.1]
41*12b65585SGordon Ross  * MD5(concat(ServerChallenge,ClientChallenge))
42*12b65585SGordon Ross  */
43*12b65585SGordon Ross void
smb_auth_ntlm2_mkchallenge(char * result,const char * srv_chal,const char * clnt_chal)44*12b65585SGordon Ross smb_auth_ntlm2_mkchallenge(char *result,
45*12b65585SGordon Ross 	const char *srv_chal, const char *clnt_chal)
46*12b65585SGordon Ross {
47*12b65585SGordon Ross 	MD5_CTX context;
48*12b65585SGordon Ross 	uchar_t challenges[2 * NTLM_CHAL_SZ];
49*12b65585SGordon Ross 	uchar_t digest[SMBAUTH_HASH_SZ];
50*12b65585SGordon Ross 
51*12b65585SGordon Ross 	/*
52*12b65585SGordon Ross 	 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
53*12b65585SGordon Ross 	 */
54*12b65585SGordon Ross 	(void) memcpy(challenges, srv_chal, NTLM_CHAL_SZ);
55*12b65585SGordon Ross 	(void) memcpy(challenges + NTLM_CHAL_SZ, clnt_chal, NTLM_CHAL_SZ);
56*12b65585SGordon Ross 
57*12b65585SGordon Ross 	/*
58*12b65585SGordon Ross 	 * digest = MD5(challenges)
59*12b65585SGordon Ross 	 */
60*12b65585SGordon Ross 	MD5Init(&context);
61*12b65585SGordon Ross 	MD5Update(&context, challenges, sizeof (challenges));
62*12b65585SGordon Ross 	MD5Final(digest, &context);
63*12b65585SGordon Ross 
64*12b65585SGordon Ross 	/*
65*12b65585SGordon Ross 	 * result = digest[0..7]
66*12b65585SGordon Ross 	 */
67*12b65585SGordon Ross 	(void) memcpy(result, digest, NTLM_CHAL_SZ);
68*12b65585SGordon Ross }
69*12b65585SGordon Ross 
70*12b65585SGordon Ross void
smb_auth_ntlm2_kxkey(unsigned char * result,const char * srv_chal,const char * clnt_chal,unsigned char * ssn_base_key)71*12b65585SGordon Ross smb_auth_ntlm2_kxkey(unsigned char *result, const char *srv_chal,
72*12b65585SGordon Ross 	const char *clnt_chal, unsigned char *ssn_base_key)
73*12b65585SGordon Ross {
74*12b65585SGordon Ross 	uchar_t challenges[2 * NTLM_CHAL_SZ];
75*12b65585SGordon Ross 
76*12b65585SGordon Ross 	/*
77*12b65585SGordon Ross 	 * challenges = ConcatenationOf(ServerChallenge, ClientChallenge)
78*12b65585SGordon Ross 	 */
79*12b65585SGordon Ross 	(void) memcpy(challenges, srv_chal, NTLM_CHAL_SZ);
80*12b65585SGordon Ross 	(void) memcpy(challenges + NTLM_CHAL_SZ, clnt_chal, NTLM_CHAL_SZ);
81*12b65585SGordon Ross 
82*12b65585SGordon Ross 	/* HMAC_MD5(SessionBaseKey, concat(...)) */
83*12b65585SGordon Ross 	/* SMBAUTH_HMACT64 args: D, Dsz, K, Ksz, digest */
84*12b65585SGordon Ross 	(void) SMBAUTH_HMACT64(challenges, sizeof (challenges),
85*12b65585SGordon Ross 	    ssn_base_key, SMBAUTH_HASH_SZ, result);
86*12b65585SGordon Ross }
87*12b65585SGordon Ross 
88da6c28aaSamw /*
89da6c28aaSamw  * smb_auth_qnd_unicode
90da6c28aaSamw  *
91da6c28aaSamw  * Quick and dirty unicode conversion!
92da6c28aaSamw  * Returns the length of dst in bytes.
93da6c28aaSamw  */
94da6c28aaSamw int
smb_auth_qnd_unicode(smb_wchar_t * dst,const char * src,int length)95bbf6f00cSJordan Brown smb_auth_qnd_unicode(smb_wchar_t *dst, const char *src, int length)
96da6c28aaSamw {
97da6c28aaSamw 	int i;
98da6c28aaSamw 	unsigned int count;
99bbf6f00cSJordan Brown 	smb_wchar_t new_char;
100da6c28aaSamw 
101bbf6f00cSJordan Brown 	if ((count = oemtoucs(dst, src, length, OEM_CPG_1252)) == 0) {
102da6c28aaSamw 		for (i = 0; i < length; ++i) {
103bbf6f00cSJordan Brown 			new_char = (smb_wchar_t)src[i] & 0xff;
104da6c28aaSamw 			dst[i] = LE_IN16(&new_char);
105da6c28aaSamw 		}
106da6c28aaSamw 		dst[i] = 0;
107da6c28aaSamw 		count = length;
108da6c28aaSamw 	}
109da6c28aaSamw 
110bbf6f00cSJordan Brown 	return (count * sizeof (smb_wchar_t));
111da6c28aaSamw }
112da6c28aaSamw 
113da6c28aaSamw /*
114da6c28aaSamw  * smb_auth_lmupr
115da6c28aaSamw  *
116da6c28aaSamw  * Converts the given LM password to all uppercase.
117da6c28aaSamw  * The standard strupr cannot
118da6c28aaSamw  * be used here because lm_pwd doesn't have to be
119da6c28aaSamw  * nul terminated.
120da6c28aaSamw  */
121da6c28aaSamw static void
smb_auth_lmupr(unsigned char * lm_pwd)122da6c28aaSamw smb_auth_lmupr(unsigned char *lm_pwd)
123da6c28aaSamw {
124da6c28aaSamw 	unsigned char *p = lm_pwd;
125da6c28aaSamw 	int i;
126da6c28aaSamw 
127da6c28aaSamw 	for (i = 0; (*p) && (i < SMBAUTH_LM_PWD_SZ); i++) {
128bbf6f00cSJordan Brown 		if (smb_isascii(*p)) {
129bbf6f00cSJordan Brown 			*p = smb_toupper(*p);
130da6c28aaSamw 			p++;
131da6c28aaSamw 		}
132da6c28aaSamw 	}
133da6c28aaSamw }
134da6c28aaSamw 
135da6c28aaSamw /*
136da6c28aaSamw  * smb_auth_lm_hash
137da6c28aaSamw  *
138da6c28aaSamw  * Source: Implementing CIFS (Chris Hertel)
139da6c28aaSamw  *
140da6c28aaSamw  * 1. The password, as entered by user, is either padded with nulls
141da6c28aaSamw  *	  or trimmed to 14 bytes.
142da6c28aaSamw  *    . Note that the 14-byte result string is not handled as a
143da6c28aaSamw  *	    nul-terminated string.
144da6c28aaSamw  *	  . The given password is OEM not Unicode
145da6c28aaSamw  *
146da6c28aaSamw  * 2. The 14-byte password is converted to all uppercase
147da6c28aaSamw  *
148da6c28aaSamw  * 3. The result is used as key to encrypt the KGS magic string to
149da6c28aaSamw  *    make a 16-byte hash.
150da6c28aaSamw  */
151da6c28aaSamw int
smb_auth_lm_hash(const char * password,unsigned char * lm_hash)15229bd2886SAlan Wright smb_auth_lm_hash(const char *password, unsigned char *lm_hash)
153da6c28aaSamw {
154da6c28aaSamw 	unsigned char lm_pwd[SMBAUTH_LM_PWD_SZ];
155da6c28aaSamw 
156da6c28aaSamw 	bzero((void *)lm_pwd, SMBAUTH_LM_PWD_SZ);
157da6c28aaSamw 	(void) strncpy((char *)lm_pwd, password, SMBAUTH_LM_PWD_SZ);
158da6c28aaSamw 	smb_auth_lmupr(lm_pwd);
159da6c28aaSamw 
160da6c28aaSamw 	return (smb_auth_DES(lm_hash, SMBAUTH_HASH_SZ, lm_pwd,
161da6c28aaSamw 	    SMBAUTH_LM_PWD_SZ, (unsigned char *)SMBAUTH_LM_MAGIC_STR,
162da6c28aaSamw 	    sizeof (SMBAUTH_LM_MAGIC_STR)));
163da6c28aaSamw }
164da6c28aaSamw 
165da6c28aaSamw /*
166da6c28aaSamw  * smb_auth_lm_response
167da6c28aaSamw  *
168da6c28aaSamw  * Create a LM response from the given LM hash and challenge.
169da6c28aaSamw  *
170da6c28aaSamw  * Returns SMBAUTH_FAILURE if any problems occur, SMBAUTH_SUCCESS if
171da6c28aaSamw  * all goes well.
172da6c28aaSamw  */
173da6c28aaSamw static int
smb_auth_lm_response(unsigned char * hash,unsigned char * challenge,unsigned char * lm_rsp)174da6c28aaSamw smb_auth_lm_response(unsigned char *hash,
175*12b65585SGordon Ross     unsigned char *challenge, /* NTLM_CHAL_SZ */
176da6c28aaSamw     unsigned char *lm_rsp)
177da6c28aaSamw {
178da6c28aaSamw 	unsigned char S21[21];
179da6c28aaSamw 
180da6c28aaSamw 	/*
181da6c28aaSamw 	 * 14-byte LM Hash should be padded with 5 nul bytes to create
182da6c28aaSamw 	 * a 21-byte string to be used in producing LM response
183da6c28aaSamw 	 */
184da6c28aaSamw 	bzero(&S21[SMBAUTH_HASH_SZ], 5);
185da6c28aaSamw 	bcopy(hash, S21, SMBAUTH_HASH_SZ);
186da6c28aaSamw 
187da6c28aaSamw 	/* padded LM Hash -> LM Response */
188da6c28aaSamw 	return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21,
189*12b65585SGordon Ross 	    challenge, NTLM_CHAL_SZ));
190da6c28aaSamw }
191da6c28aaSamw 
192da6c28aaSamw /*
193da6c28aaSamw  * smb_auth_ntlm_hash
194da6c28aaSamw  *
195da6c28aaSamw  * Make NTLM Hash (using MD4) from the given password.
196da6c28aaSamw  * The result will contain a 16-byte NTLM hash.
197da6c28aaSamw  */
198da6c28aaSamw int
smb_auth_ntlm_hash(const char * password,unsigned char * hash)19929bd2886SAlan Wright smb_auth_ntlm_hash(const char *password, unsigned char *hash)
200da6c28aaSamw {
201bbf6f00cSJordan Brown 	smb_wchar_t *unicode_password;
2021ed6b69aSGordon Ross 	int length, unicode_len;
203da6c28aaSamw 	int rc;
204da6c28aaSamw 
205da6c28aaSamw 	if (password == NULL || hash == NULL)
206da6c28aaSamw 		return (SMBAUTH_FAILURE);
207da6c28aaSamw 
208da6c28aaSamw 	length = strlen(password);
2091ed6b69aSGordon Ross 	unicode_len = (length + 1) * sizeof (smb_wchar_t);
2101ed6b69aSGordon Ross 	unicode_password = malloc(unicode_len);
211da6c28aaSamw 
212da6c28aaSamw 	if (unicode_password == NULL)
213da6c28aaSamw 		return (SMBAUTH_FAILURE);
214da6c28aaSamw 
215da6c28aaSamw 	length = smb_auth_qnd_unicode(unicode_password, password, length);
216da6c28aaSamw 	rc = smb_auth_md4(hash, (unsigned char *)unicode_password, length);
217da6c28aaSamw 
2181ed6b69aSGordon Ross 	(void) memset(unicode_password, 0, unicode_len);
219da6c28aaSamw 	free(unicode_password);
2201ed6b69aSGordon Ross 
221da6c28aaSamw 	return (rc);
222da6c28aaSamw }
223da6c28aaSamw 
224da6c28aaSamw /*
225da6c28aaSamw  * smb_auth_ntlm_response
226da6c28aaSamw  *
227da6c28aaSamw  * Make LM/NTLM response from the given LM/NTLM Hash and given
228da6c28aaSamw  * challenge.
229da6c28aaSamw  */
230da6c28aaSamw static int
smb_auth_ntlm_response(unsigned char * hash,unsigned char * challenge,unsigned char * ntlm_rsp)231da6c28aaSamw smb_auth_ntlm_response(unsigned char *hash,
232*12b65585SGordon Ross     unsigned char *challenge, /* NTLM_CHAL_SZ */
233da6c28aaSamw     unsigned char *ntlm_rsp)
234da6c28aaSamw {
235da6c28aaSamw 	unsigned char S21[21];
236da6c28aaSamw 
237da6c28aaSamw 	bcopy(hash, S21, SMBAUTH_HASH_SZ);
238da6c28aaSamw 	bzero(&S21[SMBAUTH_HASH_SZ], 5);
239da6c28aaSamw 	if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ,
240*12b65585SGordon Ross 	    S21, 21, challenge, NTLM_CHAL_SZ) == SMBAUTH_FAILURE)
241da6c28aaSamw 		return (0);
242da6c28aaSamw 	return (SMBAUTH_LM_RESP_SZ);
243da6c28aaSamw }
244da6c28aaSamw 
245da6c28aaSamw /*
246da6c28aaSamw  * smb_auth_ntlmv2_hash
247da6c28aaSamw  *
248da6c28aaSamw  * The NTLM v2 hash will be created from the given NTLM hash, username,
249da6c28aaSamw  * and the NETBIOS name of the domain.
250da6c28aaSamw  *
251da6c28aaSamw  * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
252da6c28aaSamw  * will be used in the calculation of the NTLMv2 and LMv2 responses.
253da6c28aaSamw  */
2548c10a865Sas int
smb_auth_ntlmv2_hash(unsigned char * ntlm_hash,char * username,char * ntdomain,unsigned char * ntlmv2_hash)255da6c28aaSamw smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
256c8ec8eeaSjose borrego     char *username,
257c8ec8eeaSjose borrego     char *ntdomain,
258c8ec8eeaSjose borrego     unsigned char *ntlmv2_hash)
259da6c28aaSamw {
260bbf6f00cSJordan Brown 	smb_wchar_t *data;
261da6c28aaSamw 	int data_len;
262da6c28aaSamw 	unsigned char *buf;
263da6c28aaSamw 	int rc;
264da6c28aaSamw 
265da6c28aaSamw 	if (username == NULL || ntdomain == NULL)
266da6c28aaSamw 		return (SMBAUTH_FAILURE);
267da6c28aaSamw 
268bbf6f00cSJordan Brown 	(void) smb_strupr(username);
269da6c28aaSamw 
270da6c28aaSamw 	data_len = strlen(username) + strlen(ntdomain);
271da6c28aaSamw 	buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
272da6c28aaSamw 	if (buf == NULL)
273da6c28aaSamw 		return (SMBAUTH_FAILURE);
274da6c28aaSamw 
275da6c28aaSamw 	(void) snprintf((char *)buf, data_len + 1, "%s%s", username, ntdomain);
276bbf6f00cSJordan Brown 	data = (smb_wchar_t *)malloc((data_len + 1) * sizeof (smb_wchar_t));
277da6c28aaSamw 	if (data == NULL) {
278da6c28aaSamw 		free(buf);
279da6c28aaSamw 		return (SMBAUTH_FAILURE);
280da6c28aaSamw 	}
281da6c28aaSamw 
282da6c28aaSamw 	data_len = smb_auth_qnd_unicode(data, (char *)buf, data_len);
283da6c28aaSamw 	rc = SMBAUTH_HMACT64((unsigned char *)data, data_len, ntlm_hash,
284da6c28aaSamw 	    SMBAUTH_HASH_SZ, ntlmv2_hash);
285da6c28aaSamw 
286da6c28aaSamw 	free(buf);
287da6c28aaSamw 	free(data);
288da6c28aaSamw 	return (rc);
289da6c28aaSamw }
290da6c28aaSamw 
291da6c28aaSamw /*
292da6c28aaSamw  * smb_auth_v2_response
293da6c28aaSamw  *
294da6c28aaSamw  * Caculates either the LMv2 or NTLMv2 response.
295da6c28aaSamw  *
296da6c28aaSamw  * Same algorithm is used for calculating both LMv2 or NTLMv2 responses.
297da6c28aaSamw  * This routine will return NTLMv2 response if the data blob information
298da6c28aaSamw  * is passed in as the clnt_data. Otherwise, it will return LMv2 response
299da6c28aaSamw  * with the 8-byte client challenge(a.k.a blip) as the clnt_data.
300da6c28aaSamw  *
301da6c28aaSamw  * (LM/NTLM)v2 response is the hmac-md5 hash of the specified data
302da6c28aaSamw  * (server challenge + NTLMv2 data blob or LMv2 client challenge)
303da6c28aaSamw  * using the NTLMv2 hash as the key.
304da6c28aaSamw  *
305da6c28aaSamw  * Returns the size of the corresponding v2 response upon success.
306da6c28aaSamw  * Otherwise, returns -1 on error.
307da6c28aaSamw  */
308da6c28aaSamw static int
smb_auth_v2_response(unsigned char * hash,unsigned char * srv_challenge,unsigned char * clnt_data,int clen,unsigned char * v2_rsp)309da6c28aaSamw smb_auth_v2_response(
310da6c28aaSamw 	unsigned char *hash,
311*12b65585SGordon Ross 	unsigned char *srv_challenge, /* NTLM_CHAL_SZ */
312da6c28aaSamw 	unsigned char *clnt_data, int clen,
313da6c28aaSamw 	unsigned char *v2_rsp)
314da6c28aaSamw {
315da6c28aaSamw 	unsigned char *hmac_data;
316*12b65585SGordon Ross 	int slen = NTLM_CHAL_SZ;
317da6c28aaSamw 
318*12b65585SGordon Ross 	hmac_data = malloc(NTLM_CHAL_SZ + clen);
319da6c28aaSamw 	if (!hmac_data) {
320da6c28aaSamw 		return (-1);
321da6c28aaSamw 	}
322da6c28aaSamw 
323da6c28aaSamw 	(void) memcpy(hmac_data, srv_challenge, slen);
324da6c28aaSamw 	(void) memcpy(&hmac_data[slen], clnt_data, clen);
325da6c28aaSamw 	if (SMBAUTH_HMACT64(hmac_data, slen + clen, (unsigned char *)hash,
326da6c28aaSamw 	    SMBAUTH_HASH_SZ, (unsigned char *)v2_rsp) != SMBAUTH_SUCCESS)
327da6c28aaSamw 		return (-1);
328da6c28aaSamw 	(void) memcpy(&v2_rsp[SMBAUTH_HASH_SZ], clnt_data, clen);
329da6c28aaSamw 
330da6c28aaSamw 	free(hmac_data);
331da6c28aaSamw 	return (SMBAUTH_HASH_SZ + clen);
332da6c28aaSamw }
333da6c28aaSamw 
334da6c28aaSamw 
335da6c28aaSamw static boolean_t
smb_lm_password_ok(unsigned char * challenge,unsigned char * lm_hash,unsigned char * lm_resp)336da6c28aaSamw smb_lm_password_ok(
337da6c28aaSamw     unsigned char *challenge,
338da6c28aaSamw     unsigned char *lm_hash,
339*12b65585SGordon Ross     unsigned char *lm_resp)
340da6c28aaSamw {
341*12b65585SGordon Ross 	unsigned char ok_resp[SMBAUTH_LM_RESP_SZ];
342da6c28aaSamw 	int rc;
343da6c28aaSamw 
344*12b65585SGordon Ross 	rc = smb_auth_lm_response(lm_hash, challenge, ok_resp);
345da6c28aaSamw 	if (rc != SMBAUTH_SUCCESS)
346da6c28aaSamw 		return (B_FALSE);
347da6c28aaSamw 
348*12b65585SGordon Ross 	return (bcmp(ok_resp, lm_resp, SMBAUTH_LM_RESP_SZ) == 0);
349da6c28aaSamw }
350da6c28aaSamw 
351da6c28aaSamw static boolean_t
smb_ntlm_password_ok(unsigned char * challenge,unsigned char * ntlm_hash,unsigned char * nt_resp,unsigned char * session_key)352da6c28aaSamw smb_ntlm_password_ok(
353da6c28aaSamw     unsigned char *challenge,
354da6c28aaSamw     unsigned char *ntlm_hash,
355*12b65585SGordon Ross     unsigned char *nt_resp,
356c8ec8eeaSjose borrego     unsigned char *session_key)
357da6c28aaSamw {
358*12b65585SGordon Ross 	unsigned char ok_resp[SMBAUTH_LM_RESP_SZ];
359da6c28aaSamw 	int rc;
360c8ec8eeaSjose borrego 	boolean_t ok;
361da6c28aaSamw 
362*12b65585SGordon Ross 	rc = smb_auth_ntlm_response(ntlm_hash, challenge, ok_resp);
363da6c28aaSamw 	if (rc != SMBAUTH_LM_RESP_SZ)
364da6c28aaSamw 		return (B_FALSE);
365da6c28aaSamw 
366*12b65585SGordon Ross 	ok = (bcmp(ok_resp, nt_resp, SMBAUTH_LM_RESP_SZ) == 0);
367c8ec8eeaSjose borrego 	if (ok && (session_key)) {
368c8ec8eeaSjose borrego 		rc = smb_auth_md4(session_key, ntlm_hash, SMBAUTH_HASH_SZ);
369c8ec8eeaSjose borrego 		if (rc != SMBAUTH_SUCCESS)
370c8ec8eeaSjose borrego 			ok = B_FALSE;
371c8ec8eeaSjose borrego 	}
372c8ec8eeaSjose borrego 	return (ok);
373da6c28aaSamw }
374da6c28aaSamw 
375da6c28aaSamw static boolean_t
smb_ntlmv2_password_ok(unsigned char * challenge,unsigned char * ntlm_hash,unsigned char * passwd,int pwdlen,char * domain,char * username,uchar_t * session_key)376da6c28aaSamw smb_ntlmv2_password_ok(
377da6c28aaSamw     unsigned char *challenge,
378da6c28aaSamw     unsigned char *ntlm_hash,
379da6c28aaSamw     unsigned char *passwd,
380da6c28aaSamw     int pwdlen,
381dc20a302Sas     char *domain,
382c8ec8eeaSjose borrego     char *username,
383c8ec8eeaSjose borrego     uchar_t *session_key)
384da6c28aaSamw {
385da6c28aaSamw 	unsigned char *clnt_blob;
386da6c28aaSamw 	int clnt_blob_len;
387da6c28aaSamw 	unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
388da6c28aaSamw 	unsigned char *ntlmv2_resp;
389dc20a302Sas 	boolean_t ok = B_FALSE;
390dc20a302Sas 	char *dest[3];
391dc20a302Sas 	int i;
392c8ec8eeaSjose borrego 	int rc;
393da6c28aaSamw 
394da6c28aaSamw 	clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
395da6c28aaSamw 	clnt_blob = &passwd[SMBAUTH_HASH_SZ];
396dc20a302Sas 	dest[0] = domain;
397dc20a302Sas 	if ((dest[1] = strdup(domain)) == NULL)
398dc20a302Sas 		return (B_FALSE);
399bbf6f00cSJordan Brown 	(void) smb_strupr(dest[1]);
400dc20a302Sas 	dest[2] = "";
401da6c28aaSamw 
402da6c28aaSamw 	/*
403da6c28aaSamw 	 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
404da6c28aaSamw 	 *
405dc20a302Sas 	 * The NTLMv2 Hash is created from:
406da6c28aaSamw 	 * - NTLM hash
407da6c28aaSamw 	 * - user's username, and
408da6c28aaSamw 	 * - the name of the logon destination(i.e. the NetBIOS name of either
409dc20a302Sas 	 *   the SMB server or NT Domain against which the user is trying to
410da6c28aaSamw 	 *   authenticate.
411da6c28aaSamw 	 *
412dc20a302Sas 	 * Experiments show this is not exactly the case.
413dc20a302Sas 	 * For Windows Server 2003, the domain name needs to be included and
414dc20a302Sas 	 * converted to uppercase. For Vista, the domain name needs to be
415dc20a302Sas 	 * included also, but leave the case alone.  And in some cases it needs
416dc20a302Sas 	 * to be empty. All three variants are tried here.
417da6c28aaSamw 	 */
418da6c28aaSamw 
419da6c28aaSamw 	ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
420dc20a302Sas 	if (ntlmv2_resp == NULL) {
421dc20a302Sas 		free(dest[1]);
422da6c28aaSamw 		return (B_FALSE);
423da6c28aaSamw 	}
424da6c28aaSamw 
425dc20a302Sas 	for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
426dc20a302Sas 		if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
427dc20a302Sas 		    ntlmv2_hash) != SMBAUTH_SUCCESS)
428dc20a302Sas 			break;
429dc20a302Sas 
430dc20a302Sas 		if (smb_auth_v2_response(ntlmv2_hash, challenge,
431*12b65585SGordon Ross 		    clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
432dc20a302Sas 			break;
433dc20a302Sas 
434dc20a302Sas 		ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
435c8ec8eeaSjose borrego 		if (ok && session_key) {
436c8ec8eeaSjose borrego 			rc = SMBAUTH_HMACT64(ntlmv2_resp,
437c8ec8eeaSjose borrego 			    SMBAUTH_HASH_SZ, ntlmv2_hash,
438c8ec8eeaSjose borrego 			    SMBAUTH_SESSION_KEY_SZ, session_key);
439c8ec8eeaSjose borrego 			if (rc != SMBAUTH_SUCCESS) {
440c8ec8eeaSjose borrego 				ok = B_FALSE;
441c8ec8eeaSjose borrego 			}
442dc20a302Sas 			break;
443c8ec8eeaSjose borrego 		}
444dc20a302Sas 	}
445dc20a302Sas 
446dc20a302Sas 	free(dest[1]);
447da6c28aaSamw 	free(ntlmv2_resp);
448da6c28aaSamw 	return (ok);
449da6c28aaSamw }
450da6c28aaSamw 
451dc20a302Sas static boolean_t
smb_lmv2_password_ok(unsigned char * srv_challenge,unsigned char * ntlm_hash,unsigned char * passwd,char * domain,char * username)452da6c28aaSamw smb_lmv2_password_ok(
453*12b65585SGordon Ross     unsigned char *srv_challenge,
454da6c28aaSamw     unsigned char *ntlm_hash,
455da6c28aaSamw     unsigned char *passwd,
456dc20a302Sas     char *domain,
457da6c28aaSamw     char *username)
458da6c28aaSamw {
459da6c28aaSamw 	unsigned char *clnt_challenge;
460da6c28aaSamw 	unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
461da6c28aaSamw 	unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
462dc20a302Sas 	boolean_t ok = B_FALSE;
463dc20a302Sas 	char *dest[3];
464dc20a302Sas 	int i;
465da6c28aaSamw 
466da6c28aaSamw 	clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
467dc20a302Sas 	dest[0] = domain;
468dc20a302Sas 	if ((dest[1] = strdup(domain)) == NULL)
469dc20a302Sas 		return (B_FALSE);
470bbf6f00cSJordan Brown 	(void) smb_strupr(dest[1]);
471dc20a302Sas 	dest[2] = "";
472da6c28aaSamw 
473da6c28aaSamw 	/*
474da6c28aaSamw 	 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
475da6c28aaSamw 	 *
476da6c28aaSamw 	 * The NTLMv2 Hash is created from:
477da6c28aaSamw 	 * - NTLM hash
478da6c28aaSamw 	 * - user's username, and
479da6c28aaSamw 	 * - the name of the logon destination(i.e. the NetBIOS name of either
480da6c28aaSamw 	 *   the SMB server or NT Domain against which the suer is trying to
481da6c28aaSamw 	 *   authenticate.
482da6c28aaSamw 	 *
483dc20a302Sas 	 * Experiments show this is not exactly the case.
484dc20a302Sas 	 * For Windows Server 2003, the domain name needs to be included and
485dc20a302Sas 	 * converted to uppercase. For Vista, the domain name needs to be
486dc20a302Sas 	 * included also, but leave the case alone.  And in some cases it needs
487dc20a302Sas 	 * to be empty. All three variants are tried here.
488da6c28aaSamw 	 */
489dc20a302Sas 
490dc20a302Sas 	for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
491dc20a302Sas 		if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
492dc20a302Sas 		    ntlmv2_hash) != SMBAUTH_SUCCESS)
493dc20a302Sas 			break;
494dc20a302Sas 
495*12b65585SGordon Ross 		if (smb_auth_v2_response(ntlmv2_hash, srv_challenge,
496*12b65585SGordon Ross 		    clnt_challenge, SMBAUTH_CHAL_SZ,
497dc20a302Sas 		    lmv2_resp) < 0)
498dc20a302Sas 			break;
499dc20a302Sas 
500dc20a302Sas 		ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
501c8ec8eeaSjose borrego 		if (ok)
502dc20a302Sas 			break;
503da6c28aaSamw 	}
504da6c28aaSamw 
505dc20a302Sas 	free(dest[1]);
506dc20a302Sas 	return (ok);
507da6c28aaSamw }
508da6c28aaSamw 
509da6c28aaSamw /*
510*12b65585SGordon Ross  * smb_auth_validate
511da6c28aaSamw  *
512*12b65585SGordon Ross  * Validates given NTLMv2 (or NTLM, LMv2, LM) client responses against
513*12b65585SGordon Ross  * the stored user's password, passed in smbpw.  Try those in the order
514*12b65585SGordon Ross  * strongest to weakest, stopping at a point determined by the configured
515*12b65585SGordon Ross  * lmauth_level (LM Compatibility Level).
516da6c28aaSamw  */
517da6c28aaSamw boolean_t
smb_auth_validate(smb_passwd_t * smbpw,char * domain,char * username,unsigned char * challenge,uint_t clen,unsigned char * nt_resp,uint_t nt_len,unsigned char * lm_resp,uint_t lm_len,uchar_t * session_key)518*12b65585SGordon Ross smb_auth_validate(
519da6c28aaSamw     smb_passwd_t *smbpw,
520dc20a302Sas     char *domain,
521*12b65585SGordon Ross     char *username,
522*12b65585SGordon Ross     unsigned char *challenge,
523*12b65585SGordon Ross     uint_t clen,
524*12b65585SGordon Ross     unsigned char *nt_resp,
525*12b65585SGordon Ross     uint_t nt_len,
526*12b65585SGordon Ross     unsigned char *lm_resp,
527*12b65585SGordon Ross     uint_t lm_len,
528*12b65585SGordon Ross     uchar_t *session_key)
529da6c28aaSamw {
530dc20a302Sas 	int64_t lmlevel;
531*12b65585SGordon Ross 	boolean_t ok = B_FALSE;
532da6c28aaSamw 
533dc20a302Sas 	if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
534dc20a302Sas 		return (B_FALSE);
535da6c28aaSamw 
536*12b65585SGordon Ross 	if (lmlevel > 5)
537*12b65585SGordon Ross 		return (B_FALSE);
538da6c28aaSamw 
539*12b65585SGordon Ross 	if (clen != NTLM_CHAL_SZ)
540*12b65585SGordon Ross 		return (B_FALSE);
541da6c28aaSamw 
542*12b65585SGordon Ross 	/*
543*12b65585SGordon Ross 	 * Accept NTLMv2 at any LM level (0-5).
544*12b65585SGordon Ross 	 */
545*12b65585SGordon Ross 	if (nt_len > SMBAUTH_LM_RESP_SZ) {
546*12b65585SGordon Ross 		ok = smb_ntlmv2_password_ok(challenge,
547*12b65585SGordon Ross 		    smbpw->pw_nthash, nt_resp, nt_len,
548*12b65585SGordon Ross 		    domain, username, session_key);
549*12b65585SGordon Ross 		if (ok)
550*12b65585SGordon Ross 			return (ok);
551*12b65585SGordon Ross 	}
552da6c28aaSamw 
553*12b65585SGordon Ross 	if (lmlevel == 5)
554dc20a302Sas 		return (B_FALSE);
555da6c28aaSamw 
556*12b65585SGordon Ross 	/*
557*12b65585SGordon Ross 	 * Accept NTLM at levels 0-4
558*12b65585SGordon Ross 	 */
559*12b65585SGordon Ross 	if (nt_len == SMBAUTH_LM_RESP_SZ) {
560*12b65585SGordon Ross 		ok = smb_ntlm_password_ok(challenge, smbpw->pw_nthash,
561*12b65585SGordon Ross 		    nt_resp, session_key);
562*12b65585SGordon Ross 		if (ok)
563*12b65585SGordon Ross 			return (ok);
564*12b65585SGordon Ross 	}
565*12b65585SGordon Ross 
566*12b65585SGordon Ross 	if (lmlevel == 4)
567da6c28aaSamw 		return (B_FALSE);
568da6c28aaSamw 
569da6c28aaSamw 
570*12b65585SGordon Ross 	/*
571*12b65585SGordon Ross 	 * Accept LM/LMv2 auth at levels 0-3
572*12b65585SGordon Ross 	 */
573*12b65585SGordon Ross 	if (lm_len != SMBAUTH_LM_RESP_SZ)
574*12b65585SGordon Ross 		return (B_FALSE);
575*12b65585SGordon Ross 	if (session_key)
576*12b65585SGordon Ross 		(void) smb_auth_md4(session_key, smbpw->pw_nthash,
577*12b65585SGordon Ross 		    SMBAUTH_HASH_SZ);
578*12b65585SGordon Ross 	ok = smb_lmv2_password_ok(challenge, smbpw->pw_nthash,
579*12b65585SGordon Ross 	    lm_resp, domain, username);
580*12b65585SGordon Ross 	if (ok)
581*12b65585SGordon Ross 		return (ok);
582*12b65585SGordon Ross 	ok = smb_lm_password_ok(challenge, smbpw->pw_lmhash, lm_resp);
583*12b65585SGordon Ross 	if (ok)
584*12b65585SGordon Ross 		return (ok);
585*12b65585SGordon Ross 
586*12b65585SGordon Ross 	return (B_FALSE);
587da6c28aaSamw }
5881ed6b69aSGordon Ross 
5891ed6b69aSGordon Ross /*
5901ed6b69aSGordon Ross  * smb_gen_random_passwd(buf, len)
5911ed6b69aSGordon Ross  * Generate a random password of length len-1, and store it in buf,
5921ed6b69aSGordon Ross  * null terminated.  This is used as a machine account password,
5931ed6b69aSGordon Ross  * which we set when we join a domain.
5941ed6b69aSGordon Ross  *
5951ed6b69aSGordon Ross  * [MS-DISO] A machine password is an ASCII string of randomly chosen
5961ed6b69aSGordon Ross  * characters. Each character's ASCII code is between 32 and 122 inclusive.
5971ed6b69aSGordon Ross  * That's space through 'z'.
5981ed6b69aSGordon Ross  */
5991ed6b69aSGordon Ross 
6001ed6b69aSGordon Ross int
smb_gen_random_passwd(char * buf,size_t len)6011ed6b69aSGordon Ross smb_gen_random_passwd(char *buf, size_t len)
6021ed6b69aSGordon Ross {
6031ed6b69aSGordon Ross 	const uchar_t start = ' ';
6041ed6b69aSGordon Ross 	const uchar_t modulus = 'z' - ' ' + 1;
6051ed6b69aSGordon Ross 	uchar_t t;
6061ed6b69aSGordon Ross 	int i;
6071ed6b69aSGordon Ross 
6081ed6b69aSGordon Ross 	/* Last byte is the null. */
6091ed6b69aSGordon Ross 	len--;
6101ed6b69aSGordon Ross 
6111ed6b69aSGordon Ross 	/* Temporarily put random data in the caller's buffer. */
6121ed6b69aSGordon Ross 	randomize(buf, len);
6131ed6b69aSGordon Ross 
6141ed6b69aSGordon Ross 	/* Convert the random data to printable characters. */
6151ed6b69aSGordon Ross 	for (i = 0; i < len; i++) {
6161ed6b69aSGordon Ross 		/* need unsigned math */
6171ed6b69aSGordon Ross 		t = (uchar_t)buf[i];
6181ed6b69aSGordon Ross 		t = (t % modulus) + start;
6191ed6b69aSGordon Ross 		assert(' ' <= t && t <= 'z');
6201ed6b69aSGordon Ross 		buf[i] = (char)t;
6211ed6b69aSGordon Ross 	}
6221ed6b69aSGordon Ross 
6231ed6b69aSGordon Ross 	buf[len] = '\0';
6241ed6b69aSGordon Ross 
6251ed6b69aSGordon Ross 	return (0);
6261ed6b69aSGordon Ross }
627