15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw /* 295331Samw * NETR challenge/response client functions. 305331Samw * 315331Samw * NT_STATUS_INVALID_PARAMETER 325331Samw * NT_STATUS_NO_TRUST_SAM_ACCOUNT 335331Samw * NT_STATUS_ACCESS_DENIED 345331Samw */ 355331Samw 365331Samw #include <stdio.h> 375331Samw #include <stdlib.h> 385331Samw #include <strings.h> 395331Samw #include <unistd.h> 405331Samw #include <ctype.h> 41*7052Samw #include <security/cryptoki.h> 42*7052Samw #include <security/pkcs11.h> 435331Samw 445331Samw #include <smbsrv/libsmb.h> 455521Sas200622 #include <smbsrv/libsmbrdr.h> 466432Sas200622 #include <smbsrv/libsmbns.h> 475331Samw #include <smbsrv/mlsvc_util.h> 485331Samw #include <smbsrv/ndl/netlogon.ndl> 495331Samw #include <smbsrv/ntstatus.h> 505331Samw #include <smbsrv/smbinfo.h> 515331Samw #include <smbsrv/mlsvc.h> 525331Samw #include <smbsrv/netrauth.h> 535331Samw 54*7052Samw #define NETR_SESSKEY_ZEROBUF_SZ 4 55*7052Samw #define NETR_DESKEY_LEN 7 56*7052Samw 575331Samw int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *, 585331Samw struct netr_authenticator *); 595331Samw DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *); 605331Samw 615331Samw static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *); 625331Samw static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *); 635331Samw static int netr_gen_password(BYTE *, BYTE *, BYTE *); 645331Samw 655331Samw /* 665331Samw * Shared with netr_logon.c 675331Samw */ 685331Samw netr_info_t netr_global_info; 695331Samw 705331Samw /* 715331Samw * netlogon_auth 725331Samw * 735331Samw * This is the core of the NETLOGON authentication protocol. 745331Samw * Do the challenge response authentication. 755331Samw * 765331Samw * Prior to calling this function, an anonymous session to the NETLOGON 775331Samw * pipe on a domain controller(server) should have already been opened. 786139Sjb150015 * 796139Sjb150015 * Upon a successful NETLOGON credential chain establishment, the 806139Sjb150015 * netlogon sequence number will be set to match the kpasswd sequence 816139Sjb150015 * number. 826139Sjb150015 * 835331Samw */ 845331Samw DWORD 855331Samw netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags) 865331Samw { 875331Samw netr_info_t *netr_info; 885331Samw int rc; 895521Sas200622 DWORD leout_rc[2]; 905331Samw 915331Samw netr_info = &netr_global_info; 925331Samw bzero(netr_info, sizeof (netr_info_t)); 935331Samw 945331Samw netr_info->flags |= flags; 955331Samw 965331Samw rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX); 975331Samw if (rc != 0) 985331Samw return (NT_STATUS_UNSUCCESSFUL); 995331Samw 1005331Samw (void) snprintf(netr_info->server, sizeof (netr_info->server), 1015331Samw "\\\\%s", server); 1025331Samw 1035521Sas200622 LE_OUT32(&leout_rc[0], random()); 1045521Sas200622 LE_OUT32(&leout_rc[1], random()); 1055521Sas200622 (void) memcpy(&netr_info->client_challenge, leout_rc, 1065331Samw sizeof (struct netr_credential)); 1075331Samw 1085331Samw if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) { 1095331Samw rc = netr_server_authenticate2(netr_handle, netr_info); 1106139Sjb150015 if (rc == 0) { 1116139Sjb150015 smb_update_netlogon_seqnum(); 1125331Samw netr_info->flags |= NETR_FLG_VALID; 1136139Sjb150015 1146139Sjb150015 } 1155331Samw } 1165331Samw 1176432Sas200622 /* 1186432Sas200622 * The NETLOGON credential chain establishment has unset 1196432Sas200622 * both ServerPrincipalName and dNSHostName attributes of the 1206432Sas200622 * workstation trust account. Those attributes will be updated 1216432Sas200622 * here to avoid any Kerberos authentication errors from happening. 1226432Sas200622 * 1236432Sas200622 * Later, when NT4 domain controller is supported, we need to 1246432Sas200622 * find a way to disable the following code. 1256432Sas200622 */ 126*7052Samw if (smb_ads_update_attrs() == -1) 1276432Sas200622 syslog(LOG_DEBUG, "netlogon_auth: ServerPrincipalName" 1286432Sas200622 " and dNSHostName attributes might have been unset."); 1296432Sas200622 1305331Samw return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS); 1315331Samw } 1325331Samw 1335331Samw /* 1345331Samw * netr_open 1355331Samw * 1365331Samw * Open an anonymous session to the NETLOGON pipe on a domain 1375331Samw * controller and bind to the NETR RPC interface. We store the 1385331Samw * remote server's native OS type - we may need it due to 1395331Samw * differences between versions of Windows. 1405331Samw */ 1415331Samw int 1425331Samw netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle) 1435331Samw { 1445331Samw int fid; 1455331Samw int remote_os = 0; 1465331Samw int remote_lm = 0; 1475331Samw int server_pdc; 1485521Sas200622 char *user = smbrdr_ipc_get_user(); 1495331Samw 1505521Sas200622 if (mlsvc_logon(server, domain, user) != 0) 1515331Samw return (-1); 1525331Samw 1535521Sas200622 fid = mlsvc_open_pipe(server, domain, user, "\\NETLOGON"); 1545331Samw if (fid < 0) 1555331Samw return (-1); 1565331Samw 1575331Samw if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) { 1585331Samw (void) mlsvc_close_pipe(fid); 1595331Samw return (-1); 1605331Samw } 1615331Samw 1625331Samw (void) mlsvc_session_native_values(fid, &remote_os, &remote_lm, 1635331Samw &server_pdc); 1645331Samw netr_handle->context->server_os = remote_os; 1655331Samw netr_handle->context->server_pdc = server_pdc; 1665331Samw return (0); 1675331Samw } 1685331Samw 1695331Samw /* 1705331Samw * netr_close 1715331Samw * 1725331Samw * Close a NETLOGON pipe and free the RPC context. 1735331Samw */ 1745331Samw int 1755331Samw netr_close(mlsvc_handle_t *netr_handle) 1765331Samw { 1775331Samw (void) mlsvc_close_pipe(netr_handle->context->fid); 1785331Samw free(netr_handle->context); 1795331Samw return (0); 1805331Samw } 1815331Samw 1825331Samw /* 1835331Samw * netr_server_req_challenge 1845331Samw */ 1855331Samw static int 1865331Samw netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 1875331Samw { 1885331Samw struct netr_ServerReqChallenge arg; 1895331Samw mlrpc_heapref_t heap; 1905331Samw int opnum; 1915331Samw int rc; 1925331Samw 1935331Samw bzero(&arg, sizeof (struct netr_ServerReqChallenge)); 1945331Samw opnum = NETR_OPNUM_ServerReqChallenge; 1955331Samw 1965331Samw arg.servername = (unsigned char *)netr_info->server; 1975331Samw arg.hostname = (unsigned char *)netr_info->hostname; 1985331Samw 1995331Samw (void) memcpy(&arg.client_challenge, &netr_info->client_challenge, 2005331Samw sizeof (struct netr_credential)); 2015331Samw 2025331Samw (void) mlsvc_rpc_init(&heap); 2035331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 2045331Samw if (rc == 0) { 2055331Samw if (arg.status != 0) { 2065331Samw mlsvc_rpc_report_status(opnum, arg.status); 2075331Samw rc = -1; 2085331Samw } else { 2095331Samw (void) memcpy(&netr_info->server_challenge, 2105331Samw &arg.server_challenge, 2115331Samw sizeof (struct netr_credential)); 2125331Samw } 2135331Samw } 2145331Samw 2155331Samw mlsvc_rpc_free(netr_handle->context, &heap); 2165331Samw return (rc); 2175331Samw } 2185331Samw 2195331Samw /* 2205331Samw * netr_server_authenticate2 2215331Samw */ 2225331Samw static int 2235331Samw netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 2245331Samw { 2255331Samw struct netr_ServerAuthenticate2 arg; 2265331Samw mlrpc_heapref_t heap; 2275331Samw int opnum; 2285331Samw int rc; 2295331Samw char account_name[MLSVC_DOMAIN_NAME_MAX * 2]; 2305331Samw 2315331Samw bzero(&arg, sizeof (struct netr_ServerAuthenticate2)); 2325331Samw opnum = NETR_OPNUM_ServerAuthenticate2; 2335331Samw 2345331Samw (void) snprintf(account_name, sizeof (account_name), "%s$", 2355331Samw netr_info->hostname); 2365331Samw 2375331Samw arg.servername = (unsigned char *)netr_info->server; 2385331Samw arg.account_name = (unsigned char *)account_name; 2395331Samw arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 2405331Samw arg.hostname = (unsigned char *)netr_info->hostname; 2415331Samw arg.negotiate_flags = NETR_NEGOTIATE_FLAGS; 2425331Samw 2435331Samw smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n", 2445331Samw netr_info->server, account_name, netr_info->hostname); 2455331Samw 2465331Samw if (netr_gen_session_key(netr_info) != SMBAUTH_SUCCESS) 2475331Samw return (-1); 2485331Samw 2495331Samw if (netr_gen_credentials(netr_info->session_key, 2505331Samw &netr_info->client_challenge, 2515331Samw 0, 2525331Samw &netr_info->client_credential) != SMBAUTH_SUCCESS) { 2535331Samw return (-1); 2545331Samw } 2555331Samw 2565331Samw if (netr_gen_credentials(netr_info->session_key, 2575331Samw &netr_info->server_challenge, 2585331Samw 0, 2595331Samw &netr_info->server_credential) != SMBAUTH_SUCCESS) { 2605331Samw return (-1); 2615331Samw } 2625331Samw 2635331Samw (void) memcpy(&arg.client_credential, &netr_info->client_credential, 2645331Samw sizeof (struct netr_credential)); 2655331Samw 2665331Samw (void) mlsvc_rpc_init(&heap); 2675331Samw 2685331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 2695331Samw if (rc == 0) { 2705331Samw if (arg.status != 0) { 2715331Samw mlsvc_rpc_report_status(opnum, arg.status); 2725331Samw rc = -1; 2735331Samw } else { 2745331Samw rc = memcmp(&netr_info->server_credential, 2755331Samw &arg.server_credential, 2765331Samw sizeof (struct netr_credential)); 2775331Samw } 2785331Samw } 2795331Samw 2805331Samw mlsvc_rpc_free(netr_handle->context, &heap); 2815331Samw return (rc); 2825331Samw } 2835331Samw 2845331Samw /* 2855331Samw * netr_gen_session_key 2865331Samw * 2875331Samw * Generate a session key from the client and server challenges. The 2885331Samw * algorithm is a two stage hash. For the first hash, the input is 2895331Samw * the combination of the client and server challenges, the key is 2905331Samw * the first 8 bytes of the password. The initial password is formed 2915331Samw * using the NT password hash on the local hostname in lower case. 2925331Samw * The result is stored in a temporary buffer. 2935331Samw * 2945331Samw * input: challenge 2955331Samw * key: passwd lower 8 bytes 2965331Samw * output: intermediate result 2975331Samw * 2985331Samw * For the second hash, the input is the result of the first hash and 2995331Samw * the key is the last 8 bytes of the password. 3005331Samw * 3015331Samw * input: result of first hash 3025331Samw * key: passwd upper 8 bytes 3035331Samw * output: session_key 3045331Samw * 3055331Samw * The final output should be the session key. 3065331Samw * 3075331Samw * FYI: smb_auth_DES(output, key, input) 3085331Samw * 3095331Samw * If any difficulties occur using the cryptographic framework, the 3105331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 3115331Samw * returned. 3125331Samw */ 313*7052Samw #ifdef NETR_NEGOTIATE_STRONG_KEY 314*7052Samw int 315*7052Samw netr_gen_session_key(netr_info_t *netr_info) 316*7052Samw { 317*7052Samw unsigned char ntlmhash[SMBAUTH_HASH_SZ]; 318*7052Samw int rc = SMBAUTH_FAILURE; 319*7052Samw CK_RV rv; 320*7052Samw CK_MECHANISM mechanism; 321*7052Samw CK_SESSION_HANDLE hSession; 322*7052Samw CK_ULONG diglen = MD_DIGEST_LEN; 323*7052Samw unsigned char md5digest[MD_DIGEST_LEN]; 324*7052Samw unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ]; 325*7052Samw 326*7052Samw bzero(ntlmhash, SMBAUTH_HASH_SZ); 327*7052Samw /* 328*7052Samw * We should check (netr_info->flags & NETR_FLG_INIT) and use 329*7052Samw * the appropriate password but it isn't working yet. So we 330*7052Samw * always use the default one for now. 331*7052Samw */ 332*7052Samw bzero(netr_info->password, sizeof (netr_info->password)); 333*7052Samw rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 334*7052Samw (char *)netr_info->password, sizeof (netr_info->password)); 335*7052Samw 336*7052Samw if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 337*7052Samw return (SMBAUTH_FAILURE); 338*7052Samw } 339*7052Samw 340*7052Samw rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash); 341*7052Samw if (rc != SMBAUTH_SUCCESS) 342*7052Samw return (SMBAUTH_FAILURE); 343*7052Samw 344*7052Samw bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ); 345*7052Samw 346*7052Samw mechanism.mechanism = CKM_MD5; 347*7052Samw mechanism.pParameter = 0; 348*7052Samw mechanism.ulParameterLen = 0; 349*7052Samw 350*7052Samw rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession); 351*7052Samw if (rv != CKR_OK) 352*7052Samw return (SMBAUTH_FAILURE); 353*7052Samw 354*7052Samw rv = C_DigestInit(hSession, &mechanism); 355*7052Samw if (rv != CKR_OK) 356*7052Samw goto cleanup; 357*7052Samw 358*7052Samw rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf, 359*7052Samw NETR_SESSKEY_ZEROBUF_SZ); 360*7052Samw if (rv != CKR_OK) 361*7052Samw goto cleanup; 362*7052Samw 363*7052Samw rv = C_DigestUpdate(hSession, 364*7052Samw (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ); 365*7052Samw if (rv != CKR_OK) 366*7052Samw goto cleanup; 367*7052Samw 368*7052Samw rv = C_DigestUpdate(hSession, 369*7052Samw (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ); 370*7052Samw if (rv != CKR_OK) 371*7052Samw goto cleanup; 372*7052Samw 373*7052Samw rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen); 374*7052Samw if (rv != CKR_OK) 375*7052Samw goto cleanup; 376*7052Samw 377*7052Samw rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ, 378*7052Samw netr_info->session_key); 379*7052Samw 380*7052Samw cleanup: 381*7052Samw (void) C_CloseSession(hSession); 382*7052Samw return (rc); 383*7052Samw 384*7052Samw } 385*7052Samw #else 3865331Samw int 3875331Samw netr_gen_session_key(netr_info_t *netr_info) 3885331Samw { 3895331Samw unsigned char md4hash[32]; 3905331Samw unsigned char buffer[8]; 3915331Samw DWORD data[2]; 3925331Samw DWORD *client_challenge; 3935331Samw DWORD *server_challenge; 3945331Samw int rc; 3955521Sas200622 DWORD le_data[2]; 3965331Samw 3975331Samw client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge; 3985331Samw server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge; 3995331Samw bzero(md4hash, 32); 4005331Samw 4015331Samw /* 4025331Samw * We should check (netr_info->flags & NETR_FLG_INIT) and use 4035331Samw * the appropriate password but it isn't working yet. So we 4045331Samw * always use the default one for now. 4055331Samw */ 4065772Sas200622 bzero(netr_info->password, sizeof (netr_info->password)); 4075772Sas200622 rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, 4085772Sas200622 (char *)netr_info->password, sizeof (netr_info->password)); 4095331Samw 4105772Sas200622 if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') { 411*7052Samw return (SMBAUTH_FAILURE); 4125331Samw } 4135331Samw 4145772Sas200622 rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash); 4155331Samw 4165331Samw if (rc != SMBAUTH_SUCCESS) 4175331Samw return (SMBAUTH_FAILURE); 4185331Samw 4195331Samw data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]); 4205331Samw data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]); 4215521Sas200622 LE_OUT32(&le_data[0], data[0]); 4225521Sas200622 LE_OUT32(&le_data[1], data[1]); 4235331Samw 4245521Sas200622 rc = smb_auth_DES(buffer, 8, md4hash, 8, (unsigned char *)le_data, 8); 4255331Samw if (rc != SMBAUTH_SUCCESS) 4265331Samw return (rc); 4275331Samw 4285331Samw rc = smb_auth_DES(netr_info->session_key, 8, &md4hash[9], 8, buffer, 8); 4295331Samw return (rc); 4305331Samw } 431*7052Samw #endif 4325331Samw 4335331Samw /* 4345331Samw * netr_gen_credentials 4355331Samw * 4365331Samw * Generate a set of credentials from a challenge and a session key. 4375331Samw * The algorithm is a two stage hash. For the first hash, the 4385331Samw * timestamp is added to the challenge and the result is stored in a 4395331Samw * temporary buffer: 4405331Samw * 4415331Samw * input: challenge (including timestamp) 4425331Samw * key: session_key 4435331Samw * output: intermediate result 4445331Samw * 4455331Samw * For the second hash, the input is the result of the first hash and 4465331Samw * a strange partial key is used: 4475331Samw * 4485331Samw * input: result of first hash 4495331Samw * key: funny partial key 4505331Samw * output: credentiails 4515331Samw * 4525331Samw * The final output should be an encrypted set of credentials. 4535331Samw * 4545331Samw * FYI: smb_auth_DES(output, key, input) 4555331Samw * 4565331Samw * If any difficulties occur using the cryptographic framework, the 4575331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 4585331Samw * returned. 4595331Samw */ 4605331Samw int 4615331Samw netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge, 4625331Samw DWORD timestamp, netr_cred_t *out_cred) 4635331Samw { 4645331Samw unsigned char buffer[8]; 4655331Samw DWORD data[2]; 4665521Sas200622 DWORD le_data[2]; 4675331Samw DWORD *p; 4685331Samw int rc; 4695331Samw 4705331Samw p = (DWORD *)(uintptr_t)challenge; 4715521Sas200622 data[0] = LE_IN32(&p[0]) + timestamp; 4725521Sas200622 data[1] = LE_IN32(&p[1]); 4735521Sas200622 4745521Sas200622 LE_OUT32(&le_data[0], data[0]); 4755521Sas200622 LE_OUT32(&le_data[1], data[1]); 4765331Samw 477*7052Samw if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN, 4785521Sas200622 (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS) 4795331Samw return (SMBAUTH_FAILURE); 4805331Samw 481*7052Samw rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN], 482*7052Samw NETR_DESKEY_LEN, buffer, 8); 4835331Samw 4845331Samw return (rc); 4855331Samw } 4865331Samw 4875331Samw /* 4885331Samw * netr_server_password_set 4895331Samw * 4905331Samw * Attempt to change the trust account password for this system. 4915331Samw * 4925331Samw * Note that this call may legitimately fail if the registry on the 4935331Samw * domain controller has been setup to deny attempts to change the 4945331Samw * trust account password. In this case we should just continue to 4955331Samw * use the original password. 4965331Samw * 4975331Samw * Possible status values: 4985331Samw * NT_STATUS_ACCESS_DENIED 4995331Samw */ 5005331Samw int 5015331Samw netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info) 5025331Samw { 5035331Samw struct netr_PasswordSet arg; 5045331Samw mlrpc_heapref_t heap; 5055331Samw int opnum; 5065331Samw int rc; 5075331Samw BYTE new_password[NETR_OWF_PASSWORD_SZ]; 5085331Samw char account_name[MLSVC_DOMAIN_NAME_MAX * 2]; 5095331Samw 5105331Samw bzero(&arg, sizeof (struct netr_PasswordSet)); 5115331Samw opnum = NETR_OPNUM_ServerPasswordSet; 5125331Samw 5135331Samw (void) snprintf(account_name, sizeof (account_name), "%s$", 5145331Samw netr_info->hostname); 5155331Samw 5165331Samw arg.servername = (unsigned char *)netr_info->server; 5175331Samw arg.account_name = (unsigned char *)account_name; 5185331Samw arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE; 5195331Samw arg.hostname = (unsigned char *)netr_info->hostname; 5205331Samw 5215331Samw /* 5225331Samw * Set up the client side authenticator. 5235331Samw */ 5245331Samw if (netr_setup_authenticator(netr_info, &arg.auth, 0) != 5255331Samw SMBAUTH_SUCCESS) { 5265331Samw return (-1); 5275331Samw } 5285331Samw 5295331Samw /* 5305331Samw * Generate a new password from the old password. 5315331Samw */ 5325331Samw if (netr_gen_password(netr_info->session_key, 5335331Samw netr_info->password, new_password) == SMBAUTH_FAILURE) { 5345331Samw return (-1); 5355331Samw } 5365331Samw 5375331Samw (void) memcpy(&arg.uas_new_password, &new_password, 5385331Samw NETR_OWF_PASSWORD_SZ); 5395331Samw 5405331Samw (void) mlsvc_rpc_init(&heap); 5415331Samw rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap); 5425331Samw if ((rc != 0) || (arg.status != 0)) { 5435331Samw mlsvc_rpc_report_status(opnum, arg.status); 5445331Samw mlsvc_rpc_free(netr_handle->context, &heap); 5455331Samw return (-1); 5465331Samw } 5475331Samw 5485331Samw /* 5495331Samw * Check the returned credentials. The server returns the new 5505331Samw * client credential rather than the new server credentiali, 5515331Samw * as documented elsewhere. 5525331Samw * 5535331Samw * Generate the new seed for the credential chain. Increment 5545331Samw * the timestamp and add it to the client challenge. Then we 5555331Samw * need to copy the challenge to the credential field in 5565331Samw * preparation for the next cycle. 5575331Samw */ 5585331Samw if (netr_validate_chain(netr_info, &arg.auth) == 0) { 5595331Samw /* 5605331Samw * Save the new password. 5615331Samw */ 5625331Samw (void) memcpy(netr_info->password, new_password, 5635331Samw NETR_OWF_PASSWORD_SZ); 5645331Samw } 5655331Samw 5665331Samw mlsvc_rpc_free(netr_handle->context, &heap); 5675331Samw return (0); 5685331Samw } 5695331Samw 5705331Samw /* 5715331Samw * netr_gen_password 5725331Samw * 5735331Samw * Generate a new pasword from the old password and the session key. 5745331Samw * The algorithm is a two stage hash. The session key is used in the 5755331Samw * first hash but only part of the session key is used in the second 5765331Samw * hash. 5775331Samw * 5785331Samw * If any difficulties occur using the cryptographic framework, the 5795331Samw * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is 5805331Samw * returned. 5815331Samw */ 5825331Samw static int 5835331Samw netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password) 5845331Samw { 5855331Samw int rv; 5865331Samw 587*7052Samw rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN, 588*7052Samw old_password, 8); 5895331Samw if (rv != SMBAUTH_SUCCESS) 5905331Samw return (rv); 5915331Samw 592*7052Samw rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN], 593*7052Samw NETR_DESKEY_LEN, &old_password[8], 8); 5945331Samw return (rv); 5955331Samw } 596