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 2020 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 return (SMBAUTH_FAILURE); 462 463 bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ); 464 465 mechanism.mechanism = CKM_MD5; 466 mechanism.pParameter = 0; 467 mechanism.ulParameterLen = 0; 468 469 rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 470 if (rv != CKR_OK) 471 return (SMBAUTH_FAILURE); 472 473 rv = C_DigestInit(hSession, &mechanism); 474 if (rv != CKR_OK) 475 goto cleanup; 476 477 rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf, 478 NETR_SESSKEY_ZEROBUF_SZ); 479 if (rv != CKR_OK) 480 goto cleanup; 481 482 rv = C_DigestUpdate(hSession, 483 (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ); 484 if (rv != CKR_OK) 485 goto cleanup; 486 487 rv = C_DigestUpdate(hSession, 488 (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ); 489 if (rv != CKR_OK) 490 goto cleanup; 491 492 rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen); 493 if (rv != CKR_OK) 494 goto cleanup; 495 496 rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ, 497 netr_info->session_key.key); 498 499 netr_info->session_key.len = NETR_SESSKEY128_SZ; 500 cleanup: 501 (void) C_CloseSession(hSession); 502 return (rc); 503 504 } 505 /* 506 * netr_gen_skey64 507 * 508 * Generate a 64-bit session key from the client and server challenges. 509 * See "Session-Key Computation" section of MS-NRPC document. 510 * 511 * The algorithm is a two stage hash. For the first hash, the input is 512 * the combination of the client and server challenges, the key is 513 * the first 7 bytes of the password. The initial password is formed 514 * using the NT password hash on the local hostname in lower case. 515 * The result is stored in a temporary buffer. 516 * 517 * input: challenge 518 * key: passwd lower 7 bytes 519 * output: intermediate result 520 * 521 * For the second hash, the input is the result of the first hash and 522 * the key is the last 7 bytes of the password. 523 * 524 * input: result of first hash 525 * key: passwd upper 7 bytes 526 * output: session_key 527 * 528 * The final output should be the session key. 529 * 530 * FYI: smb_auth_DES(output, key, input) 531 * 532 * If any difficulties occur using the cryptographic framework, the 533 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 534 * returned. 535 */ 536 int 537 netr_gen_skey64(netr_info_t *netr_info) 538 { 539 unsigned char md4hash[32]; 540 unsigned char buffer[8]; 541 DWORD data[2]; 542 DWORD *client_challenge; 543 DWORD *server_challenge; 544 int rc; 545 DWORD le_data[2]; 546 547 client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge; 548 server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge; 549 bzero(md4hash, 32); 550 551 /* 552 * We should check (netr_info->flags & NETR_FLG_INIT) and use 553 * the appropriate password but it isn't working yet. So we 554 * always use the default one for now. 555 */ 556 bzero(netr_info->password, sizeof (netr_info->password)); 557 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 558 (char *)netr_info->password, sizeof (netr_info->password)); 559 560 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 561 return (SMBAUTH_FAILURE); 562 } 563 564 rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash); 565 566 if (rc != SMBAUTH_SUCCESS) 567 return (SMBAUTH_FAILURE); 568 569 data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]); 570 data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]); 571 LE_OUT32(&le_data[0], data[0]); 572 LE_OUT32(&le_data[1], data[1]); 573 rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN, 574 (unsigned char *)le_data, 8); 575 576 if (rc != SMBAUTH_SUCCESS) 577 return (rc); 578 579 netr_info->session_key.len = NETR_SESSKEY64_SZ; 580 rc = smb_auth_DES(netr_info->session_key.key, 581 netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer, 582 8); 583 584 return (rc); 585 } 586 587 /* 588 * netr_gen_credentials 589 * 590 * Generate a set of credentials from a challenge and a session key. 591 * The algorithm is a two stage hash. For the first hash, the 592 * timestamp is added to the challenge and the result is stored in a 593 * temporary buffer: 594 * 595 * input: challenge (including timestamp) 596 * key: session_key 597 * output: intermediate result 598 * 599 * For the second hash, the input is the result of the first hash and 600 * a strange partial key is used: 601 * 602 * input: result of first hash 603 * key: funny partial key 604 * output: credentiails 605 * 606 * The final output should be an encrypted set of credentials. 607 * 608 * FYI: smb_auth_DES(output, key, input) 609 * 610 * If any difficulties occur using the cryptographic framework, the 611 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 612 * returned. 613 */ 614 int 615 netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge, 616 DWORD timestamp, netr_cred_t *out_cred, boolean_t retry) 617 { 618 unsigned char buffer[8]; 619 DWORD data[2]; 620 DWORD le_data[2]; 621 DWORD *p; 622 int rc; 623 624 p = (DWORD *)(uintptr_t)challenge; 625 data[0] = LE_IN32(&p[0]) + timestamp; 626 data[1] = LE_IN32(&p[1]); 627 628 LE_OUT32(&le_data[0], data[0]); 629 LE_OUT32(&le_data[1], data[1]); 630 631 if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN, 632 (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS) 633 return (SMBAUTH_FAILURE); 634 635 rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN], 636 NETR_DESKEY_LEN, buffer, 8); 637 638 /* 639 * [MS-NRPC] 3.1.4.6 "Calling Methods Requiring Session-Key 640 * Establishment" Step 6 641 * 642 * Windows DCs will reject authenticators if none of the first 643 * 5 bytes of the ClientStoredCredential are unique. 644 * Keep retrying until we've generated one that satisfies this, 645 * but only if the caller can handle retries. 646 */ 647 if (retry && !passes_dc_mitigation(out_cred->data)) 648 return (SMBAUTH_RETRY); 649 650 return (rc); 651 } 652 653 /* 654 * netr_server_password_set 655 * 656 * Attempt to change the trust account password for this system. 657 * 658 * Note that this call may legitimately fail if the registry on the 659 * domain controller has been setup to deny attempts to change the 660 * trust account password. In this case we should just continue to 661 * use the original password. 662 * 663 * Possible status values: 664 * NT_STATUS_ACCESS_DENIED 665 */ 666 int 667 netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 668 { 669 struct netr_PasswordSet arg; 670 int opnum; 671 BYTE new_password[NETR_OWF_PASSWORD_SZ]; 672 char account_name[NETBIOS_NAME_SZ * 2]; 673 674 bzero(&arg, sizeof (struct netr_PasswordSet)); 675 opnum = NETR_OPNUM_ServerPasswordSet; 676 677 (void) snprintf(account_name, sizeof (account_name), "%s$", 678 netr_info->hostname); 679 680 arg.servername = (unsigned char *)netr_info->server; 681 arg.account_name = (unsigned char *)account_name; 682 arg.sec_chan_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 683 arg.hostname = (unsigned char *)netr_info->hostname; 684 685 /* 686 * Set up the client side authenticator. 687 */ 688 if (netr_setup_authenticator(netr_info, &arg.auth, 0) != 689 SMBAUTH_SUCCESS) { 690 return (-1); 691 } 692 693 /* 694 * Generate a new password from the old password. 695 */ 696 if (netr_gen_password(netr_info->session_key.key, 697 netr_info->password, new_password) == SMBAUTH_FAILURE) { 698 return (-1); 699 } 700 701 (void) memcpy(&arg.owf_password, &new_password, 702 NETR_OWF_PASSWORD_SZ); 703 704 if (ndr_rpc_call(netr_handle, opnum, &arg) != 0) 705 return (-1); 706 707 if (arg.status != 0) { 708 ndr_rpc_status(netr_handle, opnum, arg.status); 709 ndr_rpc_release(netr_handle); 710 return (-1); 711 } 712 713 /* 714 * Check the returned credentials. The server returns the new 715 * client credential rather than the new server credentiali, 716 * as documented elsewhere. 717 * 718 * Generate the new seed for the credential chain. Increment 719 * the timestamp and add it to the client challenge. Then we 720 * need to copy the challenge to the credential field in 721 * preparation for the next cycle. 722 */ 723 if (netr_validate_chain(netr_info, &arg.auth) == 0) { 724 /* 725 * Save the new password. 726 */ 727 (void) memcpy(netr_info->password, new_password, 728 NETR_OWF_PASSWORD_SZ); 729 } 730 731 ndr_rpc_release(netr_handle); 732 return (0); 733 } 734 735 /* 736 * netr_gen_password 737 * 738 * Generate a new pasword from the old password and the session key. 739 * The algorithm is a two stage hash. The session key is used in the 740 * first hash but only part of the session key is used in the second 741 * hash. 742 * 743 * If any difficulties occur using the cryptographic framework, the 744 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 745 * returned. 746 */ 747 static int 748 netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password) 749 { 750 int rv; 751 752 rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN, 753 old_password, 8); 754 if (rv != SMBAUTH_SUCCESS) 755 return (rv); 756 757 rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN], 758 NETR_DESKEY_LEN, &old_password[8], 8); 759 return (rv); 760 } 761 762 /* 763 * Todo: need netr_server_password_set2() 764 * used by "unsecure join". (NX 11960) 765 */ 766