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 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2021 Tintri by DDN, Inc. All rights reserved. 25 * Copyright 2023 RackTop Systems, Inc. 26 */ 27 28 /* 29 * NETR challenge/response client functions. 30 * 31 * NT_STATUS_INVALID_PARAMETER 32 * NT_STATUS_NO_TRUST_SAM_ACCOUNT 33 * NT_STATUS_ACCESS_DENIED 34 */ 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <strings.h> 39 #include <unistd.h> 40 #include <ctype.h> 41 #include <security/cryptoki.h> 42 #include <security/pkcs11.h> 43 44 #include <smbsrv/libsmb.h> 45 #include <smbsrv/libsmbns.h> 46 #include <smbsrv/libmlsvc.h> 47 #include <mlsvc.h> 48 #include <smbsrv/ndl/netlogon.ndl> 49 #include <smbsrv/smbinfo.h> 50 #include <smbsrv/netrauth.h> 51 52 #define NETR_SESSKEY_ZEROBUF_SZ 4 53 /* The DES algorithm uses a 56-bit encryption key. */ 54 #define NETR_DESKEY_LEN 7 55 56 int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *, 57 struct netr_authenticator *); 58 DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *); 59 60 static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *); 61 static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *); 62 static int netr_gen_password(BYTE *, BYTE *, BYTE *); 63 64 /* 65 * Shared with netr_logon.c 66 */ 67 netr_info_t netr_global_info = { 68 .use_secure_rpc = B_TRUE, 69 .use_logon_ex = B_TRUE 70 }; 71 extern ndr_auth_ctx_t netr_ssp_ctx; 72 73 /* 74 * These flags control various parts of NetLogon RPC messages. 75 * The default is 0 - setting a bit disables some feature. 76 * They are set in smbd/netlogon_flags in svc:/network/smb/server. 77 * These are set when smbd starts. Changing them requires 78 * restarting smbd. 79 * 80 * These shouldn't be confused with either SamLogonEx's ExtraFlags, 81 * or NetrServerAuthenticate's negotiate_flags. 82 * 83 * DISABLE_SECURE_RPC causes Netlogon to use unauthenticated RPC. 84 * Note that the underlying transport is still authenticated and signed. 85 * 86 * DISABLE_RESP_VERIF instructs RPC authentication to ignore failures 87 * when verifying responses. 88 * 89 * DISABLE_SAMLOGONEX causes Netlogon to always use SamLogon, which 90 * makes use of Netlogon Authenticators. 91 * 92 * DISABLE_SEALING causes Netlogon to use Signing (integrity) instead of 93 * Sealing (privacy). 94 */ 95 #define NETR_CFG_DISABLE_SECURE_RPC 0x00000001 96 #define NETR_CFG_DISABLE_RESP_VERIF 0x00000002 97 #define NETR_CFG_DISABLE_SAMLOGONEX 0x00000004 98 #define NETR_CFG_DISABLE_SEALING 0x00000008 99 100 void 101 netlogon_init_global(uint32_t flags) 102 { 103 netr_global_info.use_secure_rpc = 104 ((flags & NETR_CFG_DISABLE_SECURE_RPC) == 0); 105 netr_ssp_ctx.auth_verify_resp = 106 ((flags & NETR_CFG_DISABLE_RESP_VERIF) == 0); 107 netr_global_info.use_logon_ex = 108 ((flags & NETR_CFG_DISABLE_SAMLOGONEX) == 0); 109 if ((flags & NETR_CFG_DISABLE_SEALING) != 0) 110 netr_ssp_ctx.auth_level = NDR_C_AUTHN_LEVEL_PKT_INTEGRITY; 111 } 112 113 /* 114 * AES-CFB8 has the odd property that 1/256 keys will encrypt 115 * a full block of 0s to all 0s. In order to mitigate this, Windows DCs 116 * now reject Challenges and Credentials where "none of the first 5 bytes 117 * are unique" (i.e. [MS-NRPC] 3.1.4.1 "Session-Key Negotiation" Step 7). 118 * This detects that condition so that we can avoid having our connection 119 * rejected unexpectedly. 120 * 121 * I've interpreted this condition as 'amongst the first 5 bytes, 122 * at least one must appear exactly once'. 123 * 124 * NOTE: Win2012r2 seems to only reject challenges whose first 5 bytes are 0. 125 */ 126 boolean_t 127 passes_dc_mitigation(uint8_t *buf) 128 { 129 int i, j; 130 131 for (i = 0; i < 5; i++) { 132 for (j = 0; j < 5; j++) { 133 if (i != j && buf[i] == buf[j]) 134 break; 135 } 136 137 /* if this byte didn't match any other byte, this passes */ 138 if (j == 5) 139 return (B_TRUE); 140 } 141 142 /* None of the bytes were unique - the check fails */ 143 return (B_FALSE); 144 } 145 146 /* 147 * netlogon_auth 148 * 149 * This is the core of the NETLOGON authentication protocol. 150 * Do the challenge response authentication. 151 * 152 * Prior to calling this function, an anonymous session to the NETLOGON 153 * pipe on a domain controller(server) should have already been opened. 154 * 155 * Upon a successful NETLOGON credential chain establishment, the 156 * netlogon sequence number will be set to match the kpasswd sequence 157 * number. 158 * 159 */ 160 DWORD 161 netlogon_auth(char *server, char *domain, DWORD flags) 162 { 163 mlsvc_handle_t netr_handle; 164 netr_info_t *netr_info; 165 int rc; 166 DWORD leout_rc[2]; 167 boolean_t retry; 168 DWORD status; 169 170 /* 171 * [MS-NRPC] 3.1.4.1 "Session-Key Negotiation" 172 * Negotiation happens on an 'unprotected RPC channel' 173 * (no RPC-level auth). 174 */ 175 status = netr_open(server, domain, &netr_handle); 176 177 if (status != 0) { 178 syslog(LOG_ERR, "netlogon_auth remote open failed (%s)", 179 xlate_nt_status(status)); 180 return (status); 181 } 182 183 netr_info = &netr_global_info; 184 bzero(&netr_info->session_key, sizeof (netr_info->session_key)); 185 bzero(&netr_info->rpc_seal_key, sizeof (netr_info->rpc_seal_key)); 186 netr_info->flags = flags; 187 188 rc = smb_getnetbiosname(netr_info->hostname, NETBIOS_NAME_SZ); 189 if (rc != 0) 190 goto errout; 191 192 /* server is our DC. Note: normally an FQDN. */ 193 (void) snprintf(netr_info->server, sizeof (netr_info->server), 194 "\\\\%s", server); 195 196 /* 197 * Domain (FQDN and NetBIOS) Name needed for Netlogon SSP-based 198 * Secure RPC. 199 */ 200 rc = smb_getdomainname(netr_info->nb_domain, 201 sizeof (netr_info->nb_domain)); 202 if (rc != 0) 203 goto errout; 204 205 rc = smb_getfqdomainname(netr_info->fqdn_domain, 206 sizeof (netr_info->fqdn_domain)); 207 if (rc != 0) 208 goto errout; 209 210 /* 211 * [MS-NRPC] 3.1.4.1 "Session-Key Negotiation" Step 7 212 * Windows DCs will reject negotiate attempts if none of the first 213 * 5 bytes of the Challenge are unique. 214 * Keep retrying until we've generated one that satisfies this. 215 */ 216 do { 217 retry = B_FALSE; 218 LE_OUT32(&leout_rc[0], arc4random()); 219 LE_OUT32(&leout_rc[1], arc4random()); 220 (void) memcpy(&netr_info->client_challenge, leout_rc, 221 sizeof (struct netr_credential)); 222 223 if (!passes_dc_mitigation(netr_info->client_challenge.data)) 224 retry = B_TRUE; 225 } while (retry); 226 227 if ((rc = netr_server_req_challenge(&netr_handle, netr_info)) == 0) { 228 rc = netr_server_authenticate2(&netr_handle, netr_info); 229 if (rc == 0) { 230 /* 231 * TODO: (later) When joining a domain using a 232 * pre-created machine account, should do: 233 * netr_server_password_set(&netr_handle, netr_info); 234 * Nexenta issue 11960 235 */ 236 smb_update_netlogon_seqnum(); 237 netr_info->flags |= NETR_FLG_VALID; 238 239 } 240 } 241 242 errout: 243 (void) netr_close(&netr_handle); 244 245 return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS); 246 } 247 248 /* 249 * netr_open 250 * 251 * Open an anonymous session to the NETLOGON pipe on a domain controller 252 * and bind to the NETR RPC interface. 253 * 254 * We store the remote server information, which is used to drive Windows 255 * version specific behavior. 256 * 257 * Returns 0 or NT status 258 */ 259 DWORD 260 netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle) 261 { 262 char user[SMB_USERNAME_MAXLEN]; 263 DWORD status; 264 265 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 266 267 status = ndr_rpc_bind(netr_handle, server, domain, user, "NETR"); 268 269 return (status); 270 } 271 272 uint32_t auth_context_id = 1; 273 274 DWORD 275 netr_open_secure(char *server, char *domain, mlsvc_handle_t *netr_handle) 276 { 277 char user[SMB_USERNAME_MAXLEN]; 278 DWORD status; 279 280 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN); 281 282 /* 283 * If the server doesn't support SECURE_RPC_FLAG, or we've disabled 284 * secure rpc (netr_global_info.use_secure_rpc), then SECURE_RPC_FLAG 285 * won't be in the set of negotiated flags. Don't use SecureRPC if 286 * that's the case. 287 */ 288 if ((netr_global_info.nego_flags & NETR_NEGO_SECURE_RPC_FLAG) != 0) { 289 netr_ssp_ctx.auth_context_id = auth_context_id++; 290 status = ndr_rpc_bind_secure(netr_handle, server, domain, user, 291 "NETR", &netr_ssp_ctx); 292 } else { 293 status = ndr_rpc_bind(netr_handle, server, domain, user, 294 "NETR"); 295 } 296 297 return (status); 298 } 299 300 /* 301 * netr_close 302 * 303 * Close a NETLOGON pipe and free the RPC context. 304 */ 305 int 306 netr_close(mlsvc_handle_t *netr_handle) 307 { 308 ndr_rpc_unbind(netr_handle); 309 return (0); 310 } 311 312 /* 313 * netr_server_req_challenge 314 */ 315 static int 316 netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 317 { 318 struct netr_ServerReqChallenge arg; 319 int opnum; 320 321 bzero(&arg, sizeof (struct netr_ServerReqChallenge)); 322 opnum = NETR_OPNUM_ServerReqChallenge; 323 324 arg.servername = (unsigned char *)netr_info->server; 325 arg.hostname = (unsigned char *)netr_info->hostname; 326 327 (void) memcpy(&arg.client_challenge, &netr_info->client_challenge, 328 sizeof (struct netr_credential)); 329 330 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 331 return (-1); 332 333 if (arg.status != 0) { 334 ndr_rpc_status(netr_handle, opnum, arg.status); 335 ndr_rpc_release(netr_handle); 336 return (-1); 337 } 338 339 (void) memcpy(&netr_info->server_challenge, &arg.server_challenge, 340 sizeof (struct netr_credential)); 341 342 ndr_rpc_release(netr_handle); 343 return (0); 344 } 345 346 uint32_t netr_server_auth2_flags = 347 NETR_NEGO_BASE_FLAGS | 348 NETR_NEGO_STRONGKEY_FLAG | 349 NETR_NEGO_SECURE_RPC_FLAG; 350 351 /* 352 * netr_server_authenticate2 353 */ 354 static int 355 netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 356 { 357 struct netr_ServerAuthenticate2 arg; 358 /* sizeof netr_info->hostname, + 1 for the '$' */ 359 char account_name[(NETBIOS_NAME_SZ * 2) + 1]; 360 int opnum; 361 int rc; 362 int i; 363 364 bzero(&arg, sizeof (struct netr_ServerAuthenticate2)); 365 opnum = NETR_OPNUM_ServerAuthenticate2; 366 367 (void) snprintf(account_name, sizeof (account_name), "%s$", 368 netr_info->hostname); 369 370 smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n", 371 netr_info->server, account_name, netr_info->hostname); 372 373 arg.servername = (unsigned char *)netr_info->server; 374 arg.account_name = (unsigned char *)account_name; 375 arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 376 arg.hostname = (unsigned char *)netr_info->hostname; 377 arg.negotiate_flags = netr_server_auth2_flags; 378 379 /* 380 * If we've disabled SecureRPC, remove it from our negotiate_flags 381 * so that the returned flags don't include it. We won't later use 382 * SecureRPC if the returned flags don't include the flag. 383 */ 384 if (!netr_global_info.use_secure_rpc) 385 arg.negotiate_flags &= ~NETR_NEGO_SECURE_RPC_FLAG; 386 387 if (arg.negotiate_flags & NETR_NEGO_STRONGKEY_FLAG) { 388 if (netr_gen_skey128(netr_info) != SMBAUTH_SUCCESS) 389 return (-1); 390 } else { 391 if (netr_gen_skey64(netr_info) != SMBAUTH_SUCCESS) 392 return (-1); 393 } 394 395 /* 396 * Calculate the 'XorKey' used to derive certain Netlogon SSP keys. 397 * This is used in [MS-NRPC] 3.3.4.2 "The Netlogon Signature Token". 398 */ 399 for (i = 0; i < netr_info->session_key.len; i++) 400 netr_info->rpc_seal_key.key[i] = 401 netr_info->session_key.key[i] ^ 0xf0; 402 netr_info->rpc_seal_key.len = netr_info->session_key.len; 403 404 /* 405 * We can't 'fiddle' with anything here to prevent getting bitten by 406 * ClientStoredCredential-based mitigations. 407 * 408 * If we're using SamLogonEx, we won't use authenticators unless 409 * some other NetLogon command is implemented and used. 410 */ 411 if (netr_gen_credentials(netr_info->session_key.key, 412 &netr_info->client_challenge, 0, 413 &netr_info->client_credential, B_FALSE) != SMBAUTH_SUCCESS) { 414 return (-1); 415 } 416 417 if (netr_gen_credentials(netr_info->session_key.key, 418 &netr_info->server_challenge, 0, 419 &netr_info->server_credential, B_FALSE) != SMBAUTH_SUCCESS) { 420 return (-1); 421 } 422 423 (void) memcpy(&arg.client_credential, &netr_info->client_credential, 424 sizeof (struct netr_credential)); 425 426 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 427 return (-1); 428 429 if (arg.status != 0) { 430 ndr_rpc_status(netr_handle, opnum, arg.status); 431 ndr_rpc_release(netr_handle); 432 return (-1); 433 } 434 435 /* The server returns the intersection of our flags and their flags. */ 436 netr_info->nego_flags = arg.negotiate_flags; 437 438 rc = memcmp(&netr_info->server_credential, &arg.server_credential, 439 sizeof (struct netr_credential)); 440 441 ndr_rpc_release(netr_handle); 442 return (rc); 443 } 444 445 /* 446 * netr_gen_skey128 447 * 448 * Generate a 128-bit session key from the client and server challenges. 449 * See "Session-Key Computation" section of MS-NRPC document. 450 */ 451 int 452 netr_gen_skey128(netr_info_t *netr_info) 453 { 454 unsigned char ntlmhash[SMBAUTH_HASH_SZ]; 455 int rc = SMBAUTH_FAILURE; 456 CK_RV rv; 457 CK_MECHANISM mechanism; 458 CK_SESSION_HANDLE hSession; 459 CK_ULONG diglen = MD_DIGEST_LEN; 460 unsigned char md5digest[MD_DIGEST_LEN]; 461 unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ]; 462 463 bzero(ntlmhash, SMBAUTH_HASH_SZ); 464 /* 465 * We should check (netr_info->flags & NETR_FLG_INIT) and use 466 * the appropriate password but it isn't working yet. So we 467 * always use the default one for now. 468 */ 469 bzero(netr_info->password, sizeof (netr_info->password)); 470 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 471 (char *)netr_info->password, sizeof (netr_info->password)); 472 473 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 474 return (SMBAUTH_FAILURE); 475 } 476 477 rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash); 478 if (rc != SMBAUTH_SUCCESS) { 479 explicit_bzero(&netr_info->password, 480 sizeof (netr_info->password)); 481 return (SMBAUTH_FAILURE); 482 } 483 484 bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ); 485 486 mechanism.mechanism = CKM_MD5; 487 mechanism.pParameter = 0; 488 mechanism.ulParameterLen = 0; 489 490 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 491 if (rv != CKR_OK) { 492 rc = SMBAUTH_FAILURE; 493 goto errout; 494 } 495 496 rv = C_DigestInit(hSession, &mechanism); 497 if (rv != CKR_OK) 498 goto cleanup; 499 500 rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf, 501 NETR_SESSKEY_ZEROBUF_SZ); 502 if (rv != CKR_OK) 503 goto cleanup; 504 505 rv = C_DigestUpdate(hSession, 506 (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ); 507 if (rv != CKR_OK) 508 goto cleanup; 509 510 rv = C_DigestUpdate(hSession, 511 (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ); 512 if (rv != CKR_OK) 513 goto cleanup; 514 515 rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen); 516 if (rv != CKR_OK) 517 goto cleanup; 518 519 rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ, 520 netr_info->session_key.key); 521 522 netr_info->session_key.len = NETR_SESSKEY128_SZ; 523 cleanup: 524 (void) C_CloseSession(hSession); 525 526 errout: 527 explicit_bzero(&netr_info->password, sizeof (netr_info->password)); 528 explicit_bzero(ntlmhash, sizeof (ntlmhash)); 529 530 return (rc); 531 532 } 533 /* 534 * netr_gen_skey64 535 * 536 * Generate a 64-bit session key from the client and server challenges. 537 * See "Session-Key Computation" section of MS-NRPC document. 538 * 539 * The algorithm is a two stage hash. For the first hash, the input is 540 * the combination of the client and server challenges, the key is 541 * the first 7 bytes of the password. The initial password is formed 542 * using the NT password hash on the local hostname in lower case. 543 * The result is stored in a temporary buffer. 544 * 545 * input: challenge 546 * key: passwd lower 7 bytes 547 * output: intermediate result 548 * 549 * For the second hash, the input is the result of the first hash and 550 * the key is the last 7 bytes of the password. 551 * 552 * input: result of first hash 553 * key: passwd upper 7 bytes 554 * output: session_key 555 * 556 * The final output should be the session key. 557 * 558 * FYI: smb_auth_DES(output, key, input) 559 * 560 * If any difficulties occur using the cryptographic framework, the 561 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 562 * returned. 563 */ 564 int 565 netr_gen_skey64(netr_info_t *netr_info) 566 { 567 unsigned char md4hash[32]; 568 unsigned char buffer[8]; 569 DWORD data[2]; 570 DWORD *client_challenge; 571 DWORD *server_challenge; 572 int rc; 573 DWORD le_data[2]; 574 575 client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge; 576 server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge; 577 bzero(md4hash, 32); 578 579 /* 580 * We should check (netr_info->flags & NETR_FLG_INIT) and use 581 * the appropriate password but it isn't working yet. So we 582 * always use the default one for now. 583 */ 584 bzero(netr_info->password, sizeof (netr_info->password)); 585 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 586 (char *)netr_info->password, sizeof (netr_info->password)); 587 588 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 589 return (SMBAUTH_FAILURE); 590 } 591 592 rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash); 593 594 if (rc != SMBAUTH_SUCCESS) { 595 rc = SMBAUTH_FAILURE; 596 goto out; 597 } 598 599 data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]); 600 data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]); 601 LE_OUT32(&le_data[0], data[0]); 602 LE_OUT32(&le_data[1], data[1]); 603 rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN, 604 (unsigned char *)le_data, 8); 605 606 if (rc != SMBAUTH_SUCCESS) 607 goto out; 608 609 netr_info->session_key.len = NETR_SESSKEY64_SZ; 610 rc = smb_auth_DES(netr_info->session_key.key, 611 netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer, 612 8); 613 614 out: 615 explicit_bzero(&netr_info->password, sizeof (netr_info->password)); 616 explicit_bzero(md4hash, sizeof (md4hash)); 617 explicit_bzero(buffer, sizeof (buffer)); 618 return (rc); 619 } 620 621 /* 622 * netr_gen_credentials 623 * 624 * Generate a set of credentials from a challenge and a session key. 625 * The algorithm is a two stage hash. For the first hash, the 626 * timestamp is added to the challenge and the result is stored in a 627 * temporary buffer: 628 * 629 * input: challenge (including timestamp) 630 * key: session_key 631 * output: intermediate result 632 * 633 * For the second hash, the input is the result of the first hash and 634 * a strange partial key is used: 635 * 636 * input: result of first hash 637 * key: funny partial key 638 * output: credentiails 639 * 640 * The final output should be an encrypted set of credentials. 641 * 642 * FYI: smb_auth_DES(output, key, input) 643 * 644 * If any difficulties occur using the cryptographic framework, the 645 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 646 * returned. 647 */ 648 int 649 netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge, 650 DWORD timestamp, netr_cred_t *out_cred, boolean_t retry) 651 { 652 unsigned char buffer[8]; 653 DWORD data[2]; 654 DWORD le_data[2]; 655 DWORD *p; 656 int rc; 657 658 p = (DWORD *)(uintptr_t)challenge; 659 data[0] = LE_IN32(&p[0]) + timestamp; 660 data[1] = LE_IN32(&p[1]); 661 662 LE_OUT32(&le_data[0], data[0]); 663 LE_OUT32(&le_data[1], data[1]); 664 665 if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN, 666 (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS) 667 return (SMBAUTH_FAILURE); 668 669 rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN], 670 NETR_DESKEY_LEN, buffer, 8); 671 672 /* 673 * [MS-NRPC] 3.1.4.6 "Calling Methods Requiring Session-Key 674 * Establishment" Step 6 675 * 676 * Windows DCs will reject authenticators if none of the first 677 * 5 bytes of the ClientStoredCredential are unique. 678 * Keep retrying until we've generated one that satisfies this, 679 * but only if the caller can handle retries. 680 */ 681 if (retry && !passes_dc_mitigation(out_cred->data)) 682 return (SMBAUTH_RETRY); 683 684 return (rc); 685 } 686 687 /* 688 * netr_server_password_set 689 * 690 * Attempt to change the trust account password for this system. 691 * 692 * Note that this call may legitimately fail if the registry on the 693 * domain controller has been setup to deny attempts to change the 694 * trust account password. In this case we should just continue to 695 * use the original password. 696 * 697 * Possible status values: 698 * NT_STATUS_ACCESS_DENIED 699 */ 700 int 701 netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 702 { 703 struct netr_PasswordSet arg; 704 int opnum; 705 BYTE new_password[NETR_OWF_PASSWORD_SZ]; 706 char account_name[NETBIOS_NAME_SZ * 2]; 707 708 bzero(&arg, sizeof (struct netr_PasswordSet)); 709 opnum = NETR_OPNUM_ServerPasswordSet; 710 711 (void) snprintf(account_name, sizeof (account_name), "%s$", 712 netr_info->hostname); 713 714 arg.servername = (unsigned char *)netr_info->server; 715 arg.account_name = (unsigned char *)account_name; 716 arg.sec_chan_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 717 arg.hostname = (unsigned char *)netr_info->hostname; 718 719 /* 720 * Set up the client side authenticator. 721 */ 722 if (netr_setup_authenticator(netr_info, &arg.auth, 0) != 723 SMBAUTH_SUCCESS) { 724 return (-1); 725 } 726 727 /* 728 * Generate a new password from the old password. 729 */ 730 if (netr_gen_password(netr_info->session_key.key, 731 netr_info->password, new_password) == SMBAUTH_FAILURE) { 732 return (-1); 733 } 734 735 (void) memcpy(&arg.owf_password, &new_password, 736 NETR_OWF_PASSWORD_SZ); 737 738 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 739 return (-1); 740 741 if (arg.status != 0) { 742 ndr_rpc_status(netr_handle, opnum, arg.status); 743 ndr_rpc_release(netr_handle); 744 return (-1); 745 } 746 747 /* 748 * Check the returned credentials. The server returns the new 749 * client credential rather than the new server credentiali, 750 * as documented elsewhere. 751 * 752 * Generate the new seed for the credential chain. Increment 753 * the timestamp and add it to the client challenge. Then we 754 * need to copy the challenge to the credential field in 755 * preparation for the next cycle. 756 */ 757 if (netr_validate_chain(netr_info, &arg.auth) == 0) { 758 /* 759 * Save the new password. 760 */ 761 (void) memcpy(netr_info->password, new_password, 762 NETR_OWF_PASSWORD_SZ); 763 } 764 765 ndr_rpc_release(netr_handle); 766 return (0); 767 } 768 769 /* 770 * netr_gen_password 771 * 772 * Generate a new pasword from the old password and the session key. 773 * The algorithm is a two stage hash. The session key is used in the 774 * first hash but only part of the session key is used in the second 775 * hash. 776 * 777 * If any difficulties occur using the cryptographic framework, the 778 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 779 * returned. 780 */ 781 static int 782 netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password) 783 { 784 int rv; 785 786 rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN, 787 old_password, 8); 788 if (rv != SMBAUTH_SUCCESS) 789 return (rv); 790 791 rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN], 792 NETR_DESKEY_LEN, &old_password[8], 8); 793 return (rv); 794 } 795 796 /* 797 * Todo: need netr_server_password_set2() 798 * used by "unsecure join". (NX 11960) 799 */ 800