xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_auth.c (revision 2850d85b7b93f31e578520dc3b3feb24db609c62)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <strings.h>
29 #include <stdlib.h>
30 #include <smbsrv/alloc.h>
31 #include <smbsrv/codepage.h>
32 #include <smbsrv/oem.h>
33 #include <smbsrv/ctype.h>
34 #include <smbsrv/crypt.h>
35 #include <smbsrv/libsmb.h>
36 
37 extern void randomize(char *data, unsigned len);
38 static uint64_t unix_micro_to_nt_time(struct timeval *unix_time);
39 
40 /*
41  * smb_auth_qnd_unicode
42  *
43  * Quick and dirty unicode conversion!
44  * Returns the length of dst in bytes.
45  */
46 int
47 smb_auth_qnd_unicode(mts_wchar_t *dst, char *src, int length)
48 {
49 	int i;
50 
51 	unsigned int cpid = oem_get_telnet_cpid();
52 	unsigned int count;
53 	mts_wchar_t new_char;
54 
55 	if ((count = oemstounicodes(dst, src, length, cpid)) == 0) {
56 		for (i = 0; i < length; ++i) {
57 			new_char = (mts_wchar_t)src[i] & 0xff;
58 			dst[i] = LE_IN16(&new_char);
59 		}
60 		dst[i] = 0;
61 		count = length;
62 	}
63 
64 	return (count * sizeof (mts_wchar_t));
65 }
66 
67 /*
68  * smb_auth_lmupr
69  *
70  * Converts the given LM password to all uppercase.
71  * The standard strupr cannot
72  * be used here because lm_pwd doesn't have to be
73  * nul terminated.
74  */
75 static void
76 smb_auth_lmupr(unsigned char *lm_pwd)
77 {
78 	unsigned char *p = lm_pwd;
79 	int i;
80 
81 	for (i = 0; (*p) && (i < SMBAUTH_LM_PWD_SZ); i++) {
82 		if (mts_isascii(*p)) {
83 			*p = codepage_toupper(*p);
84 			p++;
85 		}
86 	}
87 }
88 
89 /*
90  * smb_auth_lm_hash
91  *
92  * Source: Implementing CIFS (Chris Hertel)
93  *
94  * 1. The password, as entered by user, is either padded with nulls
95  *	  or trimmed to 14 bytes.
96  *    . Note that the 14-byte result string is not handled as a
97  *	    nul-terminated string.
98  *	  . The given password is OEM not Unicode
99  *
100  * 2. The 14-byte password is converted to all uppercase
101  *
102  * 3. The result is used as key to encrypt the KGS magic string to
103  *    make a 16-byte hash.
104  */
105 int
106 smb_auth_lm_hash(char *password, unsigned char *lm_hash)
107 {
108 	unsigned char lm_pwd[SMBAUTH_LM_PWD_SZ];
109 
110 	bzero((void *)lm_pwd, SMBAUTH_LM_PWD_SZ);
111 	(void) strncpy((char *)lm_pwd, password, SMBAUTH_LM_PWD_SZ);
112 	smb_auth_lmupr(lm_pwd);
113 
114 	return (smb_auth_DES(lm_hash, SMBAUTH_HASH_SZ, lm_pwd,
115 	    SMBAUTH_LM_PWD_SZ, (unsigned char *)SMBAUTH_LM_MAGIC_STR,
116 	    sizeof (SMBAUTH_LM_MAGIC_STR)));
117 }
118 
119 /*
120  * smb_auth_lm_response
121  *
122  * Create a LM response from the given LM hash and challenge.
123  *
124  * Returns SMBAUTH_FAILURE if any problems occur, SMBAUTH_SUCCESS if
125  * all goes well.
126  */
127 static int
128 smb_auth_lm_response(unsigned char *hash,
129     unsigned char *challenge, int clen,
130     unsigned char *lm_rsp)
131 {
132 	unsigned char S21[21];
133 
134 	/*
135 	 * 14-byte LM Hash should be padded with 5 nul bytes to create
136 	 * a 21-byte string to be used in producing LM response
137 	 */
138 	bzero(&S21[SMBAUTH_HASH_SZ], 5);
139 	bcopy(hash, S21, SMBAUTH_HASH_SZ);
140 
141 	/* padded LM Hash -> LM Response */
142 	return (smb_auth_DES(lm_rsp, SMBAUTH_LM_RESP_SZ, S21, 21,
143 	    challenge, clen));
144 }
145 
146 /*
147  * smb_auth_ntlm_hash
148  *
149  * Make NTLM Hash (using MD4) from the given password.
150  * The result will contain a 16-byte NTLM hash.
151  */
152 int
153 smb_auth_ntlm_hash(char *password, unsigned char *hash)
154 {
155 	mts_wchar_t *unicode_password;
156 	int length;
157 	int rc;
158 
159 	if (password == NULL || hash == NULL)
160 		return (SMBAUTH_FAILURE);
161 
162 	length = strlen(password);
163 	unicode_password = (mts_wchar_t *)
164 	    malloc((length + 1) * sizeof (mts_wchar_t));
165 
166 	if (unicode_password == NULL)
167 		return (SMBAUTH_FAILURE);
168 
169 	length = smb_auth_qnd_unicode(unicode_password, password, length);
170 	rc = smb_auth_md4(hash, (unsigned char *)unicode_password, length);
171 
172 	free(unicode_password);
173 	return (rc);
174 }
175 
176 /*
177  * smb_auth_ntlm_response
178  *
179  * Make LM/NTLM response from the given LM/NTLM Hash and given
180  * challenge.
181  */
182 static int
183 smb_auth_ntlm_response(unsigned char *hash,
184     unsigned char *challenge, int clen,
185     unsigned char *ntlm_rsp)
186 {
187 	unsigned char S21[21];
188 
189 	bcopy(hash, S21, SMBAUTH_HASH_SZ);
190 	bzero(&S21[SMBAUTH_HASH_SZ], 5);
191 	if (smb_auth_DES((unsigned char *)ntlm_rsp, SMBAUTH_LM_RESP_SZ,
192 	    S21, 21, challenge, clen) == SMBAUTH_FAILURE)
193 		return (0);
194 	return (SMBAUTH_LM_RESP_SZ);
195 }
196 
197 /*
198  * smb_auth_gen_data_blob
199  *
200  * Fill the NTLMv2 data blob structure with information as described in
201  * "Implementing CIFS, The Common Internet File System". (pg. 282)
202  */
203 static void
204 smb_auth_gen_data_blob(smb_auth_data_blob_t *blob, char *ntdomain)
205 {
206 	struct timeval now;
207 
208 	(void) memset(blob->ndb_signature, 1, 2);
209 	(void) memset(&blob->ndb_signature[2], 0, 2);
210 	(void) memset(blob->ndb_reserved, 0, sizeof (blob->ndb_reserved));
211 
212 	(void) gettimeofday(&now, 0);
213 	blob->ndb_timestamp = unix_micro_to_nt_time(&now);
214 	randomize((char *)blob->ndb_clnt_challenge,
215 	    SMBAUTH_V2_CLNT_CHALLENGE_SZ);
216 	(void) memset(blob->ndb_unknown, 0, sizeof (blob->ndb_unknown));
217 	blob->ndb_names[0].nne_len = smb_auth_qnd_unicode(
218 	    blob->ndb_names[0].nne_name, ntdomain, strlen(ntdomain));
219 	blob->ndb_names[0].nne_type = SMBAUTH_NAME_TYPE_DOMAIN_NETBIOS;
220 	blob->ndb_names[1].nne_len = 0;
221 	blob->ndb_names[1].nne_type = SMBAUTH_NAME_TYPE_LIST_END;
222 	*blob->ndb_names[1].nne_name = 0;
223 	(void) memset(blob->ndb_unknown2, 0, sizeof (blob->ndb_unknown2));
224 }
225 
226 /*
227  * smb_auth_memcpy
228  *
229  * It increments the pointer to the destination buffer for the easy of
230  * concatenation.
231  */
232 static void
233 smb_auth_memcpy(unsigned char **dstbuf,
234 	unsigned char *srcbuf,
235 	int srcbuf_len)
236 {
237 	(void) memcpy(*dstbuf, srcbuf, srcbuf_len);
238 	*dstbuf += srcbuf_len;
239 }
240 
241 /*
242  * smb_auth_blob_to_string
243  *
244  * Prepare the data blob string which will be used in NTLMv2 response
245  * generation.
246  *
247  * Assumption: Caller must allocate big enough buffer to prevent buffer
248  * overrun.
249  *
250  * Returns the len of the data blob string.
251  */
252 static int
253 smb_auth_blob_to_string(smb_auth_data_blob_t *blob, unsigned char *data_blob)
254 {
255 	unsigned char *bufp = data_blob;
256 
257 	smb_auth_memcpy(&bufp, blob->ndb_signature,
258 	    sizeof (blob->ndb_signature));
259 	smb_auth_memcpy(&bufp, blob->ndb_reserved,
260 	    sizeof (blob->ndb_reserved));
261 	smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_timestamp,
262 	    sizeof (blob->ndb_timestamp));
263 	smb_auth_memcpy(&bufp, blob->ndb_clnt_challenge,
264 	    SMBAUTH_V2_CLNT_CHALLENGE_SZ);
265 	smb_auth_memcpy(&bufp, blob->ndb_unknown, sizeof (blob->ndb_unknown));
266 	smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_type,
267 	    sizeof (blob->ndb_names[0].nne_type));
268 	smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[0].nne_len,
269 	    sizeof (blob->ndb_names[0].nne_len));
270 	smb_auth_memcpy(&bufp, (unsigned char *)blob->ndb_names[0].nne_name,
271 	    blob->ndb_names[0].nne_len);
272 	smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_type,
273 	    sizeof (blob->ndb_names[1].nne_type));
274 	smb_auth_memcpy(&bufp, (unsigned char *)&blob->ndb_names[1].nne_len,
275 	    sizeof (blob->ndb_names[1].nne_len));
276 	smb_auth_memcpy(&bufp, blob->ndb_unknown2, sizeof (blob->ndb_unknown2));
277 
278 	/*LINTED E_PTRDIFF_OVERFLOW*/
279 	return (bufp - data_blob);
280 }
281 
282 /*
283  * smb_auth_ntlmv2_hash
284  *
285  * The NTLM v2 hash will be created from the given NTLM hash, username,
286  * and the NETBIOS name of the domain.
287  *
288  * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
289  * will be used in the calculation of the NTLMv2 and LMv2 responses.
290  */
291 static int
292 smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
293 	char *username,
294 	char *ntdomain,
295 	unsigned char *ntlmv2_hash)
296 {
297 	mts_wchar_t *data;
298 	int data_len;
299 	unsigned char *buf;
300 	int rc;
301 
302 	if (username == NULL || ntdomain == NULL)
303 		return (SMBAUTH_FAILURE);
304 
305 	(void) utf8_strupr(username);
306 
307 	data_len = strlen(username) + strlen(ntdomain);
308 	buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
309 	if (buf == NULL)
310 		return (SMBAUTH_FAILURE);
311 
312 	(void) snprintf((char *)buf, data_len + 1, "%s%s", username, ntdomain);
313 	data = (mts_wchar_t *)malloc((data_len + 1) * sizeof (mts_wchar_t));
314 	if (data == NULL) {
315 		free(buf);
316 		return (SMBAUTH_FAILURE);
317 	}
318 
319 	data_len = smb_auth_qnd_unicode(data, (char *)buf, data_len);
320 	rc = SMBAUTH_HMACT64((unsigned char *)data, data_len, ntlm_hash,
321 	    SMBAUTH_HASH_SZ, ntlmv2_hash);
322 
323 	free(buf);
324 	free(data);
325 	return (rc);
326 }
327 
328 /*
329  * smb_auth_v2_response
330  *
331  * Caculates either the LMv2 or NTLMv2 response.
332  *
333  * Same algorithm is used for calculating both LMv2 or NTLMv2 responses.
334  * This routine will return NTLMv2 response if the data blob information
335  * is passed in as the clnt_data. Otherwise, it will return LMv2 response
336  * with the 8-byte client challenge(a.k.a blip) as the clnt_data.
337  *
338  * (LM/NTLM)v2 response is the hmac-md5 hash of the specified data
339  * (server challenge + NTLMv2 data blob or LMv2 client challenge)
340  * using the NTLMv2 hash as the key.
341  *
342  * Returns the size of the corresponding v2 response upon success.
343  * Otherwise, returns -1 on error.
344  */
345 static int
346 smb_auth_v2_response(
347 	unsigned char *hash,
348 	unsigned char *srv_challenge, int slen,
349 	unsigned char *clnt_data, int clen,
350 	unsigned char *v2_rsp)
351 {
352 	unsigned char *hmac_data;
353 
354 	hmac_data = (unsigned char *)malloc((slen + clen) * sizeof (char));
355 	if (!hmac_data) {
356 		return (-1);
357 	}
358 
359 	(void) memcpy(hmac_data, srv_challenge, slen);
360 	(void) memcpy(&hmac_data[slen], clnt_data, clen);
361 	if (SMBAUTH_HMACT64(hmac_data, slen + clen, (unsigned char *)hash,
362 	    SMBAUTH_HASH_SZ, (unsigned char *)v2_rsp) != SMBAUTH_SUCCESS)
363 		return (-1);
364 	(void) memcpy(&v2_rsp[SMBAUTH_HASH_SZ], clnt_data, clen);
365 
366 	free(hmac_data);
367 	return (SMBAUTH_HASH_SZ + clen);
368 }
369 
370 /*
371  * smb_auth_set_info
372  *
373  * Fill the smb_auth_info instance with either NTLM or NTLMv2 related
374  * authentication information based on the LMCompatibilityLevel.
375  *
376  * If the LMCompatibilityLevel equals 2, the SMB Redirector will perform
377  * NTLM challenge/response authentication which requires the NTLM hash and
378  * NTLM response.
379  *
380  * If the LMCompatibilityLevel is 3 or above, the SMB Redirector will
381  * perfrom NTLMv2 challenge/response authenticatoin which requires the
382  * NTLM hash, NTLMv2 hash, NTLMv2 response and LMv2 response.
383  *
384  * Returns -1 on error. Otherwise, returns 0 upon success.
385  */
386 int
387 smb_auth_set_info(char *username,
388 	char *password,
389 	unsigned char *ntlm_hash,
390 	char *domain,
391 	unsigned char *srv_challenge_key,
392 	int srv_challenge_len,
393 	int lmcomp_lvl,
394 	smb_auth_info_t *auth)
395 {
396 	unsigned short blob_len;
397 	unsigned char blob_buf[SMBAUTH_BLOB_MAXLEN];
398 	int rc;
399 	char *uppercase_dom;
400 
401 	auth->lmcompatibility_lvl = lmcomp_lvl;
402 	if (lmcomp_lvl == 2) {
403 		auth->ci_len = 0;
404 		*auth->ci = 0;
405 		if (!ntlm_hash) {
406 			if (smb_auth_ntlm_hash(password, auth->hash) !=
407 			    SMBAUTH_SUCCESS)
408 				return (-1);
409 		} else {
410 			(void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
411 		}
412 
413 		auth->cs_len = smb_auth_ntlm_response(auth->hash,
414 		    srv_challenge_key, srv_challenge_len, auth->cs);
415 	} else {
416 		if (!ntlm_hash) {
417 			if (smb_auth_ntlm_hash(password, auth->hash) !=
418 			    SMBAUTH_SUCCESS)
419 				return (-1);
420 		} else {
421 			(void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
422 		}
423 
424 		if (!domain)
425 			return (-1);
426 
427 		if ((uppercase_dom = strdup(domain)) == NULL)
428 			return (-1);
429 
430 		(void) utf8_strupr(uppercase_dom);
431 
432 		if (smb_auth_ntlmv2_hash(auth->hash, username,
433 		    uppercase_dom, auth->hash_v2) != SMBAUTH_SUCCESS) {
434 			free(uppercase_dom);
435 			return (-1);
436 		}
437 
438 		/* generate data blob */
439 		smb_auth_gen_data_blob(&auth->data_blob, uppercase_dom);
440 		free(uppercase_dom);
441 		blob_len = smb_auth_blob_to_string(&auth->data_blob, blob_buf);
442 
443 		/* generate NTLMv2 response */
444 		rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
445 		    srv_challenge_len, blob_buf, blob_len, auth->cs);
446 
447 		if (rc < 0)
448 			return (-1);
449 
450 		auth->cs_len = rc;
451 
452 		/* generate LMv2 response */
453 		rc = smb_auth_v2_response(auth->hash_v2, srv_challenge_key,
454 		    srv_challenge_len, auth->data_blob.ndb_clnt_challenge,
455 		    SMBAUTH_V2_CLNT_CHALLENGE_SZ, auth->ci);
456 
457 		if (rc < 0)
458 			return (-1);
459 
460 		auth->ci_len = rc;
461 	}
462 
463 	return (0);
464 }
465 
466 /*
467  * smb_auth_gen_session_key
468  *
469  * Generate the NTLM user session key if LMCompatibilityLevel is 2 or
470  * NTLMv2 user session key if LMCompatibilityLevel is 3 or above.
471  *
472  * NTLM_Session_Key = MD4(NTLM_Hash);
473  *
474  * NTLMv2_Session_Key = HMAC_MD5(NTLMv2Hash, 16, NTLMv2_HMAC, 16)
475  *
476  * Prior to calling this function, the auth instance should be set
477  * via smb_auth_set_info().
478  *
479  * Returns the appropriate session key.
480  */
481 int
482 smb_auth_gen_session_key(smb_auth_info_t *auth, unsigned char *session_key)
483 {
484 	int rc;
485 
486 	if (auth->lmcompatibility_lvl == 2)
487 		rc = smb_auth_md4(session_key, auth->hash, SMBAUTH_HASH_SZ);
488 	else
489 		rc = SMBAUTH_HMACT64((unsigned char *)auth->cs,
490 		    SMBAUTH_HASH_SZ, (unsigned char *)auth->hash_v2,
491 		    SMBAUTH_SESSION_KEY_SZ, session_key);
492 
493 	return (rc);
494 }
495 
496 /* 100's of ns between 1/1/1970 and 1/1/1601 */
497 #define	NT_TIME_BIAS    (134774LL * 24LL * 60LL * 60LL * 10000000LL)
498 
499 static uint64_t
500 unix_micro_to_nt_time(struct timeval *unix_time)
501 {
502 	uint64_t nt_time;
503 
504 	nt_time = unix_time->tv_sec;
505 	nt_time *= 10000000;  /* seconds to 100ns */
506 	nt_time += unix_time->tv_usec * 10;
507 	return (nt_time + NT_TIME_BIAS);
508 }
509 
510 static boolean_t
511 smb_lm_password_ok(
512     unsigned char *challenge,
513     uint32_t clen,
514     unsigned char *lm_hash,
515     unsigned char *passwd)
516 {
517 	unsigned char lm_resp[SMBAUTH_LM_RESP_SZ];
518 	int rc;
519 
520 	rc = smb_auth_lm_response(lm_hash, challenge, clen, lm_resp);
521 	if (rc != SMBAUTH_SUCCESS)
522 		return (B_FALSE);
523 
524 	return (bcmp(lm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
525 }
526 
527 static boolean_t
528 smb_ntlm_password_ok(
529     unsigned char *challenge,
530     uint32_t clen,
531     unsigned char *ntlm_hash,
532     unsigned char *passwd)
533 {
534 	unsigned char ntlm_resp[SMBAUTH_LM_RESP_SZ];
535 	int rc;
536 
537 	rc = smb_auth_ntlm_response(ntlm_hash, challenge, clen, ntlm_resp);
538 
539 	if (rc != SMBAUTH_LM_RESP_SZ)
540 		return (B_FALSE);
541 
542 	return (bcmp(ntlm_resp, passwd, SMBAUTH_LM_RESP_SZ) == 0);
543 }
544 
545 static boolean_t
546 smb_ntlmv2_password_ok(
547     unsigned char *challenge,
548     uint32_t clen,
549     unsigned char *ntlm_hash,
550     unsigned char *passwd,
551     int pwdlen,
552     char *domain,
553     char *username)
554 {
555 	unsigned char *clnt_blob;
556 	int clnt_blob_len;
557 	unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
558 	unsigned char *ntlmv2_resp;
559 	boolean_t ok = B_FALSE;
560 	char *dest[3];
561 	int i;
562 
563 	clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
564 	clnt_blob = &passwd[SMBAUTH_HASH_SZ];
565 	dest[0] = domain;
566 	if ((dest[1] = strdup(domain)) == NULL)
567 		return (B_FALSE);
568 	(void) utf8_strupr(dest[1]);
569 	dest[2] = "";
570 
571 	/*
572 	 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
573 	 *
574 	 * The NTLMv2 Hash is created from:
575 	 * - NTLM hash
576 	 * - user's username, and
577 	 * - the name of the logon destination(i.e. the NetBIOS name of either
578 	 *   the SMB server or NT Domain against which the user is trying to
579 	 *   authenticate.
580 	 *
581 	 * Experiments show this is not exactly the case.
582 	 * For Windows Server 2003, the domain name needs to be included and
583 	 * converted to uppercase. For Vista, the domain name needs to be
584 	 * included also, but leave the case alone.  And in some cases it needs
585 	 * to be empty. All three variants are tried here.
586 	 */
587 
588 	ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
589 	if (ntlmv2_resp == NULL) {
590 		free(dest[1]);
591 		return (B_FALSE);
592 	}
593 
594 	for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
595 		if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
596 		    ntlmv2_hash) != SMBAUTH_SUCCESS)
597 			break;
598 
599 		if (smb_auth_v2_response(ntlmv2_hash, challenge,
600 		    clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
601 			break;
602 
603 		ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
604 		if (ok == B_TRUE)
605 			break;
606 
607 	}
608 
609 	free(dest[1]);
610 	free(ntlmv2_resp);
611 	return (ok);
612 }
613 
614 static boolean_t
615 smb_lmv2_password_ok(
616     unsigned char *challenge,
617     uint32_t clen,
618     unsigned char *ntlm_hash,
619     unsigned char *passwd,
620     char *domain,
621     char *username)
622 {
623 	unsigned char *clnt_challenge;
624 	unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
625 	unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
626 	boolean_t ok = B_FALSE;
627 	char *dest[3];
628 	int i;
629 
630 	clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
631 	dest[0] = domain;
632 	if ((dest[1] = strdup(domain)) == NULL)
633 		return (B_FALSE);
634 	(void) utf8_strupr(dest[1]);
635 	dest[2] = "";
636 
637 	/*
638 	 * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
639 	 *
640 	 * The NTLMv2 Hash is created from:
641 	 * - NTLM hash
642 	 * - user's username, and
643 	 * - the name of the logon destination(i.e. the NetBIOS name of either
644 	 *   the SMB server or NT Domain against which the suer is trying to
645 	 *   authenticate.
646 	 *
647 	 * Experiments show this is not exactly the case.
648 	 * For Windows Server 2003, the domain name needs to be included and
649 	 * converted to uppercase. For Vista, the domain name needs to be
650 	 * included also, but leave the case alone.  And in some cases it needs
651 	 * to be empty. All three variants are tried here.
652 	 */
653 
654 	for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
655 		if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
656 		    ntlmv2_hash) != SMBAUTH_SUCCESS)
657 			break;
658 
659 		if (smb_auth_v2_response(ntlmv2_hash, challenge,
660 		    clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
661 		    lmv2_resp) < 0)
662 			break;
663 
664 		ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
665 		if (ok == B_TRUE)
666 			break;
667 
668 	}
669 
670 	free(dest[1]);
671 	return (ok);
672 }
673 
674 /*
675  * smb_auth_validate_lm
676  *
677  * Validates given LM/LMv2 client response, passed in passwd arg, against
678  * stored user's password, passed in smbpw
679  *
680  * If LM level <=3 server accepts LM responses, otherwise LMv2
681  */
682 boolean_t
683 smb_auth_validate_lm(
684     unsigned char *challenge,
685     uint32_t clen,
686     smb_passwd_t *smbpw,
687     unsigned char *passwd,
688     int pwdlen,
689     char *domain,
690     char *username)
691 {
692 	boolean_t ok = B_FALSE;
693 	int64_t lmlevel;
694 
695 	if (pwdlen != SMBAUTH_LM_RESP_SZ)
696 		return (B_FALSE);
697 
698 	if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
699 		return (B_FALSE);
700 
701 	if (lmlevel <= 3) {
702 		ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash,
703 		    passwd);
704 	}
705 
706 	if (!ok)
707 		ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash,
708 		    passwd, domain, username);
709 
710 	return (ok);
711 }
712 
713 /*
714  * smb_auth_validate_nt
715  *
716  * Validates given NTLM/NTLMv2 client response, passed in passwd arg, against
717  * stored user's password, passed in smbpw
718  *
719  * If LM level <=4 server accepts NTLM/NTLMv2 responses, otherwise only NTLMv2
720  */
721 boolean_t
722 smb_auth_validate_nt(
723     unsigned char *challenge,
724     uint32_t clen,
725     smb_passwd_t *smbpw,
726     unsigned char *passwd,
727     int pwdlen,
728     char *domain,
729     char *username)
730 {
731 	int64_t lmlevel;
732 	boolean_t ok;
733 
734 	if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
735 		return (B_FALSE);
736 
737 	if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ))
738 		return (B_FALSE);
739 
740 	if (pwdlen > SMBAUTH_LM_RESP_SZ)
741 		ok = smb_ntlmv2_password_ok(challenge, clen,
742 		    smbpw->pw_nthash, passwd, pwdlen, domain, username);
743 	else
744 		ok = smb_ntlm_password_ok(challenge, clen,
745 		    smbpw->pw_nthash, passwd);
746 
747 	return (ok);
748 }
749