xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c (revision 6139:5c743b207bf9)
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>
415331Samw 
425331Samw #include <smbsrv/libsmb.h>
435521Sas200622 #include <smbsrv/libsmbrdr.h>
445331Samw #include <smbsrv/mlsvc_util.h>
455331Samw #include <smbsrv/ndl/netlogon.ndl>
465331Samw #include <smbsrv/ntstatus.h>
475331Samw #include <smbsrv/smbinfo.h>
485331Samw #include <smbsrv/mlsvc.h>
495331Samw #include <smbsrv/netrauth.h>
505331Samw 
515331Samw int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
525331Samw     struct netr_authenticator *);
535331Samw DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
545331Samw 
555331Samw static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *);
565331Samw static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *);
575331Samw static int netr_gen_password(BYTE *, BYTE *, BYTE *);
585331Samw 
595331Samw /*
605331Samw  * Shared with netr_logon.c
615331Samw  */
625331Samw netr_info_t netr_global_info;
635331Samw 
645331Samw /*
655331Samw  * netlogon_auth
665331Samw  *
675331Samw  * This is the core of the NETLOGON authentication protocol.
685331Samw  * Do the challenge response authentication.
695331Samw  *
705331Samw  * Prior to calling this function, an anonymous session to the NETLOGON
715331Samw  * pipe on a domain controller(server) should have already been opened.
72*6139Sjb150015  *
73*6139Sjb150015  * Upon a successful NETLOGON credential chain establishment, the
74*6139Sjb150015  * netlogon sequence number will be set to match the kpasswd sequence
75*6139Sjb150015  * number.
76*6139Sjb150015  *
775331Samw  */
785331Samw DWORD
795331Samw netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags)
805331Samw {
815331Samw 	netr_info_t *netr_info;
825331Samw 	int rc;
835521Sas200622 	DWORD leout_rc[2];
845331Samw 
855331Samw 	netr_info = &netr_global_info;
865331Samw 	bzero(netr_info, sizeof (netr_info_t));
875331Samw 
885331Samw 	netr_info->flags |= flags;
895331Samw 
905331Samw 	rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX);
915331Samw 	if (rc != 0)
925331Samw 		return (NT_STATUS_UNSUCCESSFUL);
935331Samw 
945331Samw 	(void) snprintf(netr_info->server, sizeof (netr_info->server),
955331Samw 	    "\\\\%s", server);
965331Samw 
975521Sas200622 	LE_OUT32(&leout_rc[0], random());
985521Sas200622 	LE_OUT32(&leout_rc[1], random());
995521Sas200622 	(void) memcpy(&netr_info->client_challenge, leout_rc,
1005331Samw 	    sizeof (struct netr_credential));
1015331Samw 
1025331Samw 	if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) {
1035331Samw 		rc = netr_server_authenticate2(netr_handle, netr_info);
104*6139Sjb150015 		if (rc == 0) {
105*6139Sjb150015 			smb_update_netlogon_seqnum();
1065331Samw 			netr_info->flags |= NETR_FLG_VALID;
107*6139Sjb150015 
108*6139Sjb150015 		}
1095331Samw 	}
1105331Samw 
1115331Samw 	return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
1125331Samw }
1135331Samw 
1145331Samw /*
1155331Samw  * netr_open
1165331Samw  *
1175331Samw  * Open an anonymous session to the NETLOGON pipe on a domain
1185331Samw  * controller and bind to the NETR RPC interface. We store the
1195331Samw  * remote server's native OS type - we may need it due to
1205331Samw  * differences between versions of Windows.
1215331Samw  */
1225331Samw int
1235331Samw netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
1245331Samw {
1255331Samw 	int fid;
1265331Samw 	int remote_os = 0;
1275331Samw 	int remote_lm = 0;
1285331Samw 	int server_pdc;
1295521Sas200622 	char *user = smbrdr_ipc_get_user();
1305331Samw 
1315521Sas200622 	if (mlsvc_logon(server, domain, user) != 0)
1325331Samw 		return (-1);
1335331Samw 
1345521Sas200622 	fid = mlsvc_open_pipe(server, domain, user, "\\NETLOGON");
1355331Samw 	if (fid < 0)
1365331Samw 		return (-1);
1375331Samw 
1385331Samw 	if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) {
1395331Samw 		(void) mlsvc_close_pipe(fid);
1405331Samw 		return (-1);
1415331Samw 	}
1425331Samw 
1435331Samw 	(void) mlsvc_session_native_values(fid, &remote_os, &remote_lm,
1445331Samw 	    &server_pdc);
1455331Samw 	netr_handle->context->server_os = remote_os;
1465331Samw 	netr_handle->context->server_pdc = server_pdc;
1475331Samw 	return (0);
1485331Samw }
1495331Samw 
1505331Samw /*
1515331Samw  * netr_close
1525331Samw  *
1535331Samw  * Close a NETLOGON pipe and free the RPC context.
1545331Samw  */
1555331Samw int
1565331Samw netr_close(mlsvc_handle_t *netr_handle)
1575331Samw {
1585331Samw 	(void) mlsvc_close_pipe(netr_handle->context->fid);
1595331Samw 	free(netr_handle->context);
1605331Samw 	return (0);
1615331Samw }
1625331Samw 
1635331Samw /*
1645331Samw  * netr_server_req_challenge
1655331Samw  */
1665331Samw static int
1675331Samw netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
1685331Samw {
1695331Samw 	struct netr_ServerReqChallenge arg;
1705331Samw 	mlrpc_heapref_t heap;
1715331Samw 	int opnum;
1725331Samw 	int rc;
1735331Samw 
1745331Samw 	bzero(&arg, sizeof (struct netr_ServerReqChallenge));
1755331Samw 	opnum = NETR_OPNUM_ServerReqChallenge;
1765331Samw 
1775331Samw 	arg.servername = (unsigned char *)netr_info->server;
1785331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
1795331Samw 
1805331Samw 	(void) memcpy(&arg.client_challenge, &netr_info->client_challenge,
1815331Samw 	    sizeof (struct netr_credential));
1825331Samw 
1835331Samw 	(void) mlsvc_rpc_init(&heap);
1845331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
1855331Samw 	if (rc == 0) {
1865331Samw 		if (arg.status != 0) {
1875331Samw 			mlsvc_rpc_report_status(opnum, arg.status);
1885331Samw 			rc = -1;
1895331Samw 		} else {
1905331Samw 			(void) memcpy(&netr_info->server_challenge,
1915331Samw 			    &arg.server_challenge,
1925331Samw 			    sizeof (struct netr_credential));
1935331Samw 		}
1945331Samw 	}
1955331Samw 
1965331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
1975331Samw 	return (rc);
1985331Samw }
1995331Samw 
2005331Samw /*
2015331Samw  * netr_server_authenticate2
2025331Samw  */
2035331Samw static int
2045331Samw netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
2055331Samw {
2065331Samw 	struct netr_ServerAuthenticate2 arg;
2075331Samw 	mlrpc_heapref_t heap;
2085331Samw 	int opnum;
2095331Samw 	int rc;
2105331Samw 	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
2115331Samw 
2125331Samw 	bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
2135331Samw 	opnum = NETR_OPNUM_ServerAuthenticate2;
2145331Samw 
2155331Samw 	(void) snprintf(account_name, sizeof (account_name), "%s$",
2165331Samw 	    netr_info->hostname);
2175331Samw 
2185331Samw 	arg.servername = (unsigned char *)netr_info->server;
2195331Samw 	arg.account_name = (unsigned char *)account_name;
2205331Samw 	arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
2215331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
2225331Samw 	arg.negotiate_flags = NETR_NEGOTIATE_FLAGS;
2235331Samw 
2245331Samw 	smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
2255331Samw 	    netr_info->server, account_name, netr_info->hostname);
2265331Samw 
2275331Samw 	if (netr_gen_session_key(netr_info) != SMBAUTH_SUCCESS)
2285331Samw 		return (-1);
2295331Samw 
2305331Samw 	if (netr_gen_credentials(netr_info->session_key,
2315331Samw 	    &netr_info->client_challenge,
2325331Samw 	    0,
2335331Samw 	    &netr_info->client_credential) != SMBAUTH_SUCCESS) {
2345331Samw 		return (-1);
2355331Samw 	}
2365331Samw 
2375331Samw 	if (netr_gen_credentials(netr_info->session_key,
2385331Samw 	    &netr_info->server_challenge,
2395331Samw 	    0,
2405331Samw 	    &netr_info->server_credential) != SMBAUTH_SUCCESS) {
2415331Samw 		return (-1);
2425331Samw 	}
2435331Samw 
2445331Samw 	(void) memcpy(&arg.client_credential, &netr_info->client_credential,
2455331Samw 	    sizeof (struct netr_credential));
2465331Samw 
2475331Samw 	(void) mlsvc_rpc_init(&heap);
2485331Samw 
2495331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
2505331Samw 	if (rc == 0) {
2515331Samw 		if (arg.status != 0) {
2525331Samw 			mlsvc_rpc_report_status(opnum, arg.status);
2535331Samw 			rc = -1;
2545331Samw 		} else {
2555331Samw 			rc = memcmp(&netr_info->server_credential,
2565331Samw 			    &arg.server_credential,
2575331Samw 			    sizeof (struct netr_credential));
2585331Samw 		}
2595331Samw 	}
2605331Samw 
2615331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
2625331Samw 	return (rc);
2635331Samw }
2645331Samw 
2655331Samw /*
2665331Samw  * netr_gen_session_key
2675331Samw  *
2685331Samw  * Generate a session key from the client and server challenges. The
2695331Samw  * algorithm is a two stage hash. For the first hash, the input is
2705331Samw  * the combination of the client and server challenges, the key is
2715331Samw  * the first 8 bytes of the password. The initial password is formed
2725331Samw  * using the NT password hash on the local hostname in lower case.
2735331Samw  * The result is stored in a temporary buffer.
2745331Samw  *
2755331Samw  *		input:	challenge
2765331Samw  *		key:	passwd lower 8 bytes
2775331Samw  *		output:	intermediate result
2785331Samw  *
2795331Samw  * For the second hash, the input is the result of the first hash and
2805331Samw  * the key is the last 8 bytes of the password.
2815331Samw  *
2825331Samw  *		input:	result of first hash
2835331Samw  *		key:	passwd upper 8 bytes
2845331Samw  *		output:	session_key
2855331Samw  *
2865331Samw  * The final output should be the session key.
2875331Samw  *
2885331Samw  *		FYI: smb_auth_DES(output, key, input)
2895331Samw  *
2905331Samw  * If any difficulties occur using the cryptographic framework, the
2915331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
2925331Samw  * returned.
2935331Samw  */
2945331Samw int
2955331Samw netr_gen_session_key(netr_info_t *netr_info)
2965331Samw {
2975331Samw 	unsigned char md4hash[32];
2985331Samw 	unsigned char buffer[8];
2995331Samw 	DWORD data[2];
3005331Samw 	DWORD *client_challenge;
3015331Samw 	DWORD *server_challenge;
3025331Samw 	int rc;
3035521Sas200622 	DWORD le_data[2];
3045331Samw 
3055331Samw 	client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
3065331Samw 	server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
3075331Samw 	bzero(md4hash, 32);
3085331Samw 
3095331Samw 	/*
3105331Samw 	 * We should check (netr_info->flags & NETR_FLG_INIT) and use
3115331Samw 	 * the appropriate password but it isn't working yet.  So we
3125331Samw 	 * always use the default one for now.
3135331Samw 	 */
3145772Sas200622 	bzero(netr_info->password, sizeof (netr_info->password));
3155772Sas200622 	rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD,
3165772Sas200622 	    (char *)netr_info->password, sizeof (netr_info->password));
3175331Samw 
3185772Sas200622 	if ((rc != SMBD_SMF_OK) || *netr_info->password == '\0') {
3195331Samw 		return (-1);
3205331Samw 	}
3215331Samw 
3225772Sas200622 	rc = smb_auth_ntlm_hash((char *)netr_info->password, md4hash);
3235331Samw 
3245331Samw 	if (rc != SMBAUTH_SUCCESS)
3255331Samw 		return (SMBAUTH_FAILURE);
3265331Samw 
3275331Samw 	data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
3285331Samw 	data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
3295521Sas200622 	LE_OUT32(&le_data[0], data[0]);
3305521Sas200622 	LE_OUT32(&le_data[1], data[1]);
3315331Samw 
3325521Sas200622 	rc = smb_auth_DES(buffer, 8, md4hash, 8, (unsigned char *)le_data, 8);
3335331Samw 	if (rc != SMBAUTH_SUCCESS)
3345331Samw 		return (rc);
3355331Samw 
3365331Samw 	rc = smb_auth_DES(netr_info->session_key, 8, &md4hash[9], 8, buffer, 8);
3375331Samw 	return (rc);
3385331Samw }
3395331Samw 
3405331Samw /*
3415331Samw  * netr_gen_credentials
3425331Samw  *
3435331Samw  * Generate a set of credentials from a challenge and a session key.
3445331Samw  * The algorithm is a two stage hash. For the first hash, the
3455331Samw  * timestamp is added to the challenge and the result is stored in a
3465331Samw  * temporary buffer:
3475331Samw  *
3485331Samw  *		input:	challenge (including timestamp)
3495331Samw  *		key:	session_key
3505331Samw  *		output:	intermediate result
3515331Samw  *
3525331Samw  * For the second hash, the input is the result of the first hash and
3535331Samw  * a strange partial key is used:
3545331Samw  *
3555331Samw  *		input:	result of first hash
3565331Samw  *		key:	funny partial key
3575331Samw  *		output:	credentiails
3585331Samw  *
3595331Samw  * The final output should be an encrypted set of credentials.
3605331Samw  *
3615331Samw  *		FYI: smb_auth_DES(output, key, input)
3625331Samw  *
3635331Samw  * If any difficulties occur using the cryptographic framework, the
3645331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
3655331Samw  * returned.
3665331Samw  */
3675331Samw int
3685331Samw netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
3695331Samw     DWORD timestamp, netr_cred_t *out_cred)
3705331Samw {
3715331Samw 	unsigned char buffer[8];
3725331Samw 	unsigned char partial_key[8];
3735331Samw 	DWORD data[2];
3745521Sas200622 	DWORD le_data[2];
3755331Samw 	DWORD *p;
3765331Samw 	int rc;
3775331Samw 
3785331Samw 	p = (DWORD *)(uintptr_t)challenge;
3795521Sas200622 	data[0] = LE_IN32(&p[0]) + timestamp;
3805521Sas200622 	data[1] = LE_IN32(&p[1]);
3815521Sas200622 
3825521Sas200622 	LE_OUT32(&le_data[0], data[0]);
3835521Sas200622 	LE_OUT32(&le_data[1], data[1]);
3845331Samw 
3855331Samw 	if (smb_auth_DES(buffer, 8, session_key, 8,
3865521Sas200622 	    (unsigned char *)le_data, 8) != SMBAUTH_SUCCESS)
3875331Samw 		return (SMBAUTH_FAILURE);
3885331Samw 
3895331Samw 	bzero(partial_key, 8);
3905331Samw 	partial_key[0] = session_key[7];
3915331Samw 
3925331Samw 	rc = smb_auth_DES((unsigned char *)out_cred, 8, partial_key, 8,
3935331Samw 	    buffer, 8);
3945331Samw 	return (rc);
3955331Samw }
3965331Samw 
3975331Samw /*
3985331Samw  * netr_server_password_set
3995331Samw  *
4005331Samw  * Attempt to change the trust account password for this system.
4015331Samw  *
4025331Samw  * Note that this call may legitimately fail if the registry on the
4035331Samw  * domain controller has been setup to deny attempts to change the
4045331Samw  * trust account password. In this case we should just continue to
4055331Samw  * use the original password.
4065331Samw  *
4075331Samw  * Possible status values:
4085331Samw  *	NT_STATUS_ACCESS_DENIED
4095331Samw  */
4105331Samw int
4115331Samw netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
4125331Samw {
4135331Samw 	struct netr_PasswordSet  arg;
4145331Samw 	mlrpc_heapref_t heap;
4155331Samw 	int opnum;
4165331Samw 	int rc;
4175331Samw 	BYTE new_password[NETR_OWF_PASSWORD_SZ];
4185331Samw 	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
4195331Samw 
4205331Samw 	bzero(&arg, sizeof (struct netr_PasswordSet));
4215331Samw 	opnum = NETR_OPNUM_ServerPasswordSet;
4225331Samw 
4235331Samw 	(void) snprintf(account_name, sizeof (account_name), "%s$",
4245331Samw 	    netr_info->hostname);
4255331Samw 
4265331Samw 	arg.servername = (unsigned char *)netr_info->server;
4275331Samw 	arg.account_name = (unsigned char *)account_name;
4285331Samw 	arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
4295331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
4305331Samw 
4315331Samw 	/*
4325331Samw 	 * Set up the client side authenticator.
4335331Samw 	 */
4345331Samw 	if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
4355331Samw 	    SMBAUTH_SUCCESS) {
4365331Samw 		return (-1);
4375331Samw 	}
4385331Samw 
4395331Samw 	/*
4405331Samw 	 * Generate a new password from the old password.
4415331Samw 	 */
4425331Samw 	if (netr_gen_password(netr_info->session_key,
4435331Samw 	    netr_info->password, new_password) == SMBAUTH_FAILURE) {
4445331Samw 		return (-1);
4455331Samw 	}
4465331Samw 
4475331Samw 	(void) memcpy(&arg.uas_new_password, &new_password,
4485331Samw 	    NETR_OWF_PASSWORD_SZ);
4495331Samw 
4505331Samw 	(void) mlsvc_rpc_init(&heap);
4515331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
4525331Samw 	if ((rc != 0) || (arg.status != 0)) {
4535331Samw 		mlsvc_rpc_report_status(opnum, arg.status);
4545331Samw 		mlsvc_rpc_free(netr_handle->context, &heap);
4555331Samw 		return (-1);
4565331Samw 	}
4575331Samw 
4585331Samw 	/*
4595331Samw 	 * Check the returned credentials.  The server returns the new
4605331Samw 	 * client credential rather than the new server credentiali,
4615331Samw 	 * as documented elsewhere.
4625331Samw 	 *
4635331Samw 	 * Generate the new seed for the credential chain.  Increment
4645331Samw 	 * the timestamp and add it to the client challenge.  Then we
4655331Samw 	 * need to copy the challenge to the credential field in
4665331Samw 	 * preparation for the next cycle.
4675331Samw 	 */
4685331Samw 	if (netr_validate_chain(netr_info, &arg.auth) == 0) {
4695331Samw 		/*
4705331Samw 		 * Save the new password.
4715331Samw 		 */
4725331Samw 		(void) memcpy(netr_info->password, new_password,
4735331Samw 		    NETR_OWF_PASSWORD_SZ);
4745331Samw 	}
4755331Samw 
4765331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
4775331Samw 	return (0);
4785331Samw }
4795331Samw 
4805331Samw /*
4815331Samw  * netr_gen_password
4825331Samw  *
4835331Samw  * Generate a new pasword from the old password  and the session key.
4845331Samw  * The algorithm is a two stage hash. The session key is used in the
4855331Samw  * first hash but only part of the session key is used in the second
4865331Samw  * hash.
4875331Samw  *
4885331Samw  * If any difficulties occur using the cryptographic framework, the
4895331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
4905331Samw  * returned.
4915331Samw  */
4925331Samw static int
4935331Samw netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
4945331Samw {
4955331Samw 	unsigned char partial_key[8];
4965331Samw 	int rv;
4975331Samw 
4985331Samw 	rv = smb_auth_DES(new_password, 8, session_key, 8, old_password, 8);
4995331Samw 	if (rv != SMBAUTH_SUCCESS)
5005331Samw 		return (rv);
5015331Samw 
5025331Samw 	bzero(partial_key, 8);
5035331Samw 	partial_key[0] = session_key[7];
5045331Samw 
5055331Samw 	rv = smb_auth_DES(&new_password[8], 8, partial_key, 8,
5065331Samw 	    &old_password[8], 8);
5075331Samw 	return (rv);
5085331Samw }
509