xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c (revision 7052:efa04b030974)
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