1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21148c5f43SAlan Wright 
22da6c28aaSamw /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * This module provides the high level interface to the SAM RPC
29da6c28aaSamw  * functions.
30da6c28aaSamw  */
31da6c28aaSamw 
321ed6b69aSGordon Ross #include <sys/types.h>
331ed6b69aSGordon Ross #include <sys/isa_defs.h>
341ed6b69aSGordon Ross #include <sys/byteorder.h>
351ed6b69aSGordon Ross 
36da6c28aaSamw #include <alloca.h>
37da6c28aaSamw 
38da6c28aaSamw #include <smbsrv/libsmb.h>
39da6c28aaSamw #include <smbsrv/libmlsvc.h>
40adee6784SGordon Ross #include <smb/ntaccess.h>
418d7e4166Sjose borrego #include <lsalib.h>
428d7e4166Sjose borrego #include <samlib.h>
43da6c28aaSamw 
441ed6b69aSGordon Ross #ifdef _LITTLE_ENDIAN
451ed6b69aSGordon Ross /* little-endian values on little-endian */
461ed6b69aSGordon Ross #define	htolel(x)	((uint32_t)(x))
471ed6b69aSGordon Ross #define	letohl(x)	((uint32_t)(x))
481ed6b69aSGordon Ross #else	/* (BYTE_ORDER == LITTLE_ENDIAN) */
491ed6b69aSGordon Ross /* little-endian values on big-endian (swap) */
501ed6b69aSGordon Ross #define	letohl(x)	BSWAP_32(x)
511ed6b69aSGordon Ross #define	htolel(x)	BSWAP_32(x)
521ed6b69aSGordon Ross #endif	/* (BYTE_ORDER == LITTLE_ENDIAN) */
531ed6b69aSGordon Ross 
54da6c28aaSamw /*
55da6c28aaSamw  * Valid values for the OEM OWF password encryption.
56da6c28aaSamw  */
57da6c28aaSamw #define	SAM_KEYLEN		16
58da6c28aaSamw 
591ed6b69aSGordon Ross static void samr_fill_userpw(struct samr_user_password *, const char *);
601ed6b69aSGordon Ross static void samr_make_encrypted_password(
611ed6b69aSGordon Ross 	struct samr_encr_passwd *epw,
621ed6b69aSGordon Ross 	char *new_pw_clear,
631ed6b69aSGordon Ross 	uint8_t *crypt_key);
64da6c28aaSamw 
65da6c28aaSamw 
66da6c28aaSamw /*
671ed6b69aSGordon Ross  * Todo: Implement "unjoin" domain, which would use the
681ed6b69aSGordon Ross  * sam_remove_trust_account code below.
69da6c28aaSamw  */
70da6c28aaSamw 
71da6c28aaSamw /*
72da6c28aaSamw  * sam_remove_trust_account
73da6c28aaSamw  *
74da6c28aaSamw  * Attempt to remove the workstation trust account for this system.
75da6c28aaSamw  * Administrator access is required to perform this operation.
76da6c28aaSamw  *
77da6c28aaSamw  * Returns NT status codes.
78da6c28aaSamw  */
79da6c28aaSamw DWORD
sam_remove_trust_account(char * server,char * domain)80da6c28aaSamw sam_remove_trust_account(char *server, char *domain)
81da6c28aaSamw {
82b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char account_name[SMB_SAMACCT_MAXLEN];
83da6c28aaSamw 
84b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
85b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NT_STATUS_INTERNAL_ERROR);
86da6c28aaSamw 
87da6c28aaSamw 	return (sam_delete_account(server, domain, account_name));
88da6c28aaSamw }
89da6c28aaSamw 
90da6c28aaSamw 
91da6c28aaSamw /*
92da6c28aaSamw  * sam_delete_account
93da6c28aaSamw  *
94da6c28aaSamw  * Attempt to remove an account from the SAM database on the specified
95da6c28aaSamw  * server.
96da6c28aaSamw  *
97da6c28aaSamw  * Returns NT status codes.
98da6c28aaSamw  */
99da6c28aaSamw DWORD
sam_delete_account(char * server,char * domain_name,char * account_name)100da6c28aaSamw sam_delete_account(char *server, char *domain_name, char *account_name)
101da6c28aaSamw {
102da6c28aaSamw 	mlsvc_handle_t samr_handle;
103da6c28aaSamw 	mlsvc_handle_t domain_handle;
104da6c28aaSamw 	mlsvc_handle_t user_handle;
1057f667e74Sjose borrego 	smb_account_t ainfo;
1061ed6b69aSGordon Ross 	smb_sid_t *sid;
107da6c28aaSamw 	DWORD access_mask;
108da6c28aaSamw 	DWORD status;
109da6c28aaSamw 	int rc;
110a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
111a0aa776eSAlan Wright 
112a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
113da6c28aaSamw 
11455bf511dSas200622 	rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
11555bf511dSas200622 	    &samr_handle);
1167f667e74Sjose borrego 	if (rc != 0)
1171ed6b69aSGordon Ross 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
1187f667e74Sjose borrego 
1191ed6b69aSGordon Ross 	sid = samr_lookup_domain(&samr_handle, domain_name);
1201ed6b69aSGordon Ross 	if (sid == NULL) {
1211ed6b69aSGordon Ross 		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1221ed6b69aSGordon Ross 		goto out_samr_hdl;
123da6c28aaSamw 	}
124da6c28aaSamw 
1251ed6b69aSGordon Ross 	status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
1261ed6b69aSGordon Ross 	    (struct samr_sid *)sid, &domain_handle);
1271ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
1281ed6b69aSGordon Ross 		goto out_sid_ptr;
1291ed6b69aSGordon Ross 
1307f667e74Sjose borrego 	status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
1311ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
1321ed6b69aSGordon Ross 		goto out_dom_hdl;
1331ed6b69aSGordon Ross 
134da6c28aaSamw 	access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
13555bf511dSas200622 	status = samr_open_user(&domain_handle, access_mask,
1367f667e74Sjose borrego 	    ainfo.a_rid, &user_handle);
1371ed6b69aSGordon Ross 	if (status != NT_STATUS_SUCCESS)
1381ed6b69aSGordon Ross 		goto out_dom_hdl;
1391ed6b69aSGordon Ross 
1401ed6b69aSGordon Ross 	status = samr_delete_user(&user_handle);
1411ed6b69aSGordon Ross 
142da6c28aaSamw 	(void) samr_close_handle(&user_handle);
1431ed6b69aSGordon Ross out_dom_hdl:
144da6c28aaSamw 	(void) samr_close_handle(&domain_handle);
1451ed6b69aSGordon Ross out_sid_ptr:
1467f667e74Sjose borrego 	free(sid);
1471ed6b69aSGordon Ross out_samr_hdl:
1487f667e74Sjose borrego 	(void) samr_close_handle(&samr_handle);
1491ed6b69aSGordon Ross 
1507f667e74Sjose borrego 	return (status);
1517f667e74Sjose borrego }
15255bf511dSas200622 
15355bf511dSas200622 
15455bf511dSas200622 /*
155da6c28aaSamw  * sam_lookup_name
156da6c28aaSamw  *
157da6c28aaSamw  * Lookup an account name in the SAM database on the specified domain
158da6c28aaSamw  * controller. Provides the account RID on success.
159da6c28aaSamw  *
160da6c28aaSamw  * Returns NT status codes.
161da6c28aaSamw  */
162da6c28aaSamw DWORD
sam_lookup_name(char * server,char * domain_name,char * account_name,DWORD * rid_ret)163da6c28aaSamw sam_lookup_name(char *server, char *domain_name, char *account_name,
164da6c28aaSamw     DWORD *rid_ret)
165da6c28aaSamw {
166da6c28aaSamw 	mlsvc_handle_t samr_handle;
167da6c28aaSamw 	mlsvc_handle_t domain_handle;
1687f667e74Sjose borrego 	smb_account_t ainfo;
169da6c28aaSamw 	struct samr_sid *domain_sid;
170da6c28aaSamw 	int rc;
171da6c28aaSamw 	DWORD status;
172a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
173a0aa776eSAlan Wright 
174a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
175da6c28aaSamw 
176da6c28aaSamw 	*rid_ret = 0;
177da6c28aaSamw 
17855bf511dSas200622 	rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
17955bf511dSas200622 	    &samr_handle);
180da6c28aaSamw 
1817f667e74Sjose borrego 	if (rc != 0)
182da6c28aaSamw 		return (NT_STATUS_OPEN_FAILED);
183da6c28aaSamw 
1847f667e74Sjose borrego 	domain_sid = (struct samr_sid *)samr_lookup_domain(&samr_handle,
1857f667e74Sjose borrego 	    domain_name);
1867f667e74Sjose borrego 	if (domain_sid == NULL) {
187da6c28aaSamw 		(void) samr_close_handle(&samr_handle);
188da6c28aaSamw 		return (NT_STATUS_NO_SUCH_DOMAIN);
189da6c28aaSamw 	}
190da6c28aaSamw 
191da6c28aaSamw 	status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
192da6c28aaSamw 	    domain_sid, &domain_handle);
1937f667e74Sjose borrego 	if (status == NT_STATUS_SUCCESS) {
194da6c28aaSamw 		status = samr_lookup_domain_names(&domain_handle,
1957f667e74Sjose borrego 		    account_name, &ainfo);
1967f667e74Sjose borrego 		if (status == NT_STATUS_SUCCESS)
1977f667e74Sjose borrego 			*rid_ret = ainfo.a_rid;
198da6c28aaSamw 
199da6c28aaSamw 		(void) samr_close_handle(&domain_handle);
200da6c28aaSamw 	}
201da6c28aaSamw 
202da6c28aaSamw 	(void) samr_close_handle(&samr_handle);
203da6c28aaSamw 	return (status);
204da6c28aaSamw }
205da6c28aaSamw 
206da6c28aaSamw /*
207da6c28aaSamw  * sam_get_local_domains
208da6c28aaSamw  *
209da6c28aaSamw  * Query a remote server to get the list of local domains that it
210da6c28aaSamw  * supports.
211da6c28aaSamw  *
212da6c28aaSamw  * Returns NT status codes.
213da6c28aaSamw  */
214da6c28aaSamw DWORD
sam_get_local_domains(char * server,char * domain_name)215da6c28aaSamw sam_get_local_domains(char *server, char *domain_name)
216da6c28aaSamw {
217da6c28aaSamw 	mlsvc_handle_t samr_handle;
218da6c28aaSamw 	DWORD status;
219da6c28aaSamw 	int rc;
220a0aa776eSAlan Wright 	char user[SMB_USERNAME_MAXLEN];
221a0aa776eSAlan Wright 
222a0aa776eSAlan Wright 	smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
223da6c28aaSamw 
22455bf511dSas200622 	rc = samr_open(server, domain_name, user, SAM_ENUM_LOCAL_DOMAIN,
22555bf511dSas200622 	    &samr_handle);
226da6c28aaSamw 	if (rc != 0)
227da6c28aaSamw 		return (NT_STATUS_OPEN_FAILED);
228da6c28aaSamw 
229da6c28aaSamw 	status = samr_enum_local_domains(&samr_handle);
230da6c28aaSamw 	(void) samr_close_handle(&samr_handle);
231da6c28aaSamw 	return (status);
232da6c28aaSamw }
233da6c28aaSamw 
234da6c28aaSamw /*
2351ed6b69aSGordon Ross  * Set the account control flags on some account for which we
2361ed6b69aSGordon Ross  * have already opened a SAM handle with appropriate rights,
2371ed6b69aSGordon Ross  * passed in here as sam_handle, along with the new flags.
238da6c28aaSamw  */
2391ed6b69aSGordon Ross DWORD
netr_set_user_control(mlsvc_handle_t * user_handle,DWORD UserAccountControl)2401ed6b69aSGordon Ross netr_set_user_control(
2411ed6b69aSGordon Ross 	mlsvc_handle_t *user_handle,
2421ed6b69aSGordon Ross 	DWORD UserAccountControl)
243da6c28aaSamw {
2441ed6b69aSGordon Ross 	struct samr_SetUserInfo16 info;
245da6c28aaSamw 
2461ed6b69aSGordon Ross 	info.UserAccountControl = UserAccountControl;
2471ed6b69aSGordon Ross 	return (samr_set_user_info(user_handle, 16, &info));
248da6c28aaSamw }
2498d7e4166Sjose borrego 
2501ed6b69aSGordon Ross /*
2511ed6b69aSGordon Ross  * Set the password on some account, for which we have already
2521ed6b69aSGordon Ross  * opened a SAM handle with appropriate rights, passed in here
2531ed6b69aSGordon Ross  * as sam_handle, along with the new password as cleartext.
2541ed6b69aSGordon Ross  *
2551ed6b69aSGordon Ross  * This builds a struct SAMPR_USER_INTERNAL5_INFORMATION [MS-SAMR]
2561ed6b69aSGordon Ross  * containing the new password, encrypted with our session key.
2571ed6b69aSGordon Ross  */
2581ed6b69aSGordon Ross DWORD
netr_set_user_password(mlsvc_handle_t * user_handle,char * new_pw_clear)2591ed6b69aSGordon Ross netr_set_user_password(
2601ed6b69aSGordon Ross 	mlsvc_handle_t *user_handle,
2611ed6b69aSGordon Ross 	char *new_pw_clear)
2628d7e4166Sjose borrego {
2631ed6b69aSGordon Ross 	unsigned char ssn_key[SMBAUTH_HASH_SZ];
2641ed6b69aSGordon Ross 	struct samr_SetUserInfo24 info;
2658d7e4166Sjose borrego 
2661ed6b69aSGordon Ross 	if (ndr_rpc_get_ssnkey(user_handle, ssn_key, SMBAUTH_HASH_SZ))
2671ed6b69aSGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
2681ed6b69aSGordon Ross 
2691ed6b69aSGordon Ross 	(void) memset(&info, 0, sizeof (info));
2701ed6b69aSGordon Ross 	samr_make_encrypted_password(&info.encr_pw, new_pw_clear, ssn_key);
2711ed6b69aSGordon Ross 
2721ed6b69aSGordon Ross 	/* Rather not leave the session key around. */
2731ed6b69aSGordon Ross 	(void) memset(ssn_key, 0, sizeof (ssn_key));
2741ed6b69aSGordon Ross 
2751ed6b69aSGordon Ross 	return (samr_set_user_info(user_handle, 24, &info));
2768d7e4166Sjose borrego }
27729bd2886SAlan Wright 
2781ed6b69aSGordon Ross /*
2791ed6b69aSGordon Ross  * Change a password like NetUserChangePassword(),
2801ed6b69aSGordon Ross  * but where we already know which AD server to use,
2811ed6b69aSGordon Ross  * so we don't request the domain name or search for
2821ed6b69aSGordon Ross  * an AD server for that domain here.
2831ed6b69aSGordon Ross  */
2841ed6b69aSGordon Ross DWORD
netr_change_password(char * server,char * account,char * old_pw_clear,char * new_pw_clear)2851ed6b69aSGordon Ross netr_change_password(
2861ed6b69aSGordon Ross 	char *server,
2871ed6b69aSGordon Ross 	char *account,
2881ed6b69aSGordon Ross 	char *old_pw_clear,
2891ed6b69aSGordon Ross 	char *new_pw_clear)
2901ed6b69aSGordon Ross {
2911ed6b69aSGordon Ross 	struct samr_encr_passwd epw;
2921ed6b69aSGordon Ross 	struct samr_encr_hash old_hash;
2931ed6b69aSGordon Ross 	uint8_t old_nt_hash[SAMR_PWHASH_LEN];
2941ed6b69aSGordon Ross 	uint8_t new_nt_hash[SAMR_PWHASH_LEN];
2951ed6b69aSGordon Ross 	mlsvc_handle_t handle;
296b3700b07SGordon Ross 	DWORD status;
2971ed6b69aSGordon Ross 
2981ed6b69aSGordon Ross 	/*
2991ed6b69aSGordon Ross 	 * Create an RPC handle to this server, bound to SAMR.
300*15f5f761SMatt Barden 	 * Note: the group policy option to disable anonymous access to named
301*15f5f761SMatt Barden 	 * pipes on DCs doesn't work with this.
302*15f5f761SMatt Barden 	 * To work with that option, we'll have to find an interface that lets
303*15f5f761SMatt Barden 	 * us authenticate with an expired password, instead of the anonymous
304*15f5f761SMatt Barden 	 * bind we currently perform.
3051ed6b69aSGordon Ross 	 */
306b3700b07SGordon Ross 	status = ndr_rpc_bind(&handle, server, "", "", "SAMR");
307b3700b07SGordon Ross 	if (status != NT_STATUS_SUCCESS)
308b3700b07SGordon Ross 		return (status);
3091ed6b69aSGordon Ross 
3101ed6b69aSGordon Ross 	/*
3111ed6b69aSGordon Ross 	 * Encrypt the new p/w (plus random filler) with the
3121ed6b69aSGordon Ross 	 * old password, and send the old p/w encrypted with
3131ed6b69aSGordon Ross 	 * the new p/w hash to prove we know the old p/w.
3141ed6b69aSGordon Ross 	 * Details:  [MS-SAMR 3.1.5.10.3]
3151ed6b69aSGordon Ross 	 */
3161ed6b69aSGordon Ross 	(void) smb_auth_ntlm_hash(old_pw_clear, old_nt_hash);
3171ed6b69aSGordon Ross 	(void) smb_auth_ntlm_hash(new_pw_clear, new_nt_hash);
3181ed6b69aSGordon Ross 	samr_make_encrypted_password(&epw, new_pw_clear, old_nt_hash);
3191ed6b69aSGordon Ross 
3201ed6b69aSGordon Ross 	(void) smb_auth_DES(old_hash.data, SAMR_PWHASH_LEN,
3211ed6b69aSGordon Ross 	    new_nt_hash, 14, /* key */
3221ed6b69aSGordon Ross 	    old_nt_hash, SAMR_PWHASH_LEN);
3231ed6b69aSGordon Ross 
3241ed6b69aSGordon Ross 	/*
3251ed6b69aSGordon Ross 	 * Finally, ready to try the OtW call.
3261ed6b69aSGordon Ross 	 */
327b3700b07SGordon Ross 	status = samr_change_password(
3281ed6b69aSGordon Ross 	    &handle, server, account,
3291ed6b69aSGordon Ross 	    &epw, &old_hash);
3301ed6b69aSGordon Ross 
3311ed6b69aSGordon Ross 	/* Avoid leaving cleartext (or equivalent) around. */
3321ed6b69aSGordon Ross 	(void) memset(old_nt_hash, 0, sizeof (old_nt_hash));
3331ed6b69aSGordon Ross 	(void) memset(new_nt_hash, 0, sizeof (new_nt_hash));
3341ed6b69aSGordon Ross 
3351ed6b69aSGordon Ross 	ndr_rpc_unbind(&handle);
336b3700b07SGordon Ross 	return (status);
3378d7e4166Sjose borrego }
3388d7e4166Sjose borrego 
3391ed6b69aSGordon Ross /*
3401ed6b69aSGordon Ross  * Build an encrypted password, as used by samr_set_user_info
3411ed6b69aSGordon Ross  * and samr_change_password.  Note: This builds the unencrypted
3421ed6b69aSGordon Ross  * form in one union arm, and encrypts it in the other union arm.
3431ed6b69aSGordon Ross  */
3441ed6b69aSGordon Ross void
samr_make_encrypted_password(struct samr_encr_passwd * epw,char * new_pw_clear,uint8_t * crypt_key)3451ed6b69aSGordon Ross samr_make_encrypted_password(
3461ed6b69aSGordon Ross 	struct samr_encr_passwd *epw,
3471ed6b69aSGordon Ross 	char *new_pw_clear,
3481ed6b69aSGordon Ross 	uint8_t *crypt_key)
3491ed6b69aSGordon Ross {
3501ed6b69aSGordon Ross 	union {
3511ed6b69aSGordon Ross 		struct samr_user_password u;
3521ed6b69aSGordon Ross 		struct samr_encr_passwd e;
3531ed6b69aSGordon Ross 	} pwu;
3541ed6b69aSGordon Ross 
3551ed6b69aSGordon Ross 	samr_fill_userpw(&pwu.u, new_pw_clear);
3561ed6b69aSGordon Ross 
3571ed6b69aSGordon Ross 	(void) smb_auth_RC4(pwu.e.data, sizeof (pwu.e.data),
3581ed6b69aSGordon Ross 	    crypt_key, SAMR_PWHASH_LEN,
3591ed6b69aSGordon Ross 	    pwu.e.data, sizeof (pwu.e.data));
3601ed6b69aSGordon Ross 
3611ed6b69aSGordon Ross 	(void) memcpy(epw->data, pwu.e.data, sizeof (pwu.e.data));
3621ed6b69aSGordon Ross 	(void) memset(pwu.e.data, 0, sizeof (pwu.e.data));
3631ed6b69aSGordon Ross }
3641ed6b69aSGordon Ross 
3651ed6b69aSGordon Ross /*
3661ed6b69aSGordon Ross  * This fills in a samr_user_password (a.k.a. SAMPR_USER_PASSWORD
3671ed6b69aSGordon Ross  * in the MS Net API) which has the new password "right justified"
3681ed6b69aSGordon Ross  * in the buffer, and any space on the left filled with random junk
3691ed6b69aSGordon Ross  * to improve the quality of the encryption that is subsequently
3701ed6b69aSGordon Ross  * applied to this buffer before it goes over the wire.
3711ed6b69aSGordon Ross  */
3721ed6b69aSGordon Ross static void
samr_fill_userpw(struct samr_user_password * upw,const char * new_pw)3731ed6b69aSGordon Ross samr_fill_userpw(struct samr_user_password *upw, const char *new_pw)
3741ed6b69aSGordon Ross {
3751ed6b69aSGordon Ross 	smb_wchar_t *pbuf;
3761ed6b69aSGordon Ross 	uint32_t pwlen_bytes;
3771ed6b69aSGordon Ross 	size_t pwlen_wchars;
3781ed6b69aSGordon Ross 
3791ed6b69aSGordon Ross 	/*
3801ed6b69aSGordon Ross 	 * First fill the whole buffer with the random junk.
3811ed6b69aSGordon Ross 	 * (Slightly less random when debugging:)
3821ed6b69aSGordon Ross 	 */
3831ed6b69aSGordon Ross #ifdef DEBUG
3841ed6b69aSGordon Ross 	(void) memset(upw->Buffer, '*', sizeof (upw->Buffer));
3851ed6b69aSGordon Ross #else
3861ed6b69aSGordon Ross 	randomize((char *)upw->Buffer, sizeof (upw->Buffer));
3871ed6b69aSGordon Ross #endif
3881ed6b69aSGordon Ross 
3891ed6b69aSGordon Ross 	/*
3901ed6b69aSGordon Ross 	 * Now overwrite the last pwlen characters of
3911ed6b69aSGordon Ross 	 * that buffer with the password, and set the
3921ed6b69aSGordon Ross 	 * length field so the receiving end knows where
3931ed6b69aSGordon Ross 	 * the junk ends and the real password starts.
3941ed6b69aSGordon Ross 	 */
3951ed6b69aSGordon Ross 	pwlen_wchars = smb_wcequiv_strlen(new_pw) / 2;
3961ed6b69aSGordon Ross 	if (pwlen_wchars > SAMR_USER_PWLEN)
3971ed6b69aSGordon Ross 		pwlen_wchars = SAMR_USER_PWLEN;
3981ed6b69aSGordon Ross 	pwlen_bytes = pwlen_wchars * 2;
3991ed6b69aSGordon Ross 
4001ed6b69aSGordon Ross 	pbuf = &upw->Buffer[SAMR_USER_PWLEN - pwlen_wchars];
4011ed6b69aSGordon Ross 	(void) smb_mbstowcs(pbuf, new_pw, pwlen_wchars);
4021ed6b69aSGordon Ross 
4031ed6b69aSGordon Ross 	/* Yes, this is in Bytes, not wchars. */
4041ed6b69aSGordon Ross 	upw->Length = htolel(pwlen_bytes);
4058d7e4166Sjose borrego }
406