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