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 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 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 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 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 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 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 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 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 */ 2548c10a865Sas200622 int 255da6c28aaSamw smb_auth_ntlmv2_hash(unsigned char *ntlm_hash, 256da6c28aaSamw char *username, 257da6c28aaSamw char *ntdomain, 258da6c28aaSamw 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 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 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 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 376da6c28aaSamw smb_ntlmv2_password_ok( 377da6c28aaSamw unsigned char *challenge, 378da6c28aaSamw unsigned char *ntlm_hash, 379da6c28aaSamw unsigned char *passwd, 380da6c28aaSamw int pwdlen, 381dc20a302Sas200622 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; 389dc20a302Sas200622 boolean_t ok = B_FALSE; 390dc20a302Sas200622 char *dest[3]; 391dc20a302Sas200622 int i; 392c8ec8eeaSjose borrego int rc; 393da6c28aaSamw 394da6c28aaSamw clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ; 395da6c28aaSamw clnt_blob = &passwd[SMBAUTH_HASH_SZ]; 396dc20a302Sas200622 dest[0] = domain; 397dc20a302Sas200622 if ((dest[1] = strdup(domain)) == NULL) 398dc20a302Sas200622 return (B_FALSE); 399bbf6f00cSJordan Brown (void) smb_strupr(dest[1]); 400dc20a302Sas200622 dest[2] = ""; 401da6c28aaSamw 402da6c28aaSamw /* 403da6c28aaSamw * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS" 404da6c28aaSamw * 405dc20a302Sas200622 * 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 409dc20a302Sas200622 * the SMB server or NT Domain against which the user is trying to 410da6c28aaSamw * authenticate. 411da6c28aaSamw * 412dc20a302Sas200622 * Experiments show this is not exactly the case. 413dc20a302Sas200622 * For Windows Server 2003, the domain name needs to be included and 414dc20a302Sas200622 * converted to uppercase. For Vista, the domain name needs to be 415dc20a302Sas200622 * included also, but leave the case alone. And in some cases it needs 416dc20a302Sas200622 * to be empty. All three variants are tried here. 417da6c28aaSamw */ 418da6c28aaSamw 419da6c28aaSamw ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len); 420dc20a302Sas200622 if (ntlmv2_resp == NULL) { 421dc20a302Sas200622 free(dest[1]); 422da6c28aaSamw return (B_FALSE); 423da6c28aaSamw } 424da6c28aaSamw 425dc20a302Sas200622 for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) { 426dc20a302Sas200622 if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i], 427dc20a302Sas200622 ntlmv2_hash) != SMBAUTH_SUCCESS) 428dc20a302Sas200622 break; 429da6c28aaSamw 430dc20a302Sas200622 if (smb_auth_v2_response(ntlmv2_hash, challenge, 431*12b65585SGordon Ross clnt_blob, clnt_blob_len, ntlmv2_resp) < 0) 432dc20a302Sas200622 break; 433dc20a302Sas200622 434dc20a302Sas200622 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 } 442dc20a302Sas200622 break; 443c8ec8eeaSjose borrego } 444dc20a302Sas200622 } 445dc20a302Sas200622 446dc20a302Sas200622 free(dest[1]); 447da6c28aaSamw free(ntlmv2_resp); 448da6c28aaSamw return (ok); 449da6c28aaSamw } 450da6c28aaSamw 451dc20a302Sas200622 static boolean_t 452da6c28aaSamw smb_lmv2_password_ok( 453*12b65585SGordon Ross unsigned char *srv_challenge, 454da6c28aaSamw unsigned char *ntlm_hash, 455da6c28aaSamw unsigned char *passwd, 456dc20a302Sas200622 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]; 462dc20a302Sas200622 boolean_t ok = B_FALSE; 463dc20a302Sas200622 char *dest[3]; 464dc20a302Sas200622 int i; 465da6c28aaSamw 466da6c28aaSamw clnt_challenge = &passwd[SMBAUTH_HASH_SZ]; 467dc20a302Sas200622 dest[0] = domain; 468dc20a302Sas200622 if ((dest[1] = strdup(domain)) == NULL) 469dc20a302Sas200622 return (B_FALSE); 470bbf6f00cSJordan Brown (void) smb_strupr(dest[1]); 471dc20a302Sas200622 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 * 483dc20a302Sas200622 * Experiments show this is not exactly the case. 484dc20a302Sas200622 * For Windows Server 2003, the domain name needs to be included and 485dc20a302Sas200622 * converted to uppercase. For Vista, the domain name needs to be 486dc20a302Sas200622 * included also, but leave the case alone. And in some cases it needs 487dc20a302Sas200622 * to be empty. All three variants are tried here. 488da6c28aaSamw */ 489dc20a302Sas200622 490dc20a302Sas200622 for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) { 491dc20a302Sas200622 if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i], 492dc20a302Sas200622 ntlmv2_hash) != SMBAUTH_SUCCESS) 493dc20a302Sas200622 break; 494dc20a302Sas200622 495*12b65585SGordon Ross if (smb_auth_v2_response(ntlmv2_hash, srv_challenge, 496*12b65585SGordon Ross clnt_challenge, SMBAUTH_CHAL_SZ, 497dc20a302Sas200622 lmv2_resp) < 0) 498dc20a302Sas200622 break; 499dc20a302Sas200622 500dc20a302Sas200622 ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0); 501c8ec8eeaSjose borrego if (ok) 502dc20a302Sas200622 break; 503da6c28aaSamw } 504da6c28aaSamw 505dc20a302Sas200622 free(dest[1]); 506dc20a302Sas200622 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 518*12b65585SGordon Ross smb_auth_validate( 519da6c28aaSamw smb_passwd_t *smbpw, 520dc20a302Sas200622 char *domain, 521c8ec8eeaSjose borrego 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, 528c8ec8eeaSjose borrego uchar_t *session_key) 529da6c28aaSamw { 530dc20a302Sas200622 int64_t lmlevel; 531*12b65585SGordon Ross boolean_t ok = B_FALSE; 532da6c28aaSamw 533dc20a302Sas200622 if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK) 534dc20a302Sas200622 return (B_FALSE); 535da6c28aaSamw 536*12b65585SGordon Ross if (lmlevel > 5) 537da6c28aaSamw 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) 550da6c28aaSamw return (ok); 551da6c28aaSamw } 5521ed6b69aSGordon Ross 553*12b65585SGordon Ross if (lmlevel == 5) 554*12b65585SGordon Ross return (B_FALSE); 555*12b65585SGordon Ross 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) 567*12b65585SGordon Ross return (B_FALSE); 568*12b65585SGordon Ross 569*12b65585SGordon Ross 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); 587*12b65585SGordon Ross } 588*12b65585SGordon 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 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