xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c (revision 5331:3047ad28a67b)
1*5331Samw /*
2*5331Samw  * CDDL HEADER START
3*5331Samw  *
4*5331Samw  * The contents of this file are subject to the terms of the
5*5331Samw  * Common Development and Distribution License (the "License").
6*5331Samw  * You may not use this file except in compliance with the License.
7*5331Samw  *
8*5331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5331Samw  * or http://www.opensolaris.org/os/licensing.
10*5331Samw  * See the License for the specific language governing permissions
11*5331Samw  * and limitations under the License.
12*5331Samw  *
13*5331Samw  * When distributing Covered Code, include this CDDL HEADER in each
14*5331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5331Samw  * If applicable, add the following below this CDDL HEADER, with the
16*5331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
17*5331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5331Samw  *
19*5331Samw  * CDDL HEADER END
20*5331Samw  */
21*5331Samw /*
22*5331Samw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5331Samw  * Use is subject to license terms.
24*5331Samw  */
25*5331Samw 
26*5331Samw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5331Samw 
28*5331Samw /*
29*5331Samw  * NETR challenge/response client functions.
30*5331Samw  *
31*5331Samw  * NT_STATUS_INVALID_PARAMETER
32*5331Samw  * NT_STATUS_NO_TRUST_SAM_ACCOUNT
33*5331Samw  * NT_STATUS_ACCESS_DENIED
34*5331Samw  */
35*5331Samw 
36*5331Samw #include <stdio.h>
37*5331Samw #include <stdlib.h>
38*5331Samw #include <strings.h>
39*5331Samw #include <unistd.h>
40*5331Samw #include <ctype.h>
41*5331Samw 
42*5331Samw #include <smbsrv/libsmb.h>
43*5331Samw #include <smbsrv/mlsvc_util.h>
44*5331Samw #include <smbsrv/ndl/netlogon.ndl>
45*5331Samw #include <smbsrv/ntstatus.h>
46*5331Samw #include <smbsrv/smbinfo.h>
47*5331Samw #include <smbsrv/mlsvc.h>
48*5331Samw #include <smbsrv/netrauth.h>
49*5331Samw 
50*5331Samw int netr_setup_authenticator(netr_info_t *, struct netr_authenticator *,
51*5331Samw     struct netr_authenticator *);
52*5331Samw DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
53*5331Samw 
54*5331Samw static int netr_server_req_challenge(mlsvc_handle_t *, netr_info_t *);
55*5331Samw static int netr_server_authenticate2(mlsvc_handle_t *, netr_info_t *);
56*5331Samw static int netr_gen_password(BYTE *, BYTE *, BYTE *);
57*5331Samw 
58*5331Samw /*
59*5331Samw  * Shared with netr_logon.c
60*5331Samw  */
61*5331Samw netr_info_t netr_global_info;
62*5331Samw 
63*5331Samw /*
64*5331Samw  * netlogon_auth
65*5331Samw  *
66*5331Samw  * This is the core of the NETLOGON authentication protocol.
67*5331Samw  * Do the challenge response authentication.
68*5331Samw  *
69*5331Samw  * Prior to calling this function, an anonymous session to the NETLOGON
70*5331Samw  * pipe on a domain controller(server) should have already been opened.
71*5331Samw  */
72*5331Samw DWORD
73*5331Samw netlogon_auth(char *server, mlsvc_handle_t *netr_handle, DWORD flags)
74*5331Samw {
75*5331Samw 	netr_info_t *netr_info;
76*5331Samw 	int rc;
77*5331Samw 	DWORD random_challenge[2];
78*5331Samw 
79*5331Samw 	netr_info = &netr_global_info;
80*5331Samw 	bzero(netr_info, sizeof (netr_info_t));
81*5331Samw 
82*5331Samw 	netr_info->flags |= flags;
83*5331Samw 
84*5331Samw 	rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX);
85*5331Samw 	if (rc != 0)
86*5331Samw 		return (NT_STATUS_UNSUCCESSFUL);
87*5331Samw 
88*5331Samw 	(void) snprintf(netr_info->server, sizeof (netr_info->server),
89*5331Samw 	    "\\\\%s", server);
90*5331Samw 
91*5331Samw 	random_challenge[0] = random();
92*5331Samw 	random_challenge[1] = random();
93*5331Samw 
94*5331Samw 	(void) memcpy(&netr_info->client_challenge, random_challenge,
95*5331Samw 	    sizeof (struct netr_credential));
96*5331Samw 
97*5331Samw 	if ((rc = netr_server_req_challenge(netr_handle, netr_info)) == 0) {
98*5331Samw 		rc = netr_server_authenticate2(netr_handle, netr_info);
99*5331Samw 		if (rc == 0)
100*5331Samw 			netr_info->flags |= NETR_FLG_VALID;
101*5331Samw 	}
102*5331Samw 
103*5331Samw 	return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
104*5331Samw }
105*5331Samw 
106*5331Samw /*
107*5331Samw  * netr_open
108*5331Samw  *
109*5331Samw  * Open an anonymous session to the NETLOGON pipe on a domain
110*5331Samw  * controller and bind to the NETR RPC interface. We store the
111*5331Samw  * remote server's native OS type - we may need it due to
112*5331Samw  * differences between versions of Windows.
113*5331Samw  */
114*5331Samw int
115*5331Samw netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
116*5331Samw {
117*5331Samw 	int fid;
118*5331Samw 	int remote_os = 0;
119*5331Samw 	int remote_lm = 0;
120*5331Samw 	int server_pdc;
121*5331Samw 	char *username;
122*5331Samw 
123*5331Samw 	if (mlsvc_anonymous_logon(server, domain, &username) != 0)
124*5331Samw 		return (-1);
125*5331Samw 
126*5331Samw 	fid = mlsvc_open_pipe(server, domain, username, "\\NETLOGON");
127*5331Samw 	if (fid < 0)
128*5331Samw 		return (-1);
129*5331Samw 
130*5331Samw 	if (mlsvc_rpc_bind(netr_handle, fid, "NETR") < 0) {
131*5331Samw 		(void) mlsvc_close_pipe(fid);
132*5331Samw 		return (-1);
133*5331Samw 	}
134*5331Samw 
135*5331Samw 	(void) mlsvc_session_native_values(fid, &remote_os, &remote_lm,
136*5331Samw 	    &server_pdc);
137*5331Samw 	netr_handle->context->server_os = remote_os;
138*5331Samw 	netr_handle->context->server_pdc = server_pdc;
139*5331Samw 	return (0);
140*5331Samw }
141*5331Samw 
142*5331Samw /*
143*5331Samw  * netr_close
144*5331Samw  *
145*5331Samw  * Close a NETLOGON pipe and free the RPC context.
146*5331Samw  */
147*5331Samw int
148*5331Samw netr_close(mlsvc_handle_t *netr_handle)
149*5331Samw {
150*5331Samw 	(void) mlsvc_close_pipe(netr_handle->context->fid);
151*5331Samw 	free(netr_handle->context);
152*5331Samw 	return (0);
153*5331Samw }
154*5331Samw 
155*5331Samw /*
156*5331Samw  * netr_server_req_challenge
157*5331Samw  */
158*5331Samw static int
159*5331Samw netr_server_req_challenge(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
160*5331Samw {
161*5331Samw 	struct netr_ServerReqChallenge arg;
162*5331Samw 	mlrpc_heapref_t heap;
163*5331Samw 	int opnum;
164*5331Samw 	int rc;
165*5331Samw 
166*5331Samw 	bzero(&arg, sizeof (struct netr_ServerReqChallenge));
167*5331Samw 	opnum = NETR_OPNUM_ServerReqChallenge;
168*5331Samw 
169*5331Samw 	arg.servername = (unsigned char *)netr_info->server;
170*5331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
171*5331Samw 
172*5331Samw 	(void) memcpy(&arg.client_challenge, &netr_info->client_challenge,
173*5331Samw 	    sizeof (struct netr_credential));
174*5331Samw 
175*5331Samw 	(void) mlsvc_rpc_init(&heap);
176*5331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
177*5331Samw 	if (rc == 0) {
178*5331Samw 		if (arg.status != 0) {
179*5331Samw 			mlsvc_rpc_report_status(opnum, arg.status);
180*5331Samw 			rc = -1;
181*5331Samw 		} else {
182*5331Samw 			(void) memcpy(&netr_info->server_challenge,
183*5331Samw 			    &arg.server_challenge,
184*5331Samw 			    sizeof (struct netr_credential));
185*5331Samw 		}
186*5331Samw 	}
187*5331Samw 
188*5331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
189*5331Samw 	return (rc);
190*5331Samw }
191*5331Samw 
192*5331Samw /*
193*5331Samw  * netr_server_authenticate2
194*5331Samw  */
195*5331Samw static int
196*5331Samw netr_server_authenticate2(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
197*5331Samw {
198*5331Samw 	struct netr_ServerAuthenticate2 arg;
199*5331Samw 	mlrpc_heapref_t heap;
200*5331Samw 	int opnum;
201*5331Samw 	int rc;
202*5331Samw 	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
203*5331Samw 
204*5331Samw 	bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
205*5331Samw 	opnum = NETR_OPNUM_ServerAuthenticate2;
206*5331Samw 
207*5331Samw 	(void) snprintf(account_name, sizeof (account_name), "%s$",
208*5331Samw 	    netr_info->hostname);
209*5331Samw 
210*5331Samw 	arg.servername = (unsigned char *)netr_info->server;
211*5331Samw 	arg.account_name = (unsigned char *)account_name;
212*5331Samw 	arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
213*5331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
214*5331Samw 	arg.negotiate_flags = NETR_NEGOTIATE_FLAGS;
215*5331Samw 
216*5331Samw 	smb_tracef("server=[%s] account_name=[%s] hostname=[%s]\n",
217*5331Samw 	    netr_info->server, account_name, netr_info->hostname);
218*5331Samw 
219*5331Samw 	if (netr_gen_session_key(netr_info) != SMBAUTH_SUCCESS)
220*5331Samw 		return (-1);
221*5331Samw 
222*5331Samw 	if (netr_gen_credentials(netr_info->session_key,
223*5331Samw 	    &netr_info->client_challenge,
224*5331Samw 	    0,
225*5331Samw 	    &netr_info->client_credential) != SMBAUTH_SUCCESS) {
226*5331Samw 		return (-1);
227*5331Samw 	}
228*5331Samw 
229*5331Samw 	if (netr_gen_credentials(netr_info->session_key,
230*5331Samw 	    &netr_info->server_challenge,
231*5331Samw 	    0,
232*5331Samw 	    &netr_info->server_credential) != SMBAUTH_SUCCESS) {
233*5331Samw 		return (-1);
234*5331Samw 	}
235*5331Samw 
236*5331Samw 	(void) memcpy(&arg.client_credential, &netr_info->client_credential,
237*5331Samw 	    sizeof (struct netr_credential));
238*5331Samw 
239*5331Samw 	(void) mlsvc_rpc_init(&heap);
240*5331Samw 
241*5331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
242*5331Samw 	if (rc == 0) {
243*5331Samw 		if (arg.status != 0) {
244*5331Samw 			mlsvc_rpc_report_status(opnum, arg.status);
245*5331Samw 			rc = -1;
246*5331Samw 		} else {
247*5331Samw 			rc = memcmp(&netr_info->server_credential,
248*5331Samw 			    &arg.server_credential,
249*5331Samw 			    sizeof (struct netr_credential));
250*5331Samw 		}
251*5331Samw 	}
252*5331Samw 
253*5331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
254*5331Samw 	return (rc);
255*5331Samw }
256*5331Samw 
257*5331Samw /*
258*5331Samw  * netr_gen_session_key
259*5331Samw  *
260*5331Samw  * Generate a session key from the client and server challenges. The
261*5331Samw  * algorithm is a two stage hash. For the first hash, the input is
262*5331Samw  * the combination of the client and server challenges, the key is
263*5331Samw  * the first 8 bytes of the password. The initial password is formed
264*5331Samw  * using the NT password hash on the local hostname in lower case.
265*5331Samw  * The result is stored in a temporary buffer.
266*5331Samw  *
267*5331Samw  *		input:	challenge
268*5331Samw  *		key:	passwd lower 8 bytes
269*5331Samw  *		output:	intermediate result
270*5331Samw  *
271*5331Samw  * For the second hash, the input is the result of the first hash and
272*5331Samw  * the key is the last 8 bytes of the password.
273*5331Samw  *
274*5331Samw  *		input:	result of first hash
275*5331Samw  *		key:	passwd upper 8 bytes
276*5331Samw  *		output:	session_key
277*5331Samw  *
278*5331Samw  * The final output should be the session key.
279*5331Samw  *
280*5331Samw  *		FYI: smb_auth_DES(output, key, input)
281*5331Samw  *
282*5331Samw  * If any difficulties occur using the cryptographic framework, the
283*5331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
284*5331Samw  * returned.
285*5331Samw  */
286*5331Samw int
287*5331Samw netr_gen_session_key(netr_info_t *netr_info)
288*5331Samw {
289*5331Samw 	unsigned char md4hash[32];
290*5331Samw 	unsigned char buffer[8];
291*5331Samw 	DWORD data[2];
292*5331Samw 	DWORD *client_challenge;
293*5331Samw 	DWORD *server_challenge;
294*5331Samw 	int rc;
295*5331Samw 	char *machine_passwd;
296*5331Samw 	DWORD new_data[2];
297*5331Samw 
298*5331Samw 	client_challenge = (DWORD *)(uintptr_t)&netr_info->client_challenge;
299*5331Samw 	server_challenge = (DWORD *)(uintptr_t)&netr_info->server_challenge;
300*5331Samw 	bzero(md4hash, 32);
301*5331Samw 
302*5331Samw 	/*
303*5331Samw 	 * We should check (netr_info->flags & NETR_FLG_INIT) and use
304*5331Samw 	 * the appropriate password but it isn't working yet.  So we
305*5331Samw 	 * always use the default one for now.
306*5331Samw 	 */
307*5331Samw 	smb_config_rdlock();
308*5331Samw 	machine_passwd = smb_config_getstr(SMB_CI_MACHINE_PASSWD);
309*5331Samw 
310*5331Samw 	if (!machine_passwd || *machine_passwd == 0) {
311*5331Samw 		smb_config_unlock();
312*5331Samw 		return (-1);
313*5331Samw 	}
314*5331Samw 
315*5331Samw 	bzero(netr_info->password, sizeof (netr_info->password));
316*5331Samw 	(void) strlcpy((char *)netr_info->password, (char *)machine_passwd,
317*5331Samw 	    sizeof (netr_info->password));
318*5331Samw 
319*5331Samw 	rc = smb_auth_ntlm_hash((char *)machine_passwd, md4hash);
320*5331Samw 	smb_config_unlock();
321*5331Samw 
322*5331Samw 	if (rc != SMBAUTH_SUCCESS)
323*5331Samw 		return (SMBAUTH_FAILURE);
324*5331Samw 
325*5331Samw 	data[0] = LE_IN32(&client_challenge[0]) + LE_IN32(&server_challenge[0]);
326*5331Samw 	data[1] = LE_IN32(&client_challenge[1]) + LE_IN32(&server_challenge[1]);
327*5331Samw 	LE_OUT32(&new_data[0], data[0]);
328*5331Samw 	LE_OUT32(&new_data[1], data[1]);
329*5331Samw 
330*5331Samw 	rc = smb_auth_DES(buffer, 8, md4hash, 8, (unsigned char *)new_data, 8);
331*5331Samw 	if (rc != SMBAUTH_SUCCESS)
332*5331Samw 		return (rc);
333*5331Samw 
334*5331Samw 	rc = smb_auth_DES(netr_info->session_key, 8, &md4hash[9], 8, buffer, 8);
335*5331Samw 	return (rc);
336*5331Samw }
337*5331Samw 
338*5331Samw /*
339*5331Samw  * netr_gen_credentials
340*5331Samw  *
341*5331Samw  * Generate a set of credentials from a challenge and a session key.
342*5331Samw  * The algorithm is a two stage hash. For the first hash, the
343*5331Samw  * timestamp is added to the challenge and the result is stored in a
344*5331Samw  * temporary buffer:
345*5331Samw  *
346*5331Samw  *		input:	challenge (including timestamp)
347*5331Samw  *		key:	session_key
348*5331Samw  *		output:	intermediate result
349*5331Samw  *
350*5331Samw  * For the second hash, the input is the result of the first hash and
351*5331Samw  * a strange partial key is used:
352*5331Samw  *
353*5331Samw  *		input:	result of first hash
354*5331Samw  *		key:	funny partial key
355*5331Samw  *		output:	credentiails
356*5331Samw  *
357*5331Samw  * The final output should be an encrypted set of credentials.
358*5331Samw  *
359*5331Samw  *		FYI: smb_auth_DES(output, key, input)
360*5331Samw  *
361*5331Samw  * If any difficulties occur using the cryptographic framework, the
362*5331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
363*5331Samw  * returned.
364*5331Samw  */
365*5331Samw int
366*5331Samw netr_gen_credentials(BYTE *session_key, netr_cred_t *challenge,
367*5331Samw     DWORD timestamp, netr_cred_t *out_cred)
368*5331Samw {
369*5331Samw 	unsigned char buffer[8];
370*5331Samw 	unsigned char partial_key[8];
371*5331Samw 	DWORD data[2];
372*5331Samw 	DWORD *p;
373*5331Samw 	int rc;
374*5331Samw 
375*5331Samw 	p = (DWORD *)(uintptr_t)challenge;
376*5331Samw 	data[0] = p[0] + LE_IN32(&timestamp);
377*5331Samw 	data[1] = p[1];
378*5331Samw 
379*5331Samw 	if (smb_auth_DES(buffer, 8, session_key, 8,
380*5331Samw 	    (unsigned char *)data, 8) != SMBAUTH_SUCCESS)
381*5331Samw 		return (SMBAUTH_FAILURE);
382*5331Samw 
383*5331Samw 	bzero(partial_key, 8);
384*5331Samw 	partial_key[0] = session_key[7];
385*5331Samw 
386*5331Samw 	rc = smb_auth_DES((unsigned char *)out_cred, 8, partial_key, 8,
387*5331Samw 	    buffer, 8);
388*5331Samw 	return (rc);
389*5331Samw }
390*5331Samw 
391*5331Samw /*
392*5331Samw  * netr_server_password_set
393*5331Samw  *
394*5331Samw  * Attempt to change the trust account password for this system.
395*5331Samw  *
396*5331Samw  * Note that this call may legitimately fail if the registry on the
397*5331Samw  * domain controller has been setup to deny attempts to change the
398*5331Samw  * trust account password. In this case we should just continue to
399*5331Samw  * use the original password.
400*5331Samw  *
401*5331Samw  * Possible status values:
402*5331Samw  *	NT_STATUS_ACCESS_DENIED
403*5331Samw  */
404*5331Samw int
405*5331Samw netr_server_password_set(mlsvc_handle_t *netr_handle, netr_info_t *netr_info)
406*5331Samw {
407*5331Samw 	struct netr_PasswordSet  arg;
408*5331Samw 	mlrpc_heapref_t heap;
409*5331Samw 	int opnum;
410*5331Samw 	int rc;
411*5331Samw 	BYTE new_password[NETR_OWF_PASSWORD_SZ];
412*5331Samw 	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
413*5331Samw 
414*5331Samw 	bzero(&arg, sizeof (struct netr_PasswordSet));
415*5331Samw 	opnum = NETR_OPNUM_ServerPasswordSet;
416*5331Samw 
417*5331Samw 	(void) snprintf(account_name, sizeof (account_name), "%s$",
418*5331Samw 	    netr_info->hostname);
419*5331Samw 
420*5331Samw 	arg.servername = (unsigned char *)netr_info->server;
421*5331Samw 	arg.account_name = (unsigned char *)account_name;
422*5331Samw 	arg.account_type = NETR_WKSTA_TRUST_ACCOUNT_TYPE;
423*5331Samw 	arg.hostname = (unsigned char *)netr_info->hostname;
424*5331Samw 
425*5331Samw 	/*
426*5331Samw 	 * Set up the client side authenticator.
427*5331Samw 	 */
428*5331Samw 	if (netr_setup_authenticator(netr_info, &arg.auth, 0) !=
429*5331Samw 	    SMBAUTH_SUCCESS) {
430*5331Samw 		return (-1);
431*5331Samw 	}
432*5331Samw 
433*5331Samw 	/*
434*5331Samw 	 * Generate a new password from the old password.
435*5331Samw 	 */
436*5331Samw 	if (netr_gen_password(netr_info->session_key,
437*5331Samw 	    netr_info->password, new_password) == SMBAUTH_FAILURE) {
438*5331Samw 		return (-1);
439*5331Samw 	}
440*5331Samw 
441*5331Samw 	(void) memcpy(&arg.uas_new_password, &new_password,
442*5331Samw 	    NETR_OWF_PASSWORD_SZ);
443*5331Samw 
444*5331Samw 	(void) mlsvc_rpc_init(&heap);
445*5331Samw 	rc = mlsvc_rpc_call(netr_handle->context, opnum, &arg, &heap);
446*5331Samw 	if ((rc != 0) || (arg.status != 0)) {
447*5331Samw 		mlsvc_rpc_report_status(opnum, arg.status);
448*5331Samw 		mlsvc_rpc_free(netr_handle->context, &heap);
449*5331Samw 		return (-1);
450*5331Samw 	}
451*5331Samw 
452*5331Samw 	/*
453*5331Samw 	 * Check the returned credentials.  The server returns the new
454*5331Samw 	 * client credential rather than the new server credentiali,
455*5331Samw 	 * as documented elsewhere.
456*5331Samw 	 *
457*5331Samw 	 * Generate the new seed for the credential chain.  Increment
458*5331Samw 	 * the timestamp and add it to the client challenge.  Then we
459*5331Samw 	 * need to copy the challenge to the credential field in
460*5331Samw 	 * preparation for the next cycle.
461*5331Samw 	 */
462*5331Samw 	if (netr_validate_chain(netr_info, &arg.auth) == 0) {
463*5331Samw 		/*
464*5331Samw 		 * Save the new password.
465*5331Samw 		 */
466*5331Samw 		(void) memcpy(netr_info->password, new_password,
467*5331Samw 		    NETR_OWF_PASSWORD_SZ);
468*5331Samw 	}
469*5331Samw 
470*5331Samw 	mlsvc_rpc_free(netr_handle->context, &heap);
471*5331Samw 	return (0);
472*5331Samw }
473*5331Samw 
474*5331Samw /*
475*5331Samw  * netr_gen_password
476*5331Samw  *
477*5331Samw  * Generate a new pasword from the old password  and the session key.
478*5331Samw  * The algorithm is a two stage hash. The session key is used in the
479*5331Samw  * first hash but only part of the session key is used in the second
480*5331Samw  * hash.
481*5331Samw  *
482*5331Samw  * If any difficulties occur using the cryptographic framework, the
483*5331Samw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
484*5331Samw  * returned.
485*5331Samw  */
486*5331Samw static int
487*5331Samw netr_gen_password(BYTE *session_key, BYTE *old_password, BYTE *new_password)
488*5331Samw {
489*5331Samw 	unsigned char partial_key[8];
490*5331Samw 	int rv;
491*5331Samw 
492*5331Samw 	rv = smb_auth_DES(new_password, 8, session_key, 8, old_password, 8);
493*5331Samw 	if (rv != SMBAUTH_SUCCESS)
494*5331Samw 		return (rv);
495*5331Samw 
496*5331Samw 	bzero(partial_key, 8);
497*5331Samw 	partial_key[0] = session_key[7];
498*5331Samw 
499*5331Samw 	rv = smb_auth_DES(&new_password[8], 8, partial_key, 8,
500*5331Samw 	    &old_password[8], 8);
501*5331Samw 	return (rv);
502*5331Samw }
503