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