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