xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c (revision 7619:0ad244464731)
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 /*
275331Samw  * NETR challenge/response client functions.
285331Samw  *
295331Samw  * NT_STATUS_INVALID_PARAMETER
305331Samw  * NT_STATUS_NO_TRUST_SAM_ACCOUNT
315331Samw  * NT_STATUS_ACCESS_DENIED
325331Samw  */
335331Samw 
345331Samw #include <stdio.h>
355331Samw #include <stdlib.h>
365331Samw #include <strings.h>
375331Samw #include <unistd.h>
385331Samw #include <ctype.h>
397052Samw #include <security/cryptoki.h>
407052Samw #include <security/pkcs11.h>
415331Samw 
425331Samw #include <smbsrv/libsmb.h>
435521Sas200622 #include <smbsrv/libsmbrdr.h>
446432Sas200622 #include <smbsrv/libsmbns.h>
455331Samw #include <smbsrv/mlsvc_util.h>
465331Samw #include <smbsrv/ndl/netlogon.ndl>
475331Samw #include <smbsrv/ntstatus.h>
485331Samw #include <smbsrv/smbinfo.h>
495331Samw #include <smbsrv/mlsvc.h>
505331Samw #include <smbsrv/netrauth.h>
515331Samw 
527052Samw #define	NETR_SESSKEY_ZEROBUF_SZ		4
53*7619SJose.Borrego@Sun.COM /* The DES algorithm uses a 56-bit encryption key. */
547052Samw #define	NETR_DESKEY_LEN			7
557052Samw 
565331Samw int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
575331Samw     struct netr_authenticator *);
585331Samw DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
595331Samw 
605331Samw static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *);
615331Samw static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *);
625331Samw static int netr_gen_password(BYTE *, BYTE *, BYTE *);
635331Samw 
645331Samw /*
655331Samw  * Shared with netr_logon.c
665331Samw  */
675331Samw netr_info_t netr_global_info;
685331Samw 
695331Samw /*
705331Samw  * netlogon_auth
715331Samw  *
725331Samw  * This is the core of the NETLOGON authentication protocol.
735331Samw  * Do the challenge response authentication.
745331Samw  *
755331Samw  * Prior to calling this function, an anonymous session to the NETLOGON
765331Samw  * pipe on a domain controller(server) should have already been opened.
776139Sjb150015  *
786139Sjb150015  * Upon a successful NETLOGON credential chain establishment, the
796139Sjb150015  * netlogon sequence number will be set to match the kpasswd sequence
806139Sjb150015  * number.
816139Sjb150015  *
825331Samw  */
835331Samw DWORD
845331Samw netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags)
855331Samw {
865331Samw 	netr_info_t *netr_info;
875331Samw 	int rc;
885521Sas200622 	DWORD leout_rc[2];
895331Samw 
905331Samw 	netr_info = &netr_global_info;
915331Samw 	bzero(netr_info, sizeof (netr_info_t));
925331Samw 
935331Samw 	netr_info->flags |= flags;
945331Samw 
955331Samw 	rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX);
965331Samw 	if (rc != 0)
975331Samw 		return (NT_STATUS_UNSUCCESSFUL);
985331Samw 
995331Samw 	(void) snprintf(netr_info->server, sizeof (netr_info->server),
1005331Samw 	    "\\\\%s", server);
1015331Samw 
1025521Sas200622 	LE_OUT32(&leout_rc[0], random());
1035521Sas200622 	LE_OUT32(&leout_rc[1], random());
1045521Sas200622 	(void) memcpy(&netr_info->client_challenge, leout_rc,
1055331Samw 	    sizeof (struct netr_credential));
1065331Samw 
1075331Samw 	if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) {
1085331Samw 		rc = netr_server_authenticate2(netr_handle, netr_info);
1096139Sjb150015 		if (rc == 0) {
1106139Sjb150015 			smb_update_netlogon_seqnum();
1115331Samw 			netr_info->flags |= NETR_FLG_VALID;
1126139Sjb150015 
1136139Sjb150015 		}
1145331Samw 	}
1155331Samw 
1166432Sas200622 	/*
1176432Sas200622 	 * The NETLOGON credential chain establishment has unset
1186432Sas200622 	 * both ServerPrincipalName and dNSHostName attributes of the
1196432Sas200622 	 * workstation trust account. Those attributes will be updated
1206432Sas200622 	 * here to avoid any Kerberos authentication errors from happening.
1216432Sas200622 	 *
1226432Sas200622 	 * Later, when NT4 domain controller is supported, we need to
1236432Sas200622 	 * find a way to disable the following code.
1246432Sas200622 	 */
1257052Samw 	if (smb_ads_update_attrs() == -1)
1266432Sas200622 		syslog(LOG_DEBUG, "netlogon_auth: ServerPrincipalName"
1276432Sas200622 		    " and dNSHostName attributes might have been unset.");
1286432Sas200622 
1295331Samw 	return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
1305331Samw }
1315331Samw 
1325331Samw /*
1335331Samw  * netr_open
1345331Samw  *
1355331Samw  * Open an anonymous session to the NETLOGON pipe on a domain
1365331Samw  * controller and bind to the NETR RPC interface. We store the
1375331Samw  * remote server's native OS type - we may need it due to
1385331Samw  * differences between versions of Windows.
1395331Samw  */
1405331Samw int
1415331Samw netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
1425331Samw {
1435331Samw 	int fid;
1445331Samw 	int remote_os = 0;
1455331Samw 	int remote_lm = 0;
1465331Samw 	int server_pdc;
1475521Sas200622 	char *user = smbrdr_ipc_get_user();
1485331Samw 
1495521Sas200622 	if (mlsvc_logon(server, domain, user) != 0)
1505331Samw 		return (-1);
1515331Samw 
1525521Sas200622 	fid = mlsvc_open_pipe(server, domain, user, "\\NETLOGON");
1535331Samw 	if (fid < 0)
1545331Samw 		return (-1);
1555331Samw 
1565331Samw 	if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) {
1575331Samw 		(void) mlsvc_close_pipe(fid);
1585331Samw 		return (-1);
1595331Samw 	}
1605331Samw 
1615331Samw 	(void) mlsvc_session_native_values(fid, &remote_os, &remote_lm,
1625331Samw 	    &server_pdc);
1635331Samw 	netr_handle->context->server_os = remote_os;
1645331Samw 	netr_handle->context->server_pdc = server_pdc;
1655331Samw 	return (0);
1665331Samw }
1675331Samw 
1685331Samw /*
1695331Samw  * netr_close
1705331Samw  *
1715331Samw  * Close a NETLOGON pipe and free the RPC context.
1725331Samw  */
1735331Samw int
1745331Samw netr_close(mlsvc_handle_t *netr_handle)
1755331Samw {
1765331Samw 	(void) mlsvc_close_pipe(netr_handle->context->fid);
1775331Samw 	free(netr_handle->context);
1785331Samw 	return (0);
1795331Samw }
1805331Samw 
1815331Samw /*
1825331Samw  * netr_server_req_challenge
1835331Samw  */
1845331Samw static int
1855331Samw netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
1865331Samw {
1875331Samw 	struct netr_ServerReqChallenge arg;
1885331Samw 	mlrpc_heapref_t heap;
1895331Samw 	int opnum;
1905331Samw 	int rc;
1915331Samw 
1925331Samw 	bzero(&arg, sizeof (struct netr_ServerReqChallenge));
1935331Samw 	opnum = NETR_OPNUM_ServerReqChallenge;
1945331Samw 
1955331Samw 	arg.servername = (unsigned char *)netr_info->server;
1965331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
1975331Samw 
1985331Samw 	(void) memcpy(&arg.client_challenge, &netr_info->client_challenge,
1995331Samw 	    sizeof (struct netr_credential));
2005331Samw 
2015331Samw 	(void) mlsvc_rpc_init(&heap);
2025331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
2035331Samw 	if (rc == 0) {
2045331Samw 		if (arg.status != 0) {
2055331Samw 			mlsvc_rpc_report_status(opnum, arg.status);
2065331Samw 			rc = -1;
2075331Samw 		} else {
2085331Samw 			(void) memcpy(&netr_info->server_challenge,
2095331Samw 			    &arg.server_challenge,
2105331Samw 			    sizeof (struct netr_credential));
2115331Samw 		}
2125331Samw 	}
2135331Samw 
2145331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
2155331Samw 	return (rc);
2165331Samw }
2175331Samw 
2185331Samw /*
2195331Samw  * netr_server_authenticate2
2205331Samw  */
2215331Samw static int
2225331Samw netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
2235331Samw {
2245331Samw 	struct netr_ServerAuthenticate2 arg;
2255331Samw 	mlrpc_heapref_t heap;
2265331Samw 	int opnum;
2275331Samw 	int rc;
2285331Samw 	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
2295331Samw 
2305331Samw 	bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
2315331Samw 	opnum = NETR_OPNUM_ServerAuthenticate2;
2325331Samw 
2335331Samw 	(void) snprintf(account_name, sizeof (account_name), "%s$",
2345331Samw 	    netr_info->hostname);
2355331Samw 
236*7619SJose.Borrego@Sun.COM 	smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
237*7619SJose.Borrego@Sun.COM 	    netr_info->server, account_name, netr_info->hostname);
238*7619SJose.Borrego@Sun.COM 
2395331Samw 	arg.servername = (unsigned char *)netr_info->server;
2405331Samw 	arg.account_name = (unsigned char *)account_name;
2415331Samw 	arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
2425331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
243*7619SJose.Borrego@Sun.COM 	arg.negotiate_flags = NETR_NEGOTIATE_BASE_FLAGS;
2445331Samw 
245*7619SJose.Borrego@Sun.COM 	if (netr_handle->context->server_os != NATIVE_OS_WINNT) {
246*7619SJose.Borrego@Sun.COM 		arg.negotiate_flags |= NETR_NEGOTIATE_STRONGKEY_FLAG;
247*7619SJose.Borrego@Sun.COM 		if (netr_gen_skey128(netr_info) != SMBAUTH_SUCCESS)
248*7619SJose.Borrego@Sun.COM 			return (-1);
249*7619SJose.Borrego@Sun.COM 	} else {
250*7619SJose.Borrego@Sun.COM 		if (netr_gen_skey64(netr_info) != SMBAUTH_SUCCESS)
251*7619SJose.Borrego@Sun.COM 			return (-1);
252*7619SJose.Borrego@Sun.COM 	}
2535331Samw 
254*7619SJose.Borrego@Sun.COM 	if (netr_gen_credentials(netr_info->session_key.key,
255*7619SJose.Borrego@Sun.COM 	    &netr_info->client_challenge, 0,
2565331Samw 	    &netr_info->client_credential) != SMBAUTH_SUCCESS) {
2575331Samw 		return (-1);
2585331Samw 	}
2595331Samw 
260*7619SJose.Borrego@Sun.COM 	if (netr_gen_credentials(netr_info->session_key.key,
261*7619SJose.Borrego@Sun.COM 	    &netr_info->server_challenge, 0,
2625331Samw 	    &netr_info->server_credential) != SMBAUTH_SUCCESS) {
2635331Samw 		return (-1);
2645331Samw 	}
2655331Samw 
2665331Samw 	(void) memcpy(&arg.client_credential, &netr_info->client_credential,
2675331Samw 	    sizeof (struct netr_credential));
2685331Samw 
2695331Samw 	(void) mlsvc_rpc_init(&heap);
2705331Samw 
2715331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
2725331Samw 	if (rc == 0) {
2735331Samw 		if (arg.status != 0) {
2745331Samw 			mlsvc_rpc_report_status(opnum, arg.status);
2755331Samw 			rc = -1;
2765331Samw 		} else {
2775331Samw 			rc = memcmp(&netr_info->server_credential,
2785331Samw 			    &arg.server_credential,
2795331Samw 			    sizeof (struct netr_credential));
2805331Samw 		}
2815331Samw 	}
2825331Samw 
2835331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
2845331Samw 	return (rc);
2855331Samw }
2865331Samw 
2875331Samw /*
288*7619SJose.Borrego@Sun.COM  * netr_gen_skey128
2895331Samw  *
290*7619SJose.Borrego@Sun.COM  * Generate a 128-bit session key from the client and server challenges.
291*7619SJose.Borrego@Sun.COM  * See "Session-Key Computation" section of MS-NRPC document.
2925331Samw  */
2937052Samw int
294*7619SJose.Borrego@Sun.COM netr_gen_skey128(netr_info_t *netr_info)
2957052Samw {
2967052Samw 	unsigned char ntlmhash[SMBAUTH_HASH_SZ];
2977052Samw 	int rc = SMBAUTH_FAILURE;
2987052Samw 	CK_RV rv;
2997052Samw 	CK_MECHANISM mechanism;
3007052Samw 	CK_SESSION_HANDLE hSession;
3017052Samw 	CK_ULONG diglen = MD_DIGEST_LEN;
3027052Samw 	unsigned char md5digest[MD_DIGEST_LEN];
3037052Samw 	unsigned char zerobuf[NETR_SESSKEY_ZEROBUF_SZ];
3047052Samw 
3057052Samw 	bzero(ntlmhash, SMBAUTH_HASH_SZ);
3067052Samw 	/*
3077052Samw 	 * We should check (netr_info->flags & NETR_FLG_INIT) and use
3087052Samw 	 * the appropriate password but it isn't working yet.  So we
3097052Samw 	 * always use the default one for now.
3107052Samw 	 */
3117052Samw 	bzero(netr_info->password, sizeof (netr_info->password));
3127052Samw 	rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
3137052Samw 	    (char *)netr_info->password, sizeof (netr_info->password));
3147052Samw 
3157052Samw 	if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
3167052Samw 		return (SMBAUTH_FAILURE);
3177052Samw 	}
3187052Samw 
3197052Samw 	rc = smb_auth_ntlm_hash((char *)netr_info->password, ntlmhash);
3207052Samw 	if (rc != SMBAUTH_SUCCESS)
3217052Samw 		return (SMBAUTH_FAILURE);
3227052Samw 
3237052Samw 	bzero(zerobuf, NETR_SESSKEY_ZEROBUF_SZ);
3247052Samw 
3257052Samw 	mechanism.mechanism = CKM_MD5;
3267052Samw 	mechanism.pParameter = 0;
3277052Samw 	mechanism.ulParameterLen = 0;
3287052Samw 
3297052Samw 	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
3307052Samw 	if (rv != CKR_OK)
3317052Samw 		return (SMBAUTH_FAILURE);
3327052Samw 
3337052Samw 	rv = C_DigestInit(hSession, &mechanism);
3347052Samw 	if (rv != CKR_OK)
3357052Samw 		goto cleanup;
3367052Samw 
3377052Samw 	rv = C_DigestUpdate(hSession, (CK_BYTE_PTR)zerobuf,
3387052Samw 	    NETR_SESSKEY_ZEROBUF_SZ);
3397052Samw 	if (rv != CKR_OK)
3407052Samw 		goto cleanup;
3417052Samw 
3427052Samw 	rv = C_DigestUpdate(hSession,
3437052Samw 	    (CK_BYTE_PTR)netr_info->client_challenge.data, NETR_CRED_DATA_SZ);
3447052Samw 	if (rv != CKR_OK)
3457052Samw 		goto cleanup;
3467052Samw 
3477052Samw 	rv = C_DigestUpdate(hSession,
3487052Samw 	    (CK_BYTE_PTR)netr_info->server_challenge.data, NETR_CRED_DATA_SZ);
3497052Samw 	if (rv != CKR_OK)
3507052Samw 		goto cleanup;
3517052Samw 
3527052Samw 	rv = C_DigestFinal(hSession, (CK_BYTE_PTR)md5digest, &diglen);
3537052Samw 	if (rv != CKR_OK)
3547052Samw 		goto cleanup;
3557052Samw 
3567052Samw 	rc = smb_auth_hmac_md5(md5digest, diglen, ntlmhash, SMBAUTH_HASH_SZ,
357*7619SJose.Borrego@Sun.COM 	    netr_info->session_key.key);
3587052Samw 
359*7619SJose.Borrego@Sun.COM 	netr_info->session_key.len = NETR_SESSKEY128_SZ;
3607052Samw cleanup:
3617052Samw 	(void) C_CloseSession(hSession);
3627052Samw 	return (rc);
3637052Samw 
3647052Samw }
365*7619SJose.Borrego@Sun.COM /*
366*7619SJose.Borrego@Sun.COM  * netr_gen_skey64
367*7619SJose.Borrego@Sun.COM  *
368*7619SJose.Borrego@Sun.COM  * Generate a 64-bit session key from the client and server challenges.
369*7619SJose.Borrego@Sun.COM  * See "Session-Key Computation" section of MS-NRPC document.
370*7619SJose.Borrego@Sun.COM  *
371*7619SJose.Borrego@Sun.COM  * The algorithm is a two stage hash. For the first hash, the input is
372*7619SJose.Borrego@Sun.COM  * the combination of the client and server challenges, the key is
373*7619SJose.Borrego@Sun.COM  * the first 7 bytes of the password. The initial password is formed
374*7619SJose.Borrego@Sun.COM  * using the NT password hash on the local hostname in lower case.
375*7619SJose.Borrego@Sun.COM  * The result is stored in a temporary buffer.
376*7619SJose.Borrego@Sun.COM  *
377*7619SJose.Borrego@Sun.COM  *		input:	challenge
378*7619SJose.Borrego@Sun.COM  *		key:	passwd lower 7 bytes
379*7619SJose.Borrego@Sun.COM  *		output:	intermediate result
380*7619SJose.Borrego@Sun.COM  *
381*7619SJose.Borrego@Sun.COM  * For the second hash, the input is the result of the first hash and
382*7619SJose.Borrego@Sun.COM  * the key is the last 7 bytes of the password.
383*7619SJose.Borrego@Sun.COM  *
384*7619SJose.Borrego@Sun.COM  *		input:	result of first hash
385*7619SJose.Borrego@Sun.COM  *		key:	passwd upper 7 bytes
386*7619SJose.Borrego@Sun.COM  *		output:	session_key
387*7619SJose.Borrego@Sun.COM  *
388*7619SJose.Borrego@Sun.COM  * The final output should be the session key.
389*7619SJose.Borrego@Sun.COM  *
390*7619SJose.Borrego@Sun.COM  *		FYI: smb_auth_DES(output, key, input)
391*7619SJose.Borrego@Sun.COM  *
392*7619SJose.Borrego@Sun.COM  * If any difficulties occur using the cryptographic framework, the
393*7619SJose.Borrego@Sun.COM  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
394*7619SJose.Borrego@Sun.COM  * returned.
395*7619SJose.Borrego@Sun.COM  */
3965331Samw int
397*7619SJose.Borrego@Sun.COM netr_gen_skey64(netr_info_t *netr_info)
3985331Samw {
3995331Samw 	unsigned char md4hash[32];
4005331Samw 	unsigned char buffer[8];
4015331Samw 	DWORD data[2];
4025331Samw 	DWORD *client_challenge;
4035331Samw 	DWORD *server_challenge;
4045331Samw 	int rc;
4055521Sas200622 	DWORD le_data[2];
4065331Samw 
4075331Samw 	client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
4085331Samw 	server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
4095331Samw 	bzero(md4hash, 32);
4105331Samw 
4115331Samw 	/*
4125331Samw 	 * We should check (netr_info->flags & NETR_FLG_INIT) and use
4135331Samw 	 * the appropriate password but it isn't working yet.  So we
4145331Samw 	 * always use the default one for now.
4155331Samw 	 */
4165772Sas200622 	bzero(netr_info->password, sizeof (netr_info->password));
4175772Sas200622 	rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
4185772Sas200622 	    (char *)netr_info->password, sizeof (netr_info->password));
4195331Samw 
4205772Sas200622 	if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
4217052Samw 		return (SMBAUTH_FAILURE);
4225331Samw 	}
4235331Samw 
4245772Sas200622 	rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash);
4255331Samw 
4265331Samw 	if (rc != SMBAUTH_SUCCESS)
4275331Samw 		return (SMBAUTH_FAILURE);
4285331Samw 
4295331Samw 	data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
4305331Samw 	data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
4315521Sas200622 	LE_OUT32(&le_data[0], data[0]);
4325521Sas200622 	LE_OUT32(&le_data[1], data[1]);
433*7619SJose.Borrego@Sun.COM 	rc = smb_auth_DES(buffer, 8, md4hash, NETR_DESKEY_LEN,
434*7619SJose.Borrego@Sun.COM 	    (unsigned char *)le_data, 8);
4355331Samw 
4365331Samw 	if (rc != SMBAUTH_SUCCESS)
4375331Samw 		return (rc);
4385331Samw 
439*7619SJose.Borrego@Sun.COM 	netr_info->session_key.len = NETR_SESSKEY64_SZ;
440*7619SJose.Borrego@Sun.COM 	rc = smb_auth_DES(netr_info->session_key.key,
441*7619SJose.Borrego@Sun.COM 	    netr_info->session_key.len, &md4hash[9], NETR_DESKEY_LEN, buffer,
442*7619SJose.Borrego@Sun.COM 	    8);
443*7619SJose.Borrego@Sun.COM 
4445331Samw 	return (rc);
4455331Samw }
4465331Samw 
4475331Samw /*
4485331Samw  * netr_gen_credentials
4495331Samw  *
4505331Samw  * Generate a set of credentials from a challenge and a session key.
4515331Samw  * The algorithm is a two stage hash. For the first hash, the
4525331Samw  * timestamp is added to the challenge and the result is stored in a
4535331Samw  * temporary buffer:
4545331Samw  *
4555331Samw  *		input:	challenge (including timestamp)
4565331Samw  *		key:	session_key
4575331Samw  *		output:	intermediate result
4585331Samw  *
4595331Samw  * For the second hash, the input is the result of the first hash and
4605331Samw  * a strange partial key is used:
4615331Samw  *
4625331Samw  *		input:	result of first hash
4635331Samw  *		key:	funny partial key
4645331Samw  *		output:	credentiails
4655331Samw  *
4665331Samw  * The final output should be an encrypted set of credentials.
4675331Samw  *
4685331Samw  *		FYI: smb_auth_DES(output, key, input)
4695331Samw  *
4705331Samw  * If any difficulties occur using the cryptographic framework, the
4715331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
4725331Samw  * returned.
4735331Samw  */
4745331Samw int
4755331Samw netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
4765331Samw     DWORD timestamp, netr_cred_t *out_cred)
4775331Samw {
4785331Samw 	unsigned char buffer[8];
4795331Samw 	DWORD data[2];
4805521Sas200622 	DWORD le_data[2];
4815331Samw 	DWORD *p;
4825331Samw 	int rc;
4835331Samw 
4845331Samw 	p = (DWORD *)(uintptr_t)challenge;
4855521Sas200622 	data[0] = LE_IN32(&p[0]) + timestamp;
4865521Sas200622 	data[1] = LE_IN32(&p[1]);
4875521Sas200622 
4885521Sas200622 	LE_OUT32(&le_data[0], data[0]);
4895521Sas200622 	LE_OUT32(&le_data[1], data[1]);
4905331Samw 
4917052Samw 	if (smb_auth_DES(buffer, 8, session_key, NETR_DESKEY_LEN,
4925521Sas200622 	    (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS)
4935331Samw 		return (SMBAUTH_FAILURE);
4945331Samw 
4957052Samw 	rc = smb_auth_DES(out_cred->data, 8, &session_key[NETR_DESKEY_LEN],
4967052Samw 	    NETR_DESKEY_LEN, buffer, 8);
4975331Samw 
4985331Samw 	return (rc);
4995331Samw }
5005331Samw 
5015331Samw /*
5025331Samw  * netr_server_password_set
5035331Samw  *
5045331Samw  * Attempt to change the trust account password for this system.
5055331Samw  *
5065331Samw  * Note that this call may legitimately fail if the registry on the
5075331Samw  * domain controller has been setup to deny attempts to change the
5085331Samw  * trust account password. In this case we should just continue to
5095331Samw  * use the original password.
5105331Samw  *
5115331Samw  * Possible status values:
5125331Samw  *	NT_STATUS_ACCESS_DENIED
5135331Samw  */
5145331Samw int
5155331Samw netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
5165331Samw {
5175331Samw 	struct netr_PasswordSet  arg;
5185331Samw 	mlrpc_heapref_t heap;
5195331Samw 	int opnum;
5205331Samw 	int rc;
5215331Samw 	BYTE new_password[NETR_OWF_PASSWORD_SZ];
5225331Samw 	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
5235331Samw 
5245331Samw 	bzero(&arg, sizeof (struct netr_PasswordSet));
5255331Samw 	opnum = NETR_OPNUM_ServerPasswordSet;
5265331Samw 
5275331Samw 	(void) snprintf(account_name, sizeof (account_name), "%s$",
5285331Samw 	    netr_info->hostname);
5295331Samw 
5305331Samw 	arg.servername = (unsigned char *)netr_info->server;
5315331Samw 	arg.account_name = (unsigned char *)account_name;
5325331Samw 	arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
5335331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
5345331Samw 
5355331Samw 	/*
5365331Samw 	 * Set up the client side authenticator.
5375331Samw 	 */
5385331Samw 	if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
5395331Samw 	    SMBAUTH_SUCCESS) {
5405331Samw 		return (-1);
5415331Samw 	}
5425331Samw 
5435331Samw 	/*
5445331Samw 	 * Generate a new password from the old password.
5455331Samw 	 */
546*7619SJose.Borrego@Sun.COM 	if (netr_gen_password(netr_info->session_key.key,
5475331Samw 	    netr_info->password, new_password) == SMBAUTH_FAILURE) {
5485331Samw 		return (-1);
5495331Samw 	}
5505331Samw 
5515331Samw 	(void) memcpy(&arg.uas_new_password, &new_password,
5525331Samw 	    NETR_OWF_PASSWORD_SZ);
5535331Samw 
5545331Samw 	(void) mlsvc_rpc_init(&heap);
5555331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
5565331Samw 	if ((rc != 0) || (arg.status != 0)) {
5575331Samw 		mlsvc_rpc_report_status(opnum, arg.status);
5585331Samw 		mlsvc_rpc_free(netr_handle->context, &heap);
5595331Samw 		return (-1);
5605331Samw 	}
5615331Samw 
5625331Samw 	/*
5635331Samw 	 * Check the returned credentials.  The server returns the new
5645331Samw 	 * client credential rather than the new server credentiali,
5655331Samw 	 * as documented elsewhere.
5665331Samw 	 *
5675331Samw 	 * Generate the new seed for the credential chain.  Increment
5685331Samw 	 * the timestamp and add it to the client challenge.  Then we
5695331Samw 	 * need to copy the challenge to the credential field in
5705331Samw 	 * preparation for the next cycle.
5715331Samw 	 */
5725331Samw 	if (netr_validate_chain(netr_info, &arg.auth) == 0) {
5735331Samw 		/*
5745331Samw 		 * Save the new password.
5755331Samw 		 */
5765331Samw 		(void) memcpy(netr_info->password, new_password,
5775331Samw 		    NETR_OWF_PASSWORD_SZ);
5785331Samw 	}
5795331Samw 
5805331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
5815331Samw 	return (0);
5825331Samw }
5835331Samw 
5845331Samw /*
5855331Samw  * netr_gen_password
5865331Samw  *
5875331Samw  * Generate a new pasword from the old password  and the session key.
5885331Samw  * The algorithm is a two stage hash. The session key is used in the
5895331Samw  * first hash but only part of the session key is used in the second
5905331Samw  * hash.
5915331Samw  *
5925331Samw  * If any difficulties occur using the cryptographic framework, the
5935331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
5945331Samw  * returned.
5955331Samw  */
5965331Samw static int
5975331Samw netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
5985331Samw {
5995331Samw 	int rv;
6005331Samw 
6017052Samw 	rv = smb_auth_DES(new_password, 8, session_key, NETR_DESKEY_LEN,
6027052Samw 	    old_password, 8);
6035331Samw 	if (rv != SMBAUTH_SUCCESS)
6045331Samw 		return (rv);
6055331Samw 
6067052Samw 	rv = smb_auth_DES(&new_password[8], 8, &session_key[NETR_DESKEY_LEN],
6077052Samw 	    NETR_DESKEY_LEN, &old_password[8], 8);
6085331Samw 	return (rv);
6095331Samw }
610