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.
24c585f97bSMatt Barden  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
250ccfe583SMatt Barden  * Copyright 2023 RackTop Systems, Inc.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * NETR SamLogon and SamLogoff RPC client functions.
30da6c28aaSamw  */
31da6c28aaSamw 
32da6c28aaSamw #include <stdio.h>
33da6c28aaSamw #include <strings.h>
34da6c28aaSamw #include <stdlib.h>
35da6c28aaSamw #include <time.h>
36da6c28aaSamw #include <alloca.h>
37da6c28aaSamw #include <unistd.h>
38da6c28aaSamw #include <netdb.h>
398d7e4166Sjose borrego #include <thread.h>
40da6c28aaSamw 
413299f39fSGordon Ross #include <libmlrpc/libmlrpc.h>
42da6c28aaSamw #include <smbsrv/libsmb.h>
438d7e4166Sjose borrego #include <smbsrv/libmlsvc.h>
44da6c28aaSamw #include <smbsrv/ndl/netlogon.ndl>
45da6c28aaSamw #include <smbsrv/netrauth.h>
46da6c28aaSamw #include <smbsrv/smbinfo.h>
47da6c28aaSamw #include <smbsrv/smb_token.h>
488d7e4166Sjose borrego #include <mlsvc.h>
49da6c28aaSamw 
50ce8560eeSMatt Barden uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);
517f667e74Sjose borrego static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     smb_logon_t *, smb_token_t *);
53c585f97bSMatt Barden static void netr_invalidate_chain(netr_info_t *);
549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
55da6c28aaSamw     struct netr_logon_info1 *);
568d7e4166Sjose borrego static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     smb_logon_t *, struct netr_logon_info2 *);
589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
59da6c28aaSamw     netr_logon_id_t *);
607f667e74Sjose borrego static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
617f667e74Sjose borrego     smb_ids_t *);
622a2cfba0SGordon Ross static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *,
632a2cfba0SGordon Ross     smb_ids_t *);
647f667e74Sjose borrego static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
657f667e74Sjose borrego     smb_token_t *);
66da6c28aaSamw 
67da6c28aaSamw /*
68da6c28aaSamw  * Shared with netr_auth.c
69da6c28aaSamw  */
70da6c28aaSamw extern netr_info_t netr_global_info;
71da6c28aaSamw 
729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static mutex_t netlogon_mutex;
739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static cond_t netlogon_cv;
749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static boolean_t netlogon_busy = B_FALSE;
759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static boolean_t netlogon_abort = B_FALSE;
769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7712b65585SGordon Ross /*
7812b65585SGordon Ross  * Helper for Kerberos authentication
7912b65585SGordon Ross  */
8012b65585SGordon Ross uint32_t
smb_decode_krb5_pac(smb_token_t * token,char * data,uint_t len)8112b65585SGordon Ross smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
8212b65585SGordon Ross {
8312b65585SGordon Ross 	struct krb5_validation_info info;
8412b65585SGordon Ross 	ndr_buf_t *nbuf;
852a2cfba0SGordon Ross 	smb_sid_t *domsid;
8612b65585SGordon Ross 	uint32_t status = NT_STATUS_NO_MEMORY;
8712b65585SGordon Ross 	int rc;
8812b65585SGordon Ross 
8912b65585SGordon Ross 	bzero(&info, sizeof (info));
9012b65585SGordon Ross 
9112b65585SGordon Ross 	/* Need to keep this until we're done with &info */
9212b65585SGordon Ross 	nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
9312b65585SGordon Ross 	if (nbuf == NULL)
9412b65585SGordon Ross 		goto out;
9512b65585SGordon Ross 
9612b65585SGordon Ross 	rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
9712b65585SGordon Ross 	    NETR_OPNUM_decode_krb5_pac, data, len, &info);
9812b65585SGordon Ross 	if (rc != NDR_DRC_OK) {
9912b65585SGordon Ross 		status = RPC_NT_PROTOCOL_ERROR;
10012b65585SGordon Ross 		goto out;
10112b65585SGordon Ross 	}
10212b65585SGordon Ross 
1032a2cfba0SGordon Ross 	/*
1042a2cfba0SGordon Ross 	 * Copy the decoded info into the token,
1052a2cfba0SGordon Ross 	 * similar to netr_setup_token()
1062a2cfba0SGordon Ross 	 */
1072a2cfba0SGordon Ross 	domsid = (smb_sid_t *)info.info3.LogonDomainId;
10812b65585SGordon Ross 
10912b65585SGordon Ross 	token->tkn_user.i_sid = smb_sid_splice(domsid,
1102a2cfba0SGordon Ross 	    info.info3.UserId);
11112b65585SGordon Ross 	if (token->tkn_user.i_sid == NULL)
1122a2cfba0SGordon Ross 		goto out;
11312b65585SGordon Ross 
11412b65585SGordon Ross 	token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
1152a2cfba0SGordon Ross 	    info.info3.PrimaryGroupId);
11612b65585SGordon Ross 	if (token->tkn_primary_grp.i_sid == NULL)
1172a2cfba0SGordon Ross 		goto out;
11812b65585SGordon Ross 
1192a2cfba0SGordon Ross 	if (info.info3.EffectiveName.str) {
12012b65585SGordon Ross 		token->tkn_account_name =
1212a2cfba0SGordon Ross 		    strdup((char *)info.info3.EffectiveName.str);
12212b65585SGordon Ross 		if (token->tkn_account_name == NULL)
1232a2cfba0SGordon Ross 			goto out;
12412b65585SGordon Ross 	}
12512b65585SGordon Ross 
1262a2cfba0SGordon Ross 	if (info.info3.LogonDomainName.str) {
12712b65585SGordon Ross 		token->tkn_domain_name =
1282a2cfba0SGordon Ross 		    strdup((char *)info.info3.LogonDomainName.str);
12912b65585SGordon Ross 		if (token->tkn_domain_name == NULL)
1302a2cfba0SGordon Ross 			goto out;
13112b65585SGordon Ross 	}
13212b65585SGordon Ross 
1332a2cfba0SGordon Ross 	status = netr_setup_domain_groups(&info.info3, &token->tkn_win_grps);
1342a2cfba0SGordon Ross 	if (status != NT_STATUS_SUCCESS)
1352a2cfba0SGordon Ross 		goto out;
1362a2cfba0SGordon Ross 
1372a2cfba0SGordon Ross 	if (info.rg_rid_cnt != 0) {
1382a2cfba0SGordon Ross 		status = netr_setup_krb5res_groups(&info, &token->tkn_win_grps);
1392a2cfba0SGordon Ross 		if (status != NT_STATUS_SUCCESS)
1402a2cfba0SGordon Ross 			goto out;
1412a2cfba0SGordon Ross 	}
1422a2cfba0SGordon Ross 
1432a2cfba0SGordon Ross 	status = netr_setup_token_wingrps(&info.info3, token);
1442a2cfba0SGordon Ross 
1452a2cfba0SGordon Ross out:
1462a2cfba0SGordon Ross 	if (nbuf != NULL)
1472a2cfba0SGordon Ross 		ndr_buf_fini(nbuf);
1482a2cfba0SGordon Ross 
1492a2cfba0SGordon Ross 	return (status);
15012b65585SGordon Ross }
15112b65585SGordon Ross 
1529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
1539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Abort impending domain logon requests.
1549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
1559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_logon_abort(void)1569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_logon_abort(void)
1579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
1589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) mutex_lock(&netlogon_mutex);
1599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (netlogon_busy && !netlogon_abort)
1609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		syslog(LOG_DEBUG, "logon abort");
1619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	netlogon_abort = B_TRUE;
1629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) cond_broadcast(&netlogon_cv);
1639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) mutex_unlock(&netlogon_mutex);
1649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
1658d7e4166Sjose borrego 
166da6c28aaSamw /*
1679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * This is the entry point for authenticating domain users.
168da6c28aaSamw  *
1699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * If we are not going to attempt to authenticate the user,
1709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * this function must return without updating the status.
171da6c28aaSamw  *
1729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * If the user is successfully authenticated, we build an
1739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * access token and the status will be NT_STATUS_SUCCESS.
1749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Otherwise, the token contents are invalid.
175975041ddSGordon Ross  *
176975041ddSGordon Ross  * This will retry a few times for errors indicating that the
177975041ddSGordon Ross  * current DC might have gone off-line or become too busy etc.
178975041ddSGordon Ross  * With such errors, smb_ddiscover_bad_dc is called and then
179975041ddSGordon Ross  * the smb_domain_getinfo call here waits for new DC info.
180da6c28aaSamw  */
181975041ddSGordon Ross int smb_netr_logon_retries = 3;
1829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_logon_domain(smb_logon_t * user_info,smb_token_t * token)1839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
1848d7e4166Sjose borrego {
185975041ddSGordon Ross 	smb_domainex_t	di;
1869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	status;
187975041ddSGordon Ross 	int		retries = smb_netr_logon_retries;
1888d7e4166Sjose borrego 
1899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
1909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
1918d7e4166Sjose borrego 
1929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
1939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
1948d7e4166Sjose borrego 
195975041ddSGordon Ross 	while (--retries > 0) {
196975041ddSGordon Ross 
197975041ddSGordon Ross 		if (!smb_domain_getinfo(&di)) {
198975041ddSGordon Ross 			syslog(LOG_ERR, "logon DC getinfo failed");
199975041ddSGordon Ross 			status = NT_STATUS_NO_LOGON_SERVERS;
200975041ddSGordon Ross 			goto out;
201975041ddSGordon Ross 		}
202975041ddSGordon Ross 
2039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) mutex_lock(&netlogon_mutex);
2049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		while (netlogon_busy && !netlogon_abort)
2059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			(void) cond_wait(&netlogon_cv, &netlogon_mutex);
2069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
2079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (netlogon_abort) {
2089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			(void) mutex_unlock(&netlogon_mutex);
209975041ddSGordon Ross 			status = NT_STATUS_REQUEST_ABORTED;
210975041ddSGordon Ross 			goto out;
2119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
2129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
2139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		netlogon_busy = B_TRUE;
2149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) mutex_unlock(&netlogon_mutex);
2159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
216975041ddSGordon Ross 		status = netlogon_logon(user_info, token, &di);
2179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
2189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) mutex_lock(&netlogon_mutex);
2199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		netlogon_busy = B_FALSE;
2209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (netlogon_abort)
2219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			status = NT_STATUS_REQUEST_ABORTED;
2229fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) cond_signal(&netlogon_cv);
2239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) mutex_unlock(&netlogon_mutex);
2249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
225975041ddSGordon Ross 		switch (status) {
226975041ddSGordon Ross 		case NT_STATUS_BAD_NETWORK_PATH:
227975041ddSGordon Ross 		case NT_STATUS_BAD_NETWORK_NAME:
228975041ddSGordon Ross 		case RPC_NT_SERVER_TOO_BUSY:
229975041ddSGordon Ross 			/*
230975041ddSGordon Ross 			 * May retry with a new DC, or if we're
231975041ddSGordon Ross 			 * out of retries, will return...
232975041ddSGordon Ross 			 */
233975041ddSGordon Ross 			status = NT_STATUS_NO_LOGON_SERVERS;
2349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			break;
235975041ddSGordon Ross 		default:
236975041ddSGordon Ross 			goto out;
237975041ddSGordon Ross 		}
2389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
2399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
240975041ddSGordon Ross out:
2419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (status != NT_STATUS_SUCCESS)
2429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
2439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		    user_info->lg_e_username, xlate_nt_status(status));
2449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user_info->lg_status = status;
2458d7e4166Sjose borrego }
2468d7e4166Sjose borrego 
247ce8560eeSMatt Barden static uint32_t
netr_get_handle(char * server,char * domain,mlsvc_handle_t * netr_handle)248ce8560eeSMatt Barden netr_get_handle(char *server, char *domain, mlsvc_handle_t *netr_handle)
249ce8560eeSMatt Barden {
250ce8560eeSMatt Barden 	uint32_t status;
251ce8560eeSMatt Barden 	boolean_t did_renego = B_FALSE;
252ce8560eeSMatt Barden 
253ce8560eeSMatt Barden reauth:
254ce8560eeSMatt Barden 	if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
255ce8560eeSMatt Barden 	    !smb_match_netlogon_seqnum()) {
256ce8560eeSMatt Barden 		/*
257ce8560eeSMatt Barden 		 * This does netr_server_req_challenge() and
258ce8560eeSMatt Barden 		 * netr_server_authenticate2(), updating the
259ce8560eeSMatt Barden 		 * current netlogon sequence number.
260ce8560eeSMatt Barden 		 */
261ce8560eeSMatt Barden 		status = netlogon_auth(server, domain, NETR_FLG_NULL);
262ce8560eeSMatt Barden 
263ce8560eeSMatt Barden 		if (status != 0) {
264ce8560eeSMatt Barden 			syslog(LOG_ERR, "%s: auth failed (%s)",
265ce8560eeSMatt Barden 			    __func__, xlate_nt_status(status));
266ce8560eeSMatt Barden 			return (status);
267ce8560eeSMatt Barden 		}
268ce8560eeSMatt Barden 
269ce8560eeSMatt Barden 		netr_global_info.flags |= NETR_FLG_VALID;
270ce8560eeSMatt Barden 	}
271ce8560eeSMatt Barden 
272ce8560eeSMatt Barden 	/*
273ce8560eeSMatt Barden 	 * This netr_open_secure call does the work to connect to the DC,
274ce8560eeSMatt Barden 	 * get the IPC share, open the named pipe, RPC bind, etc.
275ce8560eeSMatt Barden 	 */
276ce8560eeSMatt Barden 	status = netr_open_secure(server, domain, netr_handle);
277ce8560eeSMatt Barden 	if (status != 0) {
278ce8560eeSMatt Barden 		/*
279ce8560eeSMatt Barden 		 * This may have failed because the DC restarted.
280ce8560eeSMatt Barden 		 * Re-negotiate once.
281ce8560eeSMatt Barden 		 */
282ce8560eeSMatt Barden 		if (!did_renego) {
283ce8560eeSMatt Barden 			did_renego = B_TRUE;
284c585f97bSMatt Barden 			netr_invalidate_chain(&netr_global_info);
285ce8560eeSMatt Barden 			syslog(LOG_ERR, "%s: open failed (%s); "
286ce8560eeSMatt Barden 			    "renegotiating...",
287ce8560eeSMatt Barden 			    __func__, xlate_nt_status(status));
288ce8560eeSMatt Barden 			goto reauth;
289ce8560eeSMatt Barden 		}
290ce8560eeSMatt Barden 		syslog(LOG_ERR, "%s: open failed (%s)",
291ce8560eeSMatt Barden 		    __func__, xlate_nt_status(status));
292ce8560eeSMatt Barden 	}
293ce8560eeSMatt Barden 
294ce8560eeSMatt Barden 	return (status);
295ce8560eeSMatt Barden }
296ce8560eeSMatt Barden 
297975041ddSGordon Ross /*
298975041ddSGordon Ross  * Run a netr_server_samlogon call, dealing with the possible need to
299975041ddSGordon Ross  * re-establish the NetLogon credential chain.  If that fails, return
300975041ddSGordon Ross  * NT_STATUS_DOMAIN_TRUST_INCONSISTENT indicating the machine account
301975041ddSGordon Ross  * needs it's password reset (or whatever).  Other errors are from the
302975041ddSGordon Ross  * netr_server_samlogon() call including the many possibilities listed
303975041ddSGordon Ross  * above that function.
304975041ddSGordon Ross  */
305ce8560eeSMatt Barden uint32_t
netlogon_logon(smb_logon_t * user_info,smb_token_t * token,smb_domainex_t * di)306975041ddSGordon Ross netlogon_logon(smb_logon_t *user_info, smb_token_t *token, smb_domainex_t *di)
307da6c28aaSamw {
308b3700b07SGordon Ross 	char server[MAXHOSTNAMELEN];
309da6c28aaSamw 	mlsvc_handle_t netr_handle;
3107f667e74Sjose borrego 	uint32_t status;
311975041ddSGordon Ross 	boolean_t did_reauth = B_FALSE;
312975041ddSGordon Ross 
313975041ddSGordon Ross 	if (di->d_dci.dc_name[0] != '\0' &&
314975041ddSGordon Ross 	    (*netr_global_info.server != '\0')) {
315975041ddSGordon Ross 		(void) snprintf(server, sizeof (server),
316975041ddSGordon Ross 		    "\\\\%s", di->d_dci.dc_name);
317975041ddSGordon Ross 		if (strncasecmp(netr_global_info.server,
318975041ddSGordon Ross 		    server, strlen(server)) != 0)
319c585f97bSMatt Barden 			netr_invalidate_chain(&netr_global_info);
320975041ddSGordon Ross 	}
321975041ddSGordon Ross 
322975041ddSGordon Ross reauth:
323ce8560eeSMatt Barden 	status = netr_get_handle(di->d_dci.dc_name,
324ce8560eeSMatt Barden 	    di->d_primary.di_nbname, &netr_handle);
325975041ddSGordon Ross 
326ce8560eeSMatt Barden 	if (status != 0) {
327ce8560eeSMatt Barden 		syslog(LOG_ERR, "%s: failed to get handle (%s)",
328ce8560eeSMatt Barden 		    __func__, xlate_nt_status(status));
329ce8560eeSMatt Barden 		return (NT_STATUS_DOMAIN_TRUST_INCONSISTENT);
330da6c28aaSamw 	}
331da6c28aaSamw 
332975041ddSGordon Ross 	status = netr_server_samlogon(&netr_handle,
333975041ddSGordon Ross 	    &netr_global_info, di->d_dci.dc_name, user_info, token);
334975041ddSGordon Ross 
335975041ddSGordon Ross 	if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
336975041ddSGordon Ross 		if (!did_reauth) {
337975041ddSGordon Ross 			/* Call netlogon_auth() again, just once. */
338ce8560eeSMatt Barden 			(void) netr_close(&netr_handle);
339975041ddSGordon Ross 			did_reauth = B_TRUE;
340975041ddSGordon Ross 			goto reauth;
341c8ec8eeaSjose borrego 		}
342975041ddSGordon Ross 		status = NT_STATUS_DOMAIN_TRUST_INCONSISTENT;
343975041ddSGordon Ross 	}
344c8ec8eeaSjose borrego 
345975041ddSGordon Ross 	(void) netr_close(&netr_handle);
346da6c28aaSamw 
347975041ddSGordon Ross 	return (status);
348975041ddSGordon Ross }
349da6c28aaSamw 
350975041ddSGordon Ross /*
351975041ddSGordon Ross  * Helper for mlsvc_netlogon
352975041ddSGordon Ross  *
353975041ddSGordon Ross  * Call netlogon_auth with appropriate locks etc.
354975041ddSGordon Ross  * Serialize like smb_logon_domain does for
355975041ddSGordon Ross  * netlogon_logon / netlogon_auth
356975041ddSGordon Ross  */
357975041ddSGordon Ross uint32_t
smb_netlogon_check(char * server,char * domain)358975041ddSGordon Ross smb_netlogon_check(char *server, char *domain)
359975041ddSGordon Ross {
360975041ddSGordon Ross 	mlsvc_handle_t netr_handle;
361975041ddSGordon Ross 	uint32_t	status;
362975041ddSGordon Ross 
363975041ddSGordon Ross 	(void) mutex_lock(&netlogon_mutex);
364975041ddSGordon Ross 	while (netlogon_busy)
365975041ddSGordon Ross 		(void) cond_wait(&netlogon_cv, &netlogon_mutex);
366975041ddSGordon Ross 
367975041ddSGordon Ross 	netlogon_busy = B_TRUE;
368975041ddSGordon Ross 	(void) mutex_unlock(&netlogon_mutex);
369975041ddSGordon Ross 
370975041ddSGordon Ross 	/*
371ce8560eeSMatt Barden 	 * Like netlogon_logon(), but no netr_server_samlogon call.
372ce8560eeSMatt Barden 	 * We're just making sure we can connect to the NETLOGON server.
373975041ddSGordon Ross 	 */
374ce8560eeSMatt Barden 	status = netr_get_handle(server, domain, &netr_handle);
375ce8560eeSMatt Barden 	if (status == 0)
376ce8560eeSMatt Barden 		(void) netr_close(&netr_handle);
377ce8560eeSMatt Barden 	else
378ce8560eeSMatt Barden 		syslog(LOG_ERR, "%s: failed to get handle (%s)",
379ce8560eeSMatt Barden 		    __func__, xlate_nt_status(status));
380975041ddSGordon Ross 
381975041ddSGordon Ross 	(void) mutex_lock(&netlogon_mutex);
382975041ddSGordon Ross 	netlogon_busy = B_FALSE;
383975041ddSGordon Ross 	(void) cond_signal(&netlogon_cv);
384975041ddSGordon Ross 	(void) mutex_unlock(&netlogon_mutex);
385da6c28aaSamw 
386da6c28aaSamw 	return (status);
387da6c28aaSamw }
388da6c28aaSamw 
3897f667e74Sjose borrego static uint32_t
netr_setup_token(struct netr_validation_info3 * info3,smb_logon_t * user_info,netr_info_t * netr_info,smb_token_t * token)3909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
3917f667e74Sjose borrego     netr_info_t *netr_info, smb_token_t *token)
392da6c28aaSamw {
393da6c28aaSamw 	char *username, *domain;
3948c10a865Sas 	unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
3957f667e74Sjose borrego 	smb_sid_t *domsid;
3967f667e74Sjose borrego 	uint32_t status;
3977f667e74Sjose borrego 	char nbdomain[NETBIOS_NAME_SZ];
398da6c28aaSamw 
3997f667e74Sjose borrego 	domsid = (smb_sid_t *)info3->LogonDomainId;
400da6c28aaSamw 
4017f667e74Sjose borrego 	token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
4027f667e74Sjose borrego 	if (token->tkn_user.i_sid == NULL)
403da6c28aaSamw 		return (NT_STATUS_NO_MEMORY);
404da6c28aaSamw 
4057f667e74Sjose borrego 	token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
4067f667e74Sjose borrego 	    info3->PrimaryGroupId);
4077f667e74Sjose borrego 	if (token->tkn_primary_grp.i_sid == NULL)
408da6c28aaSamw 		return (NT_STATUS_NO_MEMORY);
409da6c28aaSamw 
410da6c28aaSamw 	username = (info3->EffectiveName.str)
4119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
4127f667e74Sjose borrego 
4137f667e74Sjose borrego 	if (info3->LogonDomainName.str) {
4147f667e74Sjose borrego 		domain = (char *)info3->LogonDomainName.str;
4159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	} else if (*user_info->lg_e_domain != '\0') {
4169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		domain = user_info->lg_e_domain;
4177f667e74Sjose borrego 	} else {
4187f667e74Sjose borrego 		(void) smb_getdomainname(nbdomain, sizeof (nbdomain));
4197f667e74Sjose borrego 		domain = nbdomain;
4207f667e74Sjose borrego 	}
421da6c28aaSamw 
422da6c28aaSamw 	if (username)
4237f667e74Sjose borrego 		token->tkn_account_name = strdup(username);
424da6c28aaSamw 	if (domain)
4257f667e74Sjose borrego 		token->tkn_domain_name = strdup(domain);
426da6c28aaSamw 
4277f667e74Sjose borrego 	if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
428da6c28aaSamw 		return (NT_STATUS_NO_MEMORY);
429da6c28aaSamw 
4302a2cfba0SGordon Ross 	status = netr_setup_domain_groups(info3, &token->tkn_win_grps);
4312a2cfba0SGordon Ross 	if (status != NT_STATUS_SUCCESS)
4322a2cfba0SGordon Ross 		return (status);
4332a2cfba0SGordon Ross 
4347f667e74Sjose borrego 	status = netr_setup_token_wingrps(info3, token);
4357f667e74Sjose borrego 	if (status != NT_STATUS_SUCCESS)
4367f667e74Sjose borrego 		return (status);
4377f667e74Sjose borrego 
4388c10a865Sas 	/*
4398c10a865Sas 	 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
440c8ec8eeaSjose borrego 	 * session key obtained in the NETLOGON credential chain.
441c8ec8eeaSjose borrego 	 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
4428c10a865Sas 	 * key is the key to the RC4 algorithm. The RC4 byte stream is
4438c10a865Sas 	 * exclusively ored with the 16 byte UserSessionKey to recover
4448c10a865Sas 	 * the the clear form.
4458c10a865Sas 	 */
44612b65585SGordon Ross 	if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
4478c10a865Sas 		return (NT_STATUS_NO_MEMORY);
44812b65585SGordon Ross 	token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
4498c10a865Sas 	bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
4502c1b14e5Sjose borrego 	bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
45112b65585SGordon Ross 	bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
4528c10a865Sas 	    SMBAUTH_SESSION_KEY_SZ);
45312b65585SGordon Ross 	rand_hash((unsigned char *)token->tkn_ssnkey.val,
4548c10a865Sas 	    SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
4557f667e74Sjose borrego 
456da6c28aaSamw 	return (NT_STATUS_SUCCESS);
457da6c28aaSamw }
458da6c28aaSamw 
459da6c28aaSamw /*
460da6c28aaSamw  * netr_server_samlogon
461da6c28aaSamw  *
462da6c28aaSamw  * NetrServerSamLogon RPC: interactive or network. It is assumed that
463da6c28aaSamw  * we have already authenticated with the PDC. If everything works,
464da6c28aaSamw  * we build a user info structure and return it, where the caller will
465da6c28aaSamw  * probably build an access token.
466da6c28aaSamw  *
467da6c28aaSamw  * Returns an NT status. There are numerous possibilities here.
468da6c28aaSamw  * For example:
469da6c28aaSamw  *	NT_STATUS_INVALID_INFO_CLASS
470da6c28aaSamw  *	NT_STATUS_INVALID_PARAMETER
471da6c28aaSamw  *	NT_STATUS_ACCESS_DENIED
472da6c28aaSamw  *	NT_STATUS_PASSWORD_MUST_CHANGE
473da6c28aaSamw  *	NT_STATUS_NO_SUCH_USER
474da6c28aaSamw  *	NT_STATUS_WRONG_PASSWORD
475da6c28aaSamw  *	NT_STATUS_LOGON_FAILURE
476da6c28aaSamw  *	NT_STATUS_ACCOUNT_RESTRICTION
477da6c28aaSamw  *	NT_STATUS_INVALID_LOGON_HOURS
478da6c28aaSamw  *	NT_STATUS_INVALID_WORKSTATION
479da6c28aaSamw  *	NT_STATUS_INTERNAL_ERROR
480da6c28aaSamw  *	NT_STATUS_PASSWORD_EXPIRED
481da6c28aaSamw  *	NT_STATUS_ACCOUNT_DISABLED
482da6c28aaSamw  */
4837f667e74Sjose borrego uint32_t
netr_server_samlogon(mlsvc_handle_t * netr_handle,netr_info_t * netr_info,char * server,smb_logon_t * user_info,smb_token_t * token)484da6c28aaSamw netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
4859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     char *server, smb_logon_t *user_info, smb_token_t *token)
486da6c28aaSamw {
487ce8560eeSMatt Barden 	struct netr_SamLogon logon_op;
488ce8560eeSMatt Barden 	struct netr_SamLogonEx logon_ex_op;
489da6c28aaSamw 	struct netr_authenticator auth;
490da6c28aaSamw 	struct netr_authenticator ret_auth;
491da6c28aaSamw 	struct netr_logon_info1 info1;
492da6c28aaSamw 	struct netr_logon_info2 info2;
493da6c28aaSamw 	struct netr_validation_info3 *info3;
494ce8560eeSMatt Barden 	union netr_validation_u *valid_info;
495ce8560eeSMatt Barden 	union netr_logon_info_u *logon_info;
496ce8560eeSMatt Barden 	LPTSTR servername, hostname;
4978d7e4166Sjose borrego 	ndr_heap_t *heap;
498da6c28aaSamw 	int opnum;
499da6c28aaSamw 	int rc, len;
500ce8560eeSMatt Barden 	uint32_t status, *rpc_status;
501ce8560eeSMatt Barden 	void *rpc_arg;
502da6c28aaSamw 
503da6c28aaSamw 	/*
504da6c28aaSamw 	 * Should we get the server and hostname from netr_info?
505da6c28aaSamw 	 */
5068d7e4166Sjose borrego 
507da6c28aaSamw 	len = strlen(server) + 4;
508ce8560eeSMatt Barden 	servername = ndr_rpc_malloc(netr_handle, len);
509ce8560eeSMatt Barden 	hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ);
510ce8560eeSMatt Barden 	if (servername == NULL || hostname == NULL) {
5118d7e4166Sjose borrego 		ndr_rpc_release(netr_handle);
5128d7e4166Sjose borrego 		return (NT_STATUS_INTERNAL_ERROR);
5138d7e4166Sjose borrego 	}
514da6c28aaSamw 
515ce8560eeSMatt Barden 	(void) snprintf((char *)servername, len, "\\\\%s", server);
516ce8560eeSMatt Barden 	if (smb_getnetbiosname((char *)hostname, NETBIOS_NAME_SZ) != 0) {
5178d7e4166Sjose borrego 		ndr_rpc_release(netr_handle);
518da6c28aaSamw 		return (NT_STATUS_INTERNAL_ERROR);
519da6c28aaSamw 	}
520da6c28aaSamw 
521da6c28aaSamw 	rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
522da6c28aaSamw 	if (rc != SMBAUTH_SUCCESS) {
5238d7e4166Sjose borrego 		ndr_rpc_release(netr_handle);
524da6c28aaSamw 		return (NT_STATUS_INTERNAL_ERROR);
525da6c28aaSamw 	}
526da6c28aaSamw 
527ce8560eeSMatt Barden 	/*
528ce8560eeSMatt Barden 	 * If we use Secure RPC, we can use SamLogonEx instead of SamLogon.
529ce8560eeSMatt Barden 	 * SamLogonEx doesn't use NetLogon authenticators, instead relying
530ce8560eeSMatt Barden 	 * on Secure RPC to provide security.
531ce8560eeSMatt Barden 	 * This allows us to avoid being bitten by mitigations in
532ce8560eeSMatt Barden 	 * the authenticator verification logic on DCs.
533ce8560eeSMatt Barden 	 */
534ce8560eeSMatt Barden 	if (netr_info->use_logon_ex &&
535ce8560eeSMatt Barden 	    (netr_info->nego_flags & NETR_NEGO_SECURE_RPC_FLAG) != 0) {
536ce8560eeSMatt Barden 		bzero(&logon_ex_op, sizeof (struct netr_SamLogonEx));
537ce8560eeSMatt Barden 		logon_ex_op.servername = servername;
538ce8560eeSMatt Barden 		logon_ex_op.hostname = hostname;
539ce8560eeSMatt Barden 		logon_ex_op.logon_info.logon_level = user_info->lg_level;
540ce8560eeSMatt Barden 		logon_ex_op.logon_info.switch_value = user_info->lg_level;
541ce8560eeSMatt Barden 		logon_ex_op.validation_level = NETR_VALIDATION_LEVEL3;
542ce8560eeSMatt Barden 		logon_ex_op.extra_flags = 0;
543ce8560eeSMatt Barden 		logon_info = &logon_ex_op.logon_info.ru;
544ce8560eeSMatt Barden 		valid_info = &logon_ex_op.ru;
545ce8560eeSMatt Barden 		rpc_status = &logon_ex_op.status;
546ce8560eeSMatt Barden 		rpc_arg = &logon_ex_op;
547ce8560eeSMatt Barden 		opnum = NETR_OPNUM_SamLogonEx;
548ce8560eeSMatt Barden 	} else {
549ce8560eeSMatt Barden 		bzero(&logon_op, sizeof (struct netr_SamLogon));
550ce8560eeSMatt Barden 		logon_op.servername = servername;
551ce8560eeSMatt Barden 		logon_op.hostname = hostname;
552ce8560eeSMatt Barden 		logon_op.auth = &auth;
553ce8560eeSMatt Barden 		logon_op.ret_auth = &ret_auth;
554ce8560eeSMatt Barden 		logon_op.logon_info.logon_level = user_info->lg_level;
555ce8560eeSMatt Barden 		logon_op.logon_info.switch_value = user_info->lg_level;
556ce8560eeSMatt Barden 		logon_op.validation_level = NETR_VALIDATION_LEVEL3;
557ce8560eeSMatt Barden 		logon_info = &logon_op.logon_info.ru;
558ce8560eeSMatt Barden 		valid_info = &logon_op.ru;
559ce8560eeSMatt Barden 		rpc_status = &logon_op.status;
560ce8560eeSMatt Barden 		rpc_arg = &logon_op;
561ce8560eeSMatt Barden 		opnum = NETR_OPNUM_SamLogon;
562ce8560eeSMatt Barden 	}
5638d7e4166Sjose borrego 	heap = ndr_rpc_get_heap(netr_handle);
5648d7e4166Sjose borrego 
5659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	switch (user_info->lg_level) {
566da6c28aaSamw 	case NETR_INTERACTIVE_LOGON:
5679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		netr_setup_identity(heap, user_info, &info1.identity);
5689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		netr_interactive_samlogon(netr_info, user_info, &info1);
569ce8560eeSMatt Barden 		logon_info->info1 = &info1;
570da6c28aaSamw 		break;
571da6c28aaSamw 
572da6c28aaSamw 	case NETR_NETWORK_LOGON:
573f9bc6dadSDmitry.Savitsky@nexenta.com 		if (user_info->lg_challenge_key.len < 8 ||
574f9bc6dadSDmitry.Savitsky@nexenta.com 		    user_info->lg_challenge_key.val == NULL) {
575f9bc6dadSDmitry.Savitsky@nexenta.com 			ndr_rpc_release(netr_handle);
576f9bc6dadSDmitry.Savitsky@nexenta.com 			return (NT_STATUS_INVALID_PARAMETER);
577f9bc6dadSDmitry.Savitsky@nexenta.com 		}
5789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		netr_setup_identity(heap, user_info, &info2.identity);
5799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		netr_network_samlogon(heap, netr_info, user_info, &info2);
580ce8560eeSMatt Barden 		logon_info->info2 = &info2;
581da6c28aaSamw 		break;
582da6c28aaSamw 
583da6c28aaSamw 	default:
5848d7e4166Sjose borrego 		ndr_rpc_release(netr_handle);
585da6c28aaSamw 		return (NT_STATUS_INVALID_PARAMETER);
586da6c28aaSamw 	}
587da6c28aaSamw 
588ce8560eeSMatt Barden 	rc = ndr_rpc_call(netr_handle, opnum, rpc_arg);
589da6c28aaSamw 	if (rc != 0) {
590c585f97bSMatt Barden 		netr_invalidate_chain(netr_info);
591da6c28aaSamw 		status = NT_STATUS_INVALID_PARAMETER;
592ce8560eeSMatt Barden 	} else if (*rpc_status != 0) {
593ce8560eeSMatt Barden 		status = NT_SC_VALUE(*rpc_status);
594da6c28aaSamw 
595da6c28aaSamw 		/*
596da6c28aaSamw 		 * We need to validate the chain even though we have
597da6c28aaSamw 		 * a non-zero status. If the status is ACCESS_DENIED
598da6c28aaSamw 		 * this will trigger a new credential chain. However,
599da6c28aaSamw 		 * a valid credential is returned with some status
600da6c28aaSamw 		 * codes; for example, WRONG_PASSWORD.
601ce8560eeSMatt Barden 		 *
602ce8560eeSMatt Barden 		 * SamLogonEx doesn't use authenticators - nothing to validate.
603da6c28aaSamw 		 */
604ce8560eeSMatt Barden 		if (rpc_arg == &logon_op)
605ce8560eeSMatt Barden 			(void) netr_validate_chain(netr_info,
606ce8560eeSMatt Barden 			    logon_op.ret_auth);
607da6c28aaSamw 	} else {
608ce8560eeSMatt Barden 		if (rpc_arg == &logon_op) {
609ce8560eeSMatt Barden 			status = netr_validate_chain(netr_info,
610ce8560eeSMatt Barden 			    logon_op.ret_auth);
611ce8560eeSMatt Barden 			if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
612ce8560eeSMatt Barden 				ndr_rpc_release(netr_handle);
613ce8560eeSMatt Barden 				return (status);
614ce8560eeSMatt Barden 			}
615da6c28aaSamw 		}
616da6c28aaSamw 
617ce8560eeSMatt Barden 		info3 = valid_info->info3;
6189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		status = netr_setup_token(info3, user_info, netr_info, token);
619da6c28aaSamw 	}
620da6c28aaSamw 
6218d7e4166Sjose borrego 	ndr_rpc_release(netr_handle);
622da6c28aaSamw 	return (status);
623da6c28aaSamw }
624da6c28aaSamw 
625da6c28aaSamw /*
626da6c28aaSamw  * netr_interactive_samlogon
627da6c28aaSamw  *
628da6c28aaSamw  * Set things up for an interactive SamLogon. Copy the NT and LM
629da6c28aaSamw  * passwords to the logon structure and hash them with the session
630da6c28aaSamw  * key.
631da6c28aaSamw  */
632da6c28aaSamw static void
netr_interactive_samlogon(netr_info_t * netr_info,smb_logon_t * user_info,struct netr_logon_info1 * info1)6339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info,
634da6c28aaSamw     struct netr_logon_info1 *info1)
635da6c28aaSamw {
636da6c28aaSamw 	BYTE key[NETR_OWF_PASSWORD_SZ];
637da6c28aaSamw 
638da6c28aaSamw 	(void) memcpy(&info1->lm_owf_password,
6399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    user_info->lg_lm_password.val, sizeof (netr_owf_password_t));
640da6c28aaSamw 
641da6c28aaSamw 	(void) memcpy(&info1->nt_owf_password,
6429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    user_info->lg_nt_password.val, sizeof (netr_owf_password_t));
643da6c28aaSamw 
644da6c28aaSamw 	(void) memset(key, 0, NETR_OWF_PASSWORD_SZ);
6452c1b14e5Sjose borrego 	(void) memcpy(key, netr_info->session_key.key,
6462c1b14e5Sjose borrego 	    netr_info->session_key.len);
647da6c28aaSamw 
648da6c28aaSamw 	rand_hash((unsigned char *)&info1->lm_owf_password,
649da6c28aaSamw 	    NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
650da6c28aaSamw 
651da6c28aaSamw 	rand_hash((unsigned char *)&info1->nt_owf_password,
652da6c28aaSamw 	    NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
653da6c28aaSamw }
654da6c28aaSamw 
655da6c28aaSamw /*
656da6c28aaSamw  * netr_network_samlogon
657da6c28aaSamw  *
658da6c28aaSamw  * Set things up for a network SamLogon.  We provide a copy of the random
659da6c28aaSamw  * challenge, that we sent to the client, to the domain controller.  This
660da6c28aaSamw  * is the key that the client will have used to encrypt the NT and LM
661da6c28aaSamw  * passwords.  Note that Windows 9x clients may not provide both passwords.
662da6c28aaSamw  */
663da6c28aaSamw /*ARGSUSED*/
664da6c28aaSamw static void
netr_network_samlogon(ndr_heap_t * heap,netr_info_t * netr_info,smb_logon_t * user_info,struct netr_logon_info2 * info2)6658d7e4166Sjose borrego netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info,
6669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States     smb_logon_t *user_info, struct netr_logon_info2 *info2)
667da6c28aaSamw {
6682c1b14e5Sjose borrego 	uint32_t len;
6692c1b14e5Sjose borrego 
670f9bc6dadSDmitry.Savitsky@nexenta.com 	if (user_info->lg_challenge_key.len >= 8 &&
671f9bc6dadSDmitry.Savitsky@nexenta.com 	    user_info->lg_challenge_key.val != 0) {
672f9bc6dadSDmitry.Savitsky@nexenta.com 		bcopy(user_info->lg_challenge_key.val,
673f9bc6dadSDmitry.Savitsky@nexenta.com 		    info2->lm_challenge.data, 8);
674f9bc6dadSDmitry.Savitsky@nexenta.com 	} else {
675f9bc6dadSDmitry.Savitsky@nexenta.com 		bzero(info2->lm_challenge.data, 8);
676f9bc6dadSDmitry.Savitsky@nexenta.com 	}
677da6c28aaSamw 
6789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((len = user_info->lg_nt_password.len) != 0) {
6799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len,
6808d7e4166Sjose borrego 		    (ndr_vcbuf_t *)&info2->nt_response);
681da6c28aaSamw 	} else {
6822c1b14e5Sjose borrego 		bzero(&info2->nt_response, sizeof (netr_vcbuf_t));
683da6c28aaSamw 	}
684da6c28aaSamw 
6859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((len = user_info->lg_lm_password.len) != 0) {
6869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len,
6878d7e4166Sjose borrego 		    (ndr_vcbuf_t *)&info2->lm_response);
688da6c28aaSamw 	} else {
6892c1b14e5Sjose borrego 		bzero(&info2->lm_response, sizeof (netr_vcbuf_t));
690da6c28aaSamw 	}
691da6c28aaSamw }
692da6c28aaSamw 
693da6c28aaSamw /*
694da6c28aaSamw  * netr_setup_authenticator
695da6c28aaSamw  *
696da6c28aaSamw  * Set up the request and return authenticators. A new credential is
697da6c28aaSamw  * generated from the session key, the current client credential and
698da6c28aaSamw  * the current time, i.e.
699da6c28aaSamw  *
700da6c28aaSamw  *		NewCredential = Cred(SessionKey, OldCredential, time);
701da6c28aaSamw  *
702da6c28aaSamw  * The timestamp, which is used as a random seed, is stored in both
703da6c28aaSamw  * the request and return authenticators.
704da6c28aaSamw  *
705da6c28aaSamw  * If any difficulties occur using the cryptographic framework, the
706da6c28aaSamw  * function returns SMBAUTH_FAILURE.  Otherwise SMBAUTH_SUCCESS is
707da6c28aaSamw  * returned.
708da6c28aaSamw  */
709da6c28aaSamw int
netr_setup_authenticator(netr_info_t * netr_info,struct netr_authenticator * auth,struct netr_authenticator * ret_auth)710da6c28aaSamw netr_setup_authenticator(netr_info_t *netr_info,
711da6c28aaSamw     struct netr_authenticator *auth, struct netr_authenticator *ret_auth)
712da6c28aaSamw {
713ce8560eeSMatt Barden 	int rc;
714da6c28aaSamw 	bzero(auth, sizeof (struct netr_authenticator));
715da6c28aaSamw 
716ce8560eeSMatt Barden 	/*
717ce8560eeSMatt Barden 	 * Windows DCs will reject Authenticators if none of the first
718ce8560eeSMatt Barden 	 * 5 bytes of the ClientStoredCredential are unique.
719ce8560eeSMatt Barden 	 * Keep retrying until we've generated one that satisfies this.
720ce8560eeSMatt Barden 	 */
721ce8560eeSMatt Barden 	netr_info->timestamp = time(0) - 1;
722ce8560eeSMatt Barden 	do {
723ce8560eeSMatt Barden 		auth->timestamp = ++netr_info->timestamp;
724ce8560eeSMatt Barden 		rc = netr_gen_credentials(netr_info->session_key.key,
725ce8560eeSMatt Barden 		    &netr_info->client_credential,
726ce8560eeSMatt Barden 		    netr_info->timestamp,
727ce8560eeSMatt Barden 		    (netr_cred_t *)&auth->credential, B_TRUE);
728ce8560eeSMatt Barden 		if (rc != SMBAUTH_SUCCESS && rc != SMBAUTH_RETRY)
729ce8560eeSMatt Barden 			return (SMBAUTH_FAILURE);
730ce8560eeSMatt Barden 	} while (rc == SMBAUTH_RETRY);
731da6c28aaSamw 
732da6c28aaSamw 	if (ret_auth) {
733da6c28aaSamw 		bzero(ret_auth, sizeof (struct netr_authenticator));
734da6c28aaSamw 		ret_auth->timestamp = netr_info->timestamp;
735da6c28aaSamw 	}
736da6c28aaSamw 
737da6c28aaSamw 	return (SMBAUTH_SUCCESS);
738da6c28aaSamw }
739da6c28aaSamw 
740da6c28aaSamw /*
741da6c28aaSamw  * Validate the returned credentials and update the credential chain.
742da6c28aaSamw  * The server returns an updated client credential rather than a new
743da6c28aaSamw  * server credential.  The server uses (timestamp + 1) when generating
744da6c28aaSamw  * the credential.
745da6c28aaSamw  *
746da6c28aaSamw  * Generate the new seed for the credential chain. The new seed is
747da6c28aaSamw  * formed by adding (timestamp + 1) to the current client credential.
7487f667e74Sjose borrego  * The only quirk is the uint32_t style addition.
749da6c28aaSamw  *
750da6c28aaSamw  * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
751da6c28aaSamw  * NULL pointer. The Authenticator field of the SamLogon response packet
752da6c28aaSamw  * sent by the Samba 3 PDC always return NULL pointer if the received
753da6c28aaSamw  * SamLogon request is not immediately followed by the ServerReqChallenge
754da6c28aaSamw  * and ServerAuthenticate2 requests.
755da6c28aaSamw  *
756da6c28aaSamw  * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
757da6c28aaSamw  * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
758da6c28aaSamw  */
7597f667e74Sjose borrego uint32_t
netr_validate_chain(netr_info_t * netr_info,struct netr_authenticator * auth)760da6c28aaSamw netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
761da6c28aaSamw {
762da6c28aaSamw 	netr_cred_t cred;
7637f667e74Sjose borrego 	uint32_t result = NT_STATUS_SUCCESS;
7647f667e74Sjose borrego 	uint32_t *dwp;
765da6c28aaSamw 
766da6c28aaSamw 	++netr_info->timestamp;
767da6c28aaSamw 
7682c1b14e5Sjose borrego 	if (netr_gen_credentials(netr_info->session_key.key,
769da6c28aaSamw 	    &netr_info->client_credential,
770ce8560eeSMatt Barden 	    netr_info->timestamp, &cred, B_FALSE) != SMBAUTH_SUCCESS)
771da6c28aaSamw 		return (NT_STATUS_INTERNAL_ERROR);
772da6c28aaSamw 
773*fa3003d1SToomas Soome 	if (auth == NULL) {
774da6c28aaSamw 		/*
775da6c28aaSamw 		 * If the validation fails, destroy the credential chain.
776da6c28aaSamw 		 * This should trigger a new authentication chain.
777da6c28aaSamw 		 */
778c585f97bSMatt Barden 		netr_invalidate_chain(netr_info);
779da6c28aaSamw 		return (NT_STATUS_INSUFFICIENT_LOGON_INFO);
780da6c28aaSamw 	}
781da6c28aaSamw 
782da6c28aaSamw 	result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t));
783da6c28aaSamw 	if (result != 0) {
784da6c28aaSamw 		/*
785da6c28aaSamw 		 * If the validation fails, destroy the credential chain.
786da6c28aaSamw 		 * This should trigger a new authentication chain.
787da6c28aaSamw 		 */
788c585f97bSMatt Barden 		netr_invalidate_chain(netr_info);
789da6c28aaSamw 		result = NT_STATUS_UNSUCCESSFUL;
790da6c28aaSamw 	} else {
791da6c28aaSamw 		/*
792da6c28aaSamw 		 * Otherwise generate the next step in the chain.
793da6c28aaSamw 		 */
794da6c28aaSamw 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
7957f667e74Sjose borrego 		dwp = (uint32_t *)&netr_info->client_credential;
796da6c28aaSamw 		dwp[0] += netr_info->timestamp;
797da6c28aaSamw 
798da6c28aaSamw 		netr_info->flags |= NETR_FLG_VALID;
799da6c28aaSamw 	}
800da6c28aaSamw 
801da6c28aaSamw 	return (result);
802da6c28aaSamw }
803da6c28aaSamw 
804da6c28aaSamw /*
805da6c28aaSamw  * netr_invalidate_chain
806da6c28aaSamw  *
807da6c28aaSamw  * Mark the credential chain as invalid so that it will be recreated
808da6c28aaSamw  * on the next attempt.
809da6c28aaSamw  */
810da6c28aaSamw static void
netr_invalidate_chain(netr_info_t * netr_info)811c585f97bSMatt Barden netr_invalidate_chain(netr_info_t *netr_info)
812da6c28aaSamw {
813c585f97bSMatt Barden 	if ((netr_info->flags & NETR_FLG_VALID) == 0)
814c585f97bSMatt Barden 		return;
815c585f97bSMatt Barden 
816c585f97bSMatt Barden 	netr_info->flags &= ~NETR_FLG_VALID;
817c585f97bSMatt Barden 	explicit_bzero(&netr_info->session_key,
818c585f97bSMatt Barden 	    sizeof (netr_info->session_key));
8190ccfe583SMatt Barden 	explicit_bzero(&netr_info->rpc_seal_key,
8200ccfe583SMatt Barden 	    sizeof (netr_info->rpc_seal_key));
821c585f97bSMatt Barden 	explicit_bzero(&netr_info->client_credential,
822c585f97bSMatt Barden 	    sizeof (netr_info->client_credential));
823c585f97bSMatt Barden 	explicit_bzero(&netr_info->server_credential,
824c585f97bSMatt Barden 	    sizeof (netr_info->server_credential));
825da6c28aaSamw }
826da6c28aaSamw 
827da6c28aaSamw /*
828da6c28aaSamw  * netr_setup_identity
829da6c28aaSamw  *
830da6c28aaSamw  * Set up the client identity information. All of this information is
831da6c28aaSamw  * specifically related to the client user and workstation attempting
832da6c28aaSamw  * to access this system. It may not be in our primary domain.
833da6c28aaSamw  *
834da6c28aaSamw  * I don't know what logon_id is, it seems to be a unique identifier.
835da6c28aaSamw  * Increment it before each use.
836da6c28aaSamw  */
837da6c28aaSamw static void
netr_setup_identity(ndr_heap_t * heap,smb_logon_t * user_info,netr_logon_id_t * identity)8389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info,
839da6c28aaSamw     netr_logon_id_t *identity)
840da6c28aaSamw {
8418d7e4166Sjose borrego 	static mutex_t logon_id_mutex;
8428d7e4166Sjose borrego 	static uint32_t logon_id;
8438d7e4166Sjose borrego 
8448d7e4166Sjose borrego 	(void) mutex_lock(&logon_id_mutex);
845da6c28aaSamw 
846da6c28aaSamw 	if (logon_id == 0)
847da6c28aaSamw 		logon_id = 0xDCD0;
848da6c28aaSamw 
849da6c28aaSamw 	++logon_id;
8509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	user_info->lg_logon_id = logon_id;
851da6c28aaSamw 
8528d7e4166Sjose borrego 	(void) mutex_unlock(&logon_id_mutex);
8538d7e4166Sjose borrego 
85412b65585SGordon Ross 	/*
85512b65585SGordon Ross 	 * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set
85612b65585SGordon Ross 	 * ParameterControl to the 'E' + 'K' bits.  Those are:
85712b65585SGordon Ross 	 * (1 << 5) | (1 << 11), a.k.a
85812b65585SGordon Ross 	 */
85912b65585SGordon Ross 	identity->parameter_control =
86012b65585SGordon Ross 	    MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
86112b65585SGordon Ross 	    MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
862da6c28aaSamw 	identity->logon_id.LowPart = logon_id;
863da6c28aaSamw 	identity->logon_id.HighPart = 0;
864da6c28aaSamw 
8659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ndr_heap_mkvcs(heap, user_info->lg_domain,
8668d7e4166Sjose borrego 	    (ndr_vcstr_t *)&identity->domain_name);
867da6c28aaSamw 
8689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ndr_heap_mkvcs(heap, user_info->lg_username,
8698d7e4166Sjose borrego 	    (ndr_vcstr_t *)&identity->username);
870da6c28aaSamw 
871da6c28aaSamw 	/*
872da6c28aaSamw 	 * Some systems prefix the client workstation name with \\.
873da6c28aaSamw 	 * It doesn't seem to make any difference whether it's there
874da6c28aaSamw 	 * or not.
875da6c28aaSamw 	 */
8769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ndr_heap_mkvcs(heap, user_info->lg_workstation,
8778d7e4166Sjose borrego 	    (ndr_vcstr_t *)&identity->workstation);
878da6c28aaSamw }
8797f667e74Sjose borrego 
8807f667e74Sjose borrego /*
8812a2cfba0SGordon Ross  * Add local and well-known group membership to the given
8822a2cfba0SGordon Ross  * token.  Called after domain groups have been added.
8837f667e74Sjose borrego  */
8847f667e74Sjose borrego static uint32_t
netr_setup_token_wingrps(struct netr_validation_info3 * info3 __unused,smb_token_t * token)88548f31329SMatt Barden netr_setup_token_wingrps(struct netr_validation_info3 *info3 __unused,
8867f667e74Sjose borrego     smb_token_t *token)
8877f667e74Sjose borrego {
8887f667e74Sjose borrego 	uint32_t status;
8897f667e74Sjose borrego 
8902a2cfba0SGordon Ross 	status = smb_sam_usr_groups(token->tkn_user.i_sid,
8912a2cfba0SGordon Ross 	    &token->tkn_win_grps);
8922a2cfba0SGordon Ross 	if (status != NT_STATUS_SUCCESS)
8937f667e74Sjose borrego 		return (status);
8947f667e74Sjose borrego 
8952a2cfba0SGordon Ross 	status = smb_wka_token_groups(token->tkn_flags, &token->tkn_win_grps);
8967f667e74Sjose borrego 
8977f667e74Sjose borrego 	return (status);
8987f667e74Sjose borrego }
8997f667e74Sjose borrego 
9007f667e74Sjose borrego /*
9017f667e74Sjose borrego  * Converts groups information in the returned structure by domain controller
9027f667e74Sjose borrego  * (info3) to an internal representation (gids)
9037f667e74Sjose borrego  */
9047f667e74Sjose borrego static uint32_t
netr_setup_domain_groups(struct netr_validation_info3 * info3,smb_ids_t * gids)9057f667e74Sjose borrego netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
9067f667e74Sjose borrego {
9077f667e74Sjose borrego 	smb_sid_t *domain_sid;
9087f667e74Sjose borrego 	smb_id_t *ids;
9097f667e74Sjose borrego 	int i, total_cnt;
9107f667e74Sjose borrego 
9117f667e74Sjose borrego 	if ((i = info3->GroupCount) == 0)
9127f667e74Sjose borrego 		i++;
9137f667e74Sjose borrego 	i += info3->SidCount;
9147f667e74Sjose borrego 
9157f667e74Sjose borrego 	total_cnt = gids->i_cnt + i;
9167f667e74Sjose borrego 
9177f667e74Sjose borrego 	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
9187f667e74Sjose borrego 	if (gids->i_ids == NULL)
9197f667e74Sjose borrego 		return (NT_STATUS_NO_MEMORY);
9207f667e74Sjose borrego 
9217f667e74Sjose borrego 	domain_sid = (smb_sid_t *)info3->LogonDomainId;
9227f667e74Sjose borrego 
9237f667e74Sjose borrego 	ids = gids->i_ids + gids->i_cnt;
9247f667e74Sjose borrego 	for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
9257f667e74Sjose borrego 		ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
9267f667e74Sjose borrego 		if (ids->i_sid == NULL)
9277f667e74Sjose borrego 			return (NT_STATUS_NO_MEMORY);
9287f667e74Sjose borrego 
9297f667e74Sjose borrego 		ids->i_attrs = info3->GroupIds[i].attributes;
9307f667e74Sjose borrego 	}
9317f667e74Sjose borrego 
9327f667e74Sjose borrego 	if (info3->GroupCount == 0) {
9337f667e74Sjose borrego 		/*
9347f667e74Sjose borrego 		 * if there's no global group should add the primary group.
9357f667e74Sjose borrego 		 */
9367f667e74Sjose borrego 		ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
9377f667e74Sjose borrego 		if (ids->i_sid == NULL)
9387f667e74Sjose borrego 			return (NT_STATUS_NO_MEMORY);
9397f667e74Sjose borrego 
9407f667e74Sjose borrego 		ids->i_attrs = 0x7;
9417f667e74Sjose borrego 		gids->i_cnt++;
9427f667e74Sjose borrego 		ids++;
9437f667e74Sjose borrego 	}
9447f667e74Sjose borrego 
9457f667e74Sjose borrego 	/* Add the extra SIDs */
9467f667e74Sjose borrego 	for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
9477f667e74Sjose borrego 		ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
9487f667e74Sjose borrego 		if (ids->i_sid == NULL)
9497f667e74Sjose borrego 			return (NT_STATUS_NO_MEMORY);
9507f667e74Sjose borrego 
9517f667e74Sjose borrego 		ids->i_attrs = info3->ExtraSids[i].attributes;
9527f667e74Sjose borrego 	}
9537f667e74Sjose borrego 
9547f667e74Sjose borrego 	return (NT_STATUS_SUCCESS);
9557f667e74Sjose borrego }
9567f667e74Sjose borrego 
9572a2cfba0SGordon Ross /*
9582a2cfba0SGordon Ross  * Converts additional "resource" groups (from krb5_validation_info)
9592a2cfba0SGordon Ross  * into the internal representation (gids), appending to the list
9602a2cfba0SGordon Ross  * already put in place by netr_setup_domain_groups().
9612a2cfba0SGordon Ross  */
netr_setup_krb5res_groups(struct krb5_validation_info * info,smb_ids_t * gids)9622a2cfba0SGordon Ross static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *info,
9632a2cfba0SGordon Ross     smb_ids_t *gids)
9642a2cfba0SGordon Ross {
9652a2cfba0SGordon Ross 	smb_sid_t *domain_sid;
9662a2cfba0SGordon Ross 	smb_id_t *ids;
9672a2cfba0SGordon Ross 	int i, total_cnt;
9682a2cfba0SGordon Ross 
9692a2cfba0SGordon Ross 	total_cnt = gids->i_cnt + info->rg_rid_cnt;
9702a2cfba0SGordon Ross 
9712a2cfba0SGordon Ross 	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
9722a2cfba0SGordon Ross 	if (gids->i_ids == NULL)
9732a2cfba0SGordon Ross 		return (NT_STATUS_NO_MEMORY);
9742a2cfba0SGordon Ross 
9752a2cfba0SGordon Ross 	domain_sid = (smb_sid_t *)info->rg_dom_sid;
9762a2cfba0SGordon Ross 
9772a2cfba0SGordon Ross 	ids = gids->i_ids + gids->i_cnt;
9782a2cfba0SGordon Ross 	for (i = 0; i < info->rg_rid_cnt; i++, gids->i_cnt++, ids++) {
9792a2cfba0SGordon Ross 		ids->i_sid = smb_sid_splice(domain_sid, info->rg_rids[i].rid);
9802a2cfba0SGordon Ross 		if (ids->i_sid == NULL)
9812a2cfba0SGordon Ross 			return (NT_STATUS_NO_MEMORY);
9822a2cfba0SGordon Ross 		ids->i_attrs = info->rg_rids[i].attributes;
9832a2cfba0SGordon Ross 	}
9842a2cfba0SGordon Ross 
9852a2cfba0SGordon Ross 	return (0);
9862a2cfba0SGordon Ross }
987