112b65585SGordon Ross /*
212b65585SGordon Ross  * CDDL HEADER START
312b65585SGordon Ross  *
412b65585SGordon Ross  * The contents of this file are subject to the terms of the
512b65585SGordon Ross  * Common Development and Distribution License (the "License").
612b65585SGordon Ross  * You may not use this file except in compliance with the License.
712b65585SGordon Ross  *
812b65585SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912b65585SGordon Ross  * or http://www.opensolaris.org/os/licensing.
1012b65585SGordon Ross  * See the License for the specific language governing permissions
1112b65585SGordon Ross  * and limitations under the License.
1212b65585SGordon Ross  *
1312b65585SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
1412b65585SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512b65585SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
1612b65585SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
1712b65585SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
1812b65585SGordon Ross  *
1912b65585SGordon Ross  * CDDL HEADER END
2012b65585SGordon Ross  */
2112b65585SGordon Ross /*
2212b65585SGordon Ross  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23e3d9e7f3SGordon Ross  * Copyright 2015-2021 Tintri by DDN, Inc. All rights reserved.
242d0c20a0SMatt Barden  * Copyright 2022-2023 RackTop Systems, Inc.
2512b65585SGordon Ross  */
2612b65585SGordon Ross 
2712b65585SGordon Ross /*
2812b65585SGordon Ross  * Authentication support for SMB session setup
2912b65585SGordon Ross  */
3012b65585SGordon Ross 
3112b65585SGordon Ross #include <sys/types.h>
3212b65585SGordon Ross #include <sys/sid.h>
3312b65585SGordon Ross #include <sys/priv_names.h>
3412b65585SGordon Ross #include <sys/socket.h>
3512b65585SGordon Ross #include <sys/un.h>
3612b65585SGordon Ross #include <netinet/in.h>
3712b65585SGordon Ross #include <smbsrv/smb_idmap.h>
3812b65585SGordon Ross #include <smbsrv/smb_kproto.h>
3912b65585SGordon Ross #include <smbsrv/smb_token.h>
404e065a9fSAlexander Stetsenko #include <smbsrv/smb2_kproto.h>
4112b65585SGordon Ross 
42b210fedeSGordon Ross static uint32_t smb_authsock_open(smb_request_t *);
4312b65585SGordon Ross static int smb_authsock_send(ksocket_t, void *, size_t);
4412b65585SGordon Ross static int smb_authsock_recv(ksocket_t, void *, size_t);
45b210fedeSGordon Ross static uint32_t smb_authsock_sendrecv(smb_request_t *, smb_lsa_msg_hdr_t *hdr,
4612b65585SGordon Ross 				void *sndbuf, void **recvbuf);
4712b65585SGordon Ross /* void smb_authsock_close(smb_user_t *); kproto.h */
4812b65585SGordon Ross 
4912b65585SGordon Ross static uint32_t smb_auth_do_clinfo(smb_request_t *);
5012b65585SGordon Ross static uint32_t smb_auth_do_oldreq(smb_request_t *);
5112b65585SGordon Ross static uint32_t smb_auth_get_token(smb_request_t *);
5212b65585SGordon Ross static uint32_t smb_priv_xlate(smb_token_t *);
5312b65585SGordon Ross 
5412b65585SGordon Ross /*
5512b65585SGordon Ross  * Handle old-style session setup (non-extended security)
56811599a4SMatt Barden  * Note: Used only by SMB1
5712b65585SGordon Ross  *
5812b65585SGordon Ross  * The user information is passed to smbd for authentication.
5912b65585SGordon Ross  * If smbd can authenticate the user an access token is returned and we
6012b65585SGordon Ross  * generate a cred and new user based on the token.
6112b65585SGordon Ross  */
6212b65585SGordon Ross int
smb_authenticate_old(smb_request_t * sr)6312b65585SGordon Ross smb_authenticate_old(smb_request_t *sr)
6412b65585SGordon Ross {
6512b65585SGordon Ross 	smb_user_t	*user = NULL;
6612b65585SGordon Ross 	uint32_t	status;
6712b65585SGordon Ross 
6812b65585SGordon Ross 	user = smb_user_new(sr->session);
6912b65585SGordon Ross 	if (user == NULL)
7012b65585SGordon Ross 		return (NT_STATUS_TOO_MANY_SESSIONS);
7112b65585SGordon Ross 
7212b65585SGordon Ross 	/* user cleanup in smb_request_free */
7312b65585SGordon Ross 	sr->uid_user = user;
7412b65585SGordon Ross 	sr->smb_uid = user->u_uid;
75811599a4SMatt Barden 	sr->smb2_ssnid = 0;
7612b65585SGordon Ross 
7712b65585SGordon Ross 	/*
7812b65585SGordon Ross 	 * Open a connection to the local logon service.
7912b65585SGordon Ross 	 * If we can't, it may be busy, or not running.
8012b65585SGordon Ross 	 * Don't log here - this may be frequent.
8112b65585SGordon Ross 	 */
82b210fedeSGordon Ross 	if ((status = smb_authsock_open(sr)) != 0)
8312b65585SGordon Ross 		goto errout;
8412b65585SGordon Ross 
8512b65585SGordon Ross 	/*
8612b65585SGordon Ross 	 * Tell the auth. svc who this client is.
8712b65585SGordon Ross 	 */
8812b65585SGordon Ross 	if ((status = smb_auth_do_clinfo(sr)) != 0)
8912b65585SGordon Ross 		goto errout;
9012b65585SGordon Ross 
9112b65585SGordon Ross 	/*
9212b65585SGordon Ross 	 * Authentication proper
9312b65585SGordon Ross 	 */
9412b65585SGordon Ross 	if ((status = smb_auth_do_oldreq(sr)) != 0)
9512b65585SGordon Ross 		goto errout;
9612b65585SGordon Ross 
9712b65585SGordon Ross 	/*
9812b65585SGordon Ross 	 * Get the final auth. token.
9912b65585SGordon Ross 	 */
10012b65585SGordon Ross 	if ((status = smb_auth_get_token(sr)) != 0)
10112b65585SGordon Ross 		goto errout;
10212b65585SGordon Ross 
10312b65585SGordon Ross 	return (0);
10412b65585SGordon Ross 
10512b65585SGordon Ross errout:
10612b65585SGordon Ross 	smb_user_logoff(user);
10712b65585SGordon Ross 	return (status);
10812b65585SGordon Ross }
10912b65585SGordon Ross 
11012b65585SGordon Ross /*
11112b65585SGordon Ross  * Build an authentication request message and
11212b65585SGordon Ross  * send it to the local logon service.
11312b65585SGordon Ross  */
11412b65585SGordon Ross static uint32_t
smb_auth_do_oldreq(smb_request_t * sr)11512b65585SGordon Ross smb_auth_do_oldreq(smb_request_t *sr)
11612b65585SGordon Ross {
11712b65585SGordon Ross 	smb_lsa_msg_hdr_t	msg_hdr;
11812b65585SGordon Ross 	smb_logon_t	user_info;
11912b65585SGordon Ross 	XDR		xdrs;
12012b65585SGordon Ross 	smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
12112b65585SGordon Ross 	void		*sbuf = NULL;
12212b65585SGordon Ross 	void		*rbuf = NULL;
12312b65585SGordon Ross 	uint32_t	slen = 0;
12412b65585SGordon Ross 	uint32_t	rlen = 0;
12512b65585SGordon Ross 	uint32_t	status;
12612b65585SGordon Ross 	bool_t		ok;
12712b65585SGordon Ross 
12812b65585SGordon Ross 	bzero(&user_info, sizeof (smb_logon_t));
12912b65585SGordon Ross 
13012b65585SGordon Ross 	user_info.lg_level = NETR_NETWORK_LOGON;
13112b65585SGordon Ross 	user_info.lg_username = sinfo->ssi_user;
13212b65585SGordon Ross 	user_info.lg_domain = sinfo->ssi_domain;
13312b65585SGordon Ross 	user_info.lg_workstation = sr->session->workstation;
13412b65585SGordon Ross 	user_info.lg_clnt_ipaddr = sr->session->ipaddr;
13512b65585SGordon Ross 	user_info.lg_local_ipaddr = sr->session->local_ipaddr;
13612b65585SGordon Ross 	user_info.lg_local_port = sr->session->s_local_port;
13712b65585SGordon Ross 	user_info.lg_challenge_key.val = sr->session->challenge_key;
13812b65585SGordon Ross 	user_info.lg_challenge_key.len = sr->session->challenge_len;
13912b65585SGordon Ross 	user_info.lg_nt_password.val = sinfo->ssi_ntpwd;
14012b65585SGordon Ross 	user_info.lg_nt_password.len = sinfo->ssi_ntpwlen;
14112b65585SGordon Ross 	user_info.lg_lm_password.val = sinfo->ssi_lmpwd;
14212b65585SGordon Ross 	user_info.lg_lm_password.len = sinfo->ssi_lmpwlen;
14312b65585SGordon Ross 	user_info.lg_native_os = sr->session->native_os;
14412b65585SGordon Ross 	user_info.lg_native_lm = sr->session->native_lm;
14512b65585SGordon Ross 	/* lg_flags? */
14612b65585SGordon Ross 
14712b65585SGordon Ross 	slen = xdr_sizeof(smb_logon_xdr, &user_info);
14812b65585SGordon Ross 	sbuf = kmem_alloc(slen, KM_SLEEP);
14912b65585SGordon Ross 	xdrmem_create(&xdrs, sbuf, slen, XDR_ENCODE);
15012b65585SGordon Ross 	ok = smb_logon_xdr(&xdrs, &user_info);
15112b65585SGordon Ross 	xdr_destroy(&xdrs);
15212b65585SGordon Ross 	if (!ok) {
15312b65585SGordon Ross 		status = RPC_NT_BAD_STUB_DATA;
15412b65585SGordon Ross 		goto out;
15512b65585SGordon Ross 	}
15612b65585SGordon Ross 
15712b65585SGordon Ross 	msg_hdr.lmh_msgtype = LSA_MTYPE_OLDREQ;
15812b65585SGordon Ross 	msg_hdr.lmh_msglen = slen;
159b210fedeSGordon Ross 	status = smb_authsock_sendrecv(sr, &msg_hdr, sbuf, &rbuf);
16012b65585SGordon Ross 	if (status != 0)
16112b65585SGordon Ross 		goto out;
16212b65585SGordon Ross 	rlen = msg_hdr.lmh_msglen;
16312b65585SGordon Ross 	kmem_free(sbuf, slen);
16412b65585SGordon Ross 	sbuf = NULL;
16512b65585SGordon Ross 
16612b65585SGordon Ross 	/*
16712b65585SGordon Ross 	 * Decode the response message.
16812b65585SGordon Ross 	 */
16912b65585SGordon Ross 	switch (msg_hdr.lmh_msgtype) {
17012b65585SGordon Ross 
17112b65585SGordon Ross 	case LSA_MTYPE_OK:
17212b65585SGordon Ross 		status = 0;
17312b65585SGordon Ross 		break;
17412b65585SGordon Ross 
17512b65585SGordon Ross 	case LSA_MTYPE_ERROR:
17612b65585SGordon Ross 		if (rlen == sizeof (smb_lsa_eresp_t)) {
17712b65585SGordon Ross 			smb_lsa_eresp_t *ler = rbuf;
17812b65585SGordon Ross 			status = ler->ler_ntstatus;
17912b65585SGordon Ross 			break;
18012b65585SGordon Ross 		}
18112b65585SGordon Ross 		/* FALLTHROUGH */
18212b65585SGordon Ross 
18312b65585SGordon Ross 	default:	/*  Bogus message type */
18412b65585SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
18512b65585SGordon Ross 		break;
18612b65585SGordon Ross 	}
18712b65585SGordon Ross 
18812b65585SGordon Ross out:
18912b65585SGordon Ross 	if (rbuf != NULL)
19012b65585SGordon Ross 		kmem_free(rbuf, rlen);
19112b65585SGordon Ross 	if (sbuf != NULL)
19212b65585SGordon Ross 		kmem_free(sbuf, slen);
19312b65585SGordon Ross 
19412b65585SGordon Ross 	return (status);
19512b65585SGordon Ross }
19612b65585SGordon Ross 
19712b65585SGordon Ross /*
19812b65585SGordon Ross  * Handle new-style (extended security) session setup.
19912b65585SGordon Ross  * Returns zero: success, non-zero: error (value not used)
20012b65585SGordon Ross  *
20112b65585SGordon Ross  * Note that this style uses a sequence of session setup requests,
20212b65585SGordon Ross  * where the first has SMB UID=0, and subsequent requests in the
20312b65585SGordon Ross  * same authentication sequence have the SMB UID returned for that
20412b65585SGordon Ross  * first request.  We allocate a USER object when the first request
20512b65585SGordon Ross  * in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that
20612b65585SGordon Ross  * to maintain state between requests in this sequence.  The state
20712b65585SGordon Ross  * for one sequence includes an AF_UNIX "authsock" connection to the
20812b65585SGordon Ross  * user-space smbd.  The neat part of this is: in smbd, the handler
20912b65585SGordon Ross  * for the server-side of one authsock gets only request specific to
21012b65585SGordon Ross  * one authentication sequence, simplifying it's work immensely.
21112b65585SGordon Ross  * When the authentication sequence is finished, with either success
21212b65585SGordon Ross  * or failure, the local side of the authsock is closed.
21312b65585SGordon Ross  *
21412b65585SGordon Ross  * As with the old-style authentication, if we succeed, then the
21512b65585SGordon Ross  * last message from smbd will be an smb_token_t encoding the
21612b65585SGordon Ross  * information about the new user.
21712b65585SGordon Ross  *
21812b65585SGordon Ross  * Outline:
21912b65585SGordon Ross  * (a) On the first request (UID==0) create a USER object,
22012b65585SGordon Ross  *     and on subsequent requests, find USER by SMB UID.
22112b65585SGordon Ross  * (b) Send message / recv. response as above,
22212b65585SGordon Ross  * (c) If response says "we're done", close authsock
22312b65585SGordon Ross  *     (both success and failure must close authsock)
22412b65585SGordon Ross  */
22512b65585SGordon Ross int
smb_authenticate_ext(smb_request_t * sr)22612b65585SGordon Ross smb_authenticate_ext(smb_request_t *sr)
22712b65585SGordon Ross {
22812b65585SGordon Ross 	smb_lsa_msg_hdr_t	msg_hdr;
22912b65585SGordon Ross 	smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
23012b65585SGordon Ross 	smb_user_t	*user = NULL;
23112b65585SGordon Ross 	void		*rbuf = NULL;
23212b65585SGordon Ross 	uint32_t	rlen = 0;
23312b65585SGordon Ross 	uint32_t	status;
23412b65585SGordon Ross 
23512b65585SGordon Ross 	ASSERT(sr->uid_user == NULL);
23612b65585SGordon Ross 
23712b65585SGordon Ross 	/*
238811599a4SMatt Barden 	 * Paranoid:  While finding/creating the user object, make sure
239811599a4SMatt Barden 	 * SMB2 ignores smb_uid, and SMB1 ignores smb2_ssnid.  The
240811599a4SMatt Barden 	 * logic below assumes the "other" one is always zero; both
241811599a4SMatt Barden 	 * the "first request" tests and smb_session_lookup_uid_st.
242811599a4SMatt Barden 	 */
243811599a4SMatt Barden 	if (sr->session->dialect >= SMB_VERS_2_BASE) {
244811599a4SMatt Barden 		/* SMB2+ ignores smb_uid */
245811599a4SMatt Barden 		ASSERT(sr->smb_uid == 0);
246811599a4SMatt Barden 		sr->smb_uid = 0;
247811599a4SMatt Barden 	} else {
248811599a4SMatt Barden 		/* SMB1 ignores smb2_ssnid */
249811599a4SMatt Barden 		ASSERT(sr->smb2_ssnid == 0);
250811599a4SMatt Barden 		sr->smb2_ssnid = 0;
251811599a4SMatt Barden 	}
252811599a4SMatt Barden 
253811599a4SMatt Barden 	/*
254811599a4SMatt Barden 	 * On the first request (UID/ssnid==0) create a USER object.
255811599a4SMatt Barden 	 * On subsequent requests (UID/ssnid!=0) find the USER object.
25612b65585SGordon Ross 	 * Either way, sr->uid_user is set, so our ref. on the
25712b65585SGordon Ross 	 * user object is dropped during normal cleanup work
25812b65585SGordon Ross 	 * for the smb_request (sr).  Ditto u_authsock.
25912b65585SGordon Ross 	 */
260811599a4SMatt Barden 	if (sr->smb2_ssnid == 0 && sr->smb_uid == 0) {
26112b65585SGordon Ross 		user = smb_user_new(sr->session);
26212b65585SGordon Ross 		if (user == NULL)
26312b65585SGordon Ross 			return (NT_STATUS_TOO_MANY_SESSIONS);
26412b65585SGordon Ross 
26512b65585SGordon Ross 		/* user cleanup in smb_request_free */
26612b65585SGordon Ross 		sr->uid_user = user;
267811599a4SMatt Barden 		if (sr->session->dialect >= SMB_VERS_2_BASE) {
268811599a4SMatt Barden 			/* Intentionally leave smb_uid=0 for SMB2 */
269811599a4SMatt Barden 			sr->smb2_ssnid = user->u_ssnid;
270811599a4SMatt Barden 		} else {
271811599a4SMatt Barden 			/* Intentionally leave smb2_ssnid=0 for SMB1 */
272811599a4SMatt Barden 			sr->smb_uid = user->u_uid;
273811599a4SMatt Barden 		}
27412b65585SGordon Ross 
27512b65585SGordon Ross 		/*
27612b65585SGordon Ross 		 * Open a connection to the local logon service.
27712b65585SGordon Ross 		 * If we can't, it may be busy, or not running.
27812b65585SGordon Ross 		 * Don't log here - this may be frequent.
27912b65585SGordon Ross 		 */
280b210fedeSGordon Ross 		if ((status = smb_authsock_open(sr)) != 0)
28112b65585SGordon Ross 			goto errout;
28212b65585SGordon Ross 
28312b65585SGordon Ross 		/*
28412b65585SGordon Ross 		 * Tell the auth. svc who this client is.
28512b65585SGordon Ross 		 */
28612b65585SGordon Ross 		if ((status = smb_auth_do_clinfo(sr)) != 0)
28712b65585SGordon Ross 			goto errout;
28812b65585SGordon Ross 
28912b65585SGordon Ross 		msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST;
2904e065a9fSAlexander Stetsenko 
2914e065a9fSAlexander Stetsenko 		if (sr->session->dialect >= SMB_VERS_3_11) {
2924e065a9fSAlexander Stetsenko 			if (smb31_preauth_sha512_calc(sr, &sr->command,
2934e065a9fSAlexander Stetsenko 			    sr->session->smb31_preauth_hashval,
2944e065a9fSAlexander Stetsenko 			    user->u_preauth_hashval) != 0)
2954e065a9fSAlexander Stetsenko 				cmn_err(CE_WARN, "(2) Preauth hash calculation "
2964e065a9fSAlexander Stetsenko 				    "failed");
2974e065a9fSAlexander Stetsenko 		}
29812b65585SGordon Ross 	} else {
29912b65585SGordon Ross 		user = smb_session_lookup_uid_st(sr->session,
300811599a4SMatt Barden 		    sr->smb2_ssnid, sr->smb_uid, SMB_USER_STATE_LOGGING_ON);
30112b65585SGordon Ross 		if (user == NULL)
30212b65585SGordon Ross 			return (NT_STATUS_USER_SESSION_DELETED);
30312b65585SGordon Ross 
30412b65585SGordon Ross 		/* user cleanup in smb_request_free */
30512b65585SGordon Ross 		sr->uid_user = user;
30612b65585SGordon Ross 
30712b65585SGordon Ross 		msg_hdr.lmh_msgtype = LSA_MTYPE_ESNEXT;
3084e065a9fSAlexander Stetsenko 
3094e065a9fSAlexander Stetsenko 		if (sr->session->dialect >= SMB_VERS_3_11) {
3104e065a9fSAlexander Stetsenko 			if (smb31_preauth_sha512_calc(sr, &sr->command,
3114e065a9fSAlexander Stetsenko 			    user->u_preauth_hashval,
3124e065a9fSAlexander Stetsenko 			    user->u_preauth_hashval) != 0)
3134e065a9fSAlexander Stetsenko 				cmn_err(CE_WARN, "(4) Preauth hash calculation "
3144e065a9fSAlexander Stetsenko 				    "failed");
3154e065a9fSAlexander Stetsenko 		}
31612b65585SGordon Ross 	}
31712b65585SGordon Ross 
31812b65585SGordon Ross 	/*
31912b65585SGordon Ross 	 * Wrap the "security blob" with our header
32012b65585SGordon Ross 	 * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT)
32112b65585SGordon Ross 	 * and send it up the authsock with either
32212b65585SGordon Ross 	 */
32312b65585SGordon Ross 	msg_hdr.lmh_msglen = sinfo->ssi_iseclen;
324b210fedeSGordon Ross 	status = smb_authsock_sendrecv(sr, &msg_hdr,
32512b65585SGordon Ross 	    sinfo->ssi_isecblob, &rbuf);
32612b65585SGordon Ross 	if (status != 0)
32712b65585SGordon Ross 		goto errout;
32812b65585SGordon Ross 	rlen = msg_hdr.lmh_msglen;
32912b65585SGordon Ross 
33012b65585SGordon Ross 	/*
33112b65585SGordon Ross 	 * Decode the response message.
33212b65585SGordon Ross 	 * Note: allocated rbuf
33312b65585SGordon Ross 	 */
33412b65585SGordon Ross 	switch (msg_hdr.lmh_msgtype) {
33512b65585SGordon Ross 
33612b65585SGordon Ross 	case LSA_MTYPE_ES_CONT:
33712b65585SGordon Ross 		sinfo->ssi_oseclen = (uint16_t)rlen;
33812b65585SGordon Ross 		sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
33912b65585SGordon Ross 		bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
34012b65585SGordon Ross 		/*
34112b65585SGordon Ross 		 * This is not really an error, but tells the client
34212b65585SGordon Ross 		 * it should send another session setup request.
34312b65585SGordon Ross 		 */
34412b65585SGordon Ross 		status = NT_STATUS_MORE_PROCESSING_REQUIRED;
34512b65585SGordon Ross 		break;
34612b65585SGordon Ross 
34712b65585SGordon Ross 	case LSA_MTYPE_ES_DONE:
34812b65585SGordon Ross 		sinfo->ssi_oseclen = (uint16_t)rlen;
34912b65585SGordon Ross 		sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
35012b65585SGordon Ross 		bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
35112b65585SGordon Ross 		sinfo->ssi_ntpwlen = 0;
35212b65585SGordon Ross 		/*
35312b65585SGordon Ross 		 * Get the final auth. token.
35412b65585SGordon Ross 		 */
35512b65585SGordon Ross 		status = smb_auth_get_token(sr);
35612b65585SGordon Ross 		break;
35712b65585SGordon Ross 
35812b65585SGordon Ross 	case LSA_MTYPE_ERROR:
35912b65585SGordon Ross 		/*
36012b65585SGordon Ross 		 * Authentication failed.  Return the error
36112b65585SGordon Ross 		 * provided in the reply message.
36212b65585SGordon Ross 		 */
36312b65585SGordon Ross 		if (rlen == sizeof (smb_lsa_eresp_t)) {
36412b65585SGordon Ross 			smb_lsa_eresp_t *ler = rbuf;
36512b65585SGordon Ross 			status = ler->ler_ntstatus;
36612b65585SGordon Ross 			goto errout;
36712b65585SGordon Ross 		}
36812b65585SGordon Ross 		/* FALLTHROUGH */
36912b65585SGordon Ross 
37012b65585SGordon Ross 	default:	/*  Bogus message type */
37112b65585SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
37212b65585SGordon Ross 		goto errout;
37312b65585SGordon Ross 	}
37412b65585SGordon Ross 
37512b65585SGordon Ross 	if (status != 0 && status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
37612b65585SGordon Ross 	errout:
37712b65585SGordon Ross 		smb_user_logoff(user);
37812b65585SGordon Ross 	}
37912b65585SGordon Ross 
38012b65585SGordon Ross 	if (rbuf != NULL)
38112b65585SGordon Ross 		kmem_free(rbuf, rlen);
38212b65585SGordon Ross 
38312b65585SGordon Ross 	return (status);
38412b65585SGordon Ross }
38512b65585SGordon Ross 
38612b65585SGordon Ross /*
38712b65585SGordon Ross  * Send the "client info" up to the auth service.
38812b65585SGordon Ross  */
38912b65585SGordon Ross static uint32_t
smb_auth_do_clinfo(smb_request_t * sr)39012b65585SGordon Ross smb_auth_do_clinfo(smb_request_t *sr)
39112b65585SGordon Ross {
39212b65585SGordon Ross 	smb_lsa_msg_hdr_t msg_hdr;
39312b65585SGordon Ross 	smb_lsa_clinfo_t clinfo;
39412b65585SGordon Ross 	void *rbuf = NULL;
39512b65585SGordon Ross 	uint32_t status;
39612b65585SGordon Ross 
39712b65585SGordon Ross 	/*
39812b65585SGordon Ross 	 * Send a message with info. about the client
39912b65585SGordon Ross 	 * (IP address, etc) and wait for an ACK.
40012b65585SGordon Ross 	 */
40112b65585SGordon Ross 	msg_hdr.lmh_msgtype = LSA_MTYPE_CLINFO;
40212b65585SGordon Ross 	msg_hdr.lmh_msglen = sizeof (clinfo);
40312b65585SGordon Ross 	clinfo.lci_clnt_ipaddr = sr->session->ipaddr;
40412b65585SGordon Ross 	(void) memcpy(clinfo.lci_challenge_key,
40512b65585SGordon Ross 	    sr->session->challenge_key,
40612b65585SGordon Ross 	    sizeof (clinfo.lci_challenge_key));
407b210fedeSGordon Ross 	status = smb_authsock_sendrecv(sr, &msg_hdr, &clinfo, &rbuf);
40812b65585SGordon Ross 	/* We don't use this response. */
40912b65585SGordon Ross 	if (rbuf != NULL) {
41012b65585SGordon Ross 		kmem_free(rbuf, msg_hdr.lmh_msglen);
41112b65585SGordon Ross 		rbuf = NULL;
41212b65585SGordon Ross 	}
41312b65585SGordon Ross 
41412b65585SGordon Ross 	return (status);
41512b65585SGordon Ross }
41612b65585SGordon Ross 
41712b65585SGordon Ross /*
41812b65585SGordon Ross  * After a successful authentication, ask the authsvc to
41912b65585SGordon Ross  * send us the authentication token.
42012b65585SGordon Ross  */
42112b65585SGordon Ross static uint32_t
smb_auth_get_token(smb_request_t * sr)42212b65585SGordon Ross smb_auth_get_token(smb_request_t *sr)
42312b65585SGordon Ross {
42412b65585SGordon Ross 	smb_lsa_msg_hdr_t msg_hdr;
42512b65585SGordon Ross 	XDR		xdrs;
42612b65585SGordon Ross 	smb_user_t	*user = sr->uid_user;
42712b65585SGordon Ross 	smb_token_t	*token = NULL;
42812b65585SGordon Ross 	cred_t		*cr = NULL;
42912b65585SGordon Ross 	void		*rbuf = NULL;
43012b65585SGordon Ross 	uint32_t	rlen = 0;
43112b65585SGordon Ross 	uint32_t	privileges;
43212b65585SGordon Ross 	uint32_t	status;
43312b65585SGordon Ross 	bool_t		ok;
43412b65585SGordon Ross 
43512b65585SGordon Ross 	msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK;
43612b65585SGordon Ross 	msg_hdr.lmh_msglen = 0;
43712b65585SGordon Ross 
438b210fedeSGordon Ross 	status = smb_authsock_sendrecv(sr, &msg_hdr, NULL, &rbuf);
43912b65585SGordon Ross 	if (status != 0)
44012b65585SGordon Ross 		goto errout;
44112b65585SGordon Ross 
44212b65585SGordon Ross 	rlen = msg_hdr.lmh_msglen;
44312b65585SGordon Ross 	switch (msg_hdr.lmh_msgtype) {
44412b65585SGordon Ross 
44512b65585SGordon Ross 	case LSA_MTYPE_TOKEN:
44612b65585SGordon Ross 		status = 0;
44712b65585SGordon Ross 		break;
44812b65585SGordon Ross 
44912b65585SGordon Ross 	case LSA_MTYPE_ERROR:
45012b65585SGordon Ross 		if (rlen == sizeof (smb_lsa_eresp_t)) {
45112b65585SGordon Ross 			smb_lsa_eresp_t *ler = rbuf;
45212b65585SGordon Ross 			status = ler->ler_ntstatus;
45312b65585SGordon Ross 			goto errout;
45412b65585SGordon Ross 		}
45512b65585SGordon Ross 		/* FALLTHROUGH */
45612b65585SGordon Ross 
45712b65585SGordon Ross 	default:
45812b65585SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
45912b65585SGordon Ross 		goto errout;
46012b65585SGordon Ross 	}
46112b65585SGordon Ross 
46212b65585SGordon Ross 	/*
46312b65585SGordon Ross 	 * Authenticated.  Decode the LSA_MTYPE_TOKEN.
46412b65585SGordon Ross 	 */
46512b65585SGordon Ross 	xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE);
46612b65585SGordon Ross 	token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
46712b65585SGordon Ross 	ok = smb_token_xdr(&xdrs, token);
46812b65585SGordon Ross 	xdr_destroy(&xdrs);
46912b65585SGordon Ross 	if (!ok) {
47012b65585SGordon Ross 		status = RPC_NT_BAD_STUB_DATA;
47112b65585SGordon Ross 		goto errout;
47212b65585SGordon Ross 	}
47312b65585SGordon Ross 	kmem_free(rbuf, rlen);
47412b65585SGordon Ross 	rbuf = NULL;
47512b65585SGordon Ross 
47612b65585SGordon Ross 	/*
47712b65585SGordon Ross 	 * Setup the logon object.
47812b65585SGordon Ross 	 */
47912b65585SGordon Ross 	cr = smb_cred_create(token);
480e3d9e7f3SGordon Ross 	if (cr == NULL) {
481e3d9e7f3SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
48212b65585SGordon Ross 		goto errout;
483e3d9e7f3SGordon Ross 	}
48412b65585SGordon Ross 	privileges = smb_priv_xlate(token);
48512b65585SGordon Ross 	(void) smb_user_logon(user, cr,
48612b65585SGordon Ross 	    token->tkn_domain_name, token->tkn_account_name,
48712b65585SGordon Ross 	    token->tkn_flags, privileges, token->tkn_audit_sid);
48812b65585SGordon Ross 	crfree(cr);
48912b65585SGordon Ross 
4901160dcf7SMatt Barden 	/*
4912d0c20a0SMatt Barden 	 * Set Session.EncryptData so encryption can be enforced,
4922d0c20a0SMatt Barden 	 * and set up encryption keys if we have a session key.
4932d0c20a0SMatt Barden 	 * This happens even for anonymous/guest users, as Windows
4942d0c20a0SMatt Barden 	 * currently will send encrypted requests from them.
4951160dcf7SMatt Barden 	 */
4961160dcf7SMatt Barden 	if (sr->session->dialect >= SMB_VERS_3_0)
4974f0ce1daSGordon Ross 		smb3_encrypt_begin(sr->uid_user, token);
4981160dcf7SMatt Barden 
49912b65585SGordon Ross 	/*
50012b65585SGordon Ross 	 * Save the session key, and (maybe) enable signing,
50112b65585SGordon Ross 	 * but only for real logon (not ANON or GUEST).
50212b65585SGordon Ross 	 */
50312b65585SGordon Ross 	if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) {
504a90cf9f2SGordon Ross 		if (sr->session->dialect >= SMB_VERS_2_BASE) {
505c51c88bdSMatt Barden 			smb2_sign_begin(sr, token);
506a90cf9f2SGordon Ross 		} else {
507c51c88bdSMatt Barden 			smb_sign_begin(sr, token);
50812b65585SGordon Ross 		}
50912b65585SGordon Ross 	}
51012b65585SGordon Ross 
51112b65585SGordon Ross 	smb_token_free(token);
51212b65585SGordon Ross 
51312b65585SGordon Ross 	sr->user_cr = user->u_cred;
51412b65585SGordon Ross 	return (0);
51512b65585SGordon Ross 
51612b65585SGordon Ross errout:
51712b65585SGordon Ross 	if (rbuf != NULL)
51812b65585SGordon Ross 		kmem_free(rbuf, rlen);
51912b65585SGordon Ross 	if (token != NULL)
52012b65585SGordon Ross 		smb_token_free(token);
52112b65585SGordon Ross 	return (status);
52212b65585SGordon Ross }
52312b65585SGordon Ross 
52412b65585SGordon Ross /*
52512b65585SGordon Ross  * Tokens are allocated in the kernel via XDR.
52612b65585SGordon Ross  * Call xdr_free before freeing the token structure.
52712b65585SGordon Ross  */
52812b65585SGordon Ross void
smb_token_free(smb_token_t * token)52912b65585SGordon Ross smb_token_free(smb_token_t *token)
53012b65585SGordon Ross {
53112b65585SGordon Ross 	if (token != NULL) {
53212b65585SGordon Ross 		xdr_free(smb_token_xdr, (char *)token);
53312b65585SGordon Ross 		kmem_free(token, sizeof (smb_token_t));
53412b65585SGordon Ross 	}
53512b65585SGordon Ross }
53612b65585SGordon Ross 
53712b65585SGordon Ross /*
53812b65585SGordon Ross  * Convert access token privileges to local definitions.
53912b65585SGordon Ross  */
54012b65585SGordon Ross static uint32_t
smb_priv_xlate(smb_token_t * token)54112b65585SGordon Ross smb_priv_xlate(smb_token_t *token)
54212b65585SGordon Ross {
54312b65585SGordon Ross 	uint32_t	privileges = 0;
54412b65585SGordon Ross 
545cc3780e6SGordon Ross 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
546cc3780e6SGordon Ross 		privileges |= SMB_USER_PRIV_SECURITY;
547cc3780e6SGordon Ross 
548cc3780e6SGordon Ross 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
549cc3780e6SGordon Ross 		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
550cc3780e6SGordon Ross 
55112b65585SGordon Ross 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
55212b65585SGordon Ross 		privileges |= SMB_USER_PRIV_BACKUP;
55312b65585SGordon Ross 
55412b65585SGordon Ross 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
55512b65585SGordon Ross 		privileges |= SMB_USER_PRIV_RESTORE;
55612b65585SGordon Ross 
557cc3780e6SGordon Ross 	if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID))
558cc3780e6SGordon Ross 		privileges |= SMB_USER_PRIV_CHANGE_NOTIFY;
55912b65585SGordon Ross 
5600292c176SMatt Barden 	if (smb_token_query_privilege(token, SE_READ_FILE_LUID))
5610292c176SMatt Barden 		privileges |= SMB_USER_PRIV_READ_FILE;
5620292c176SMatt Barden 
5630292c176SMatt Barden 	if (smb_token_query_privilege(token, SE_WRITE_FILE_LUID))
5640292c176SMatt Barden 		privileges |= SMB_USER_PRIV_WRITE_FILE;
5650292c176SMatt Barden 
56612b65585SGordon Ross 	return (privileges);
56712b65585SGordon Ross }
56812b65585SGordon Ross 
569b210fedeSGordon Ross /*
570b210fedeSGordon Ross  * Unblock a request that might be blocked reading some
571b210fedeSGordon Ross  * authentication socket.  This can happen when either the
572b210fedeSGordon Ross  * client cancels a session setup or closes the connection.
573b210fedeSGordon Ross  */
574b210fedeSGordon Ross static void
smb_authsock_cancel(smb_request_t * sr)575b210fedeSGordon Ross smb_authsock_cancel(smb_request_t *sr)
576b210fedeSGordon Ross {
577b210fedeSGordon Ross 	smb_user_t *user = sr->cancel_arg2;
578b210fedeSGordon Ross 	ksocket_t authsock = NULL;
579b210fedeSGordon Ross 
580b210fedeSGordon Ross 	ASSERT(user == sr->uid_user);
581b210fedeSGordon Ross 
582b210fedeSGordon Ross 	/*
583b210fedeSGordon Ross 	 * Check user state, and get a hold on the auth socket.
584b210fedeSGordon Ross 	 */
585b210fedeSGordon Ross 	mutex_enter(&user->u_mutex);
586b210fedeSGordon Ross 	if (user->u_state == SMB_USER_STATE_LOGGING_ON) {
587b210fedeSGordon Ross 		if ((authsock = user->u_authsock) != NULL)
588b210fedeSGordon Ross 			ksocket_hold(authsock);
589b210fedeSGordon Ross 	}
590b210fedeSGordon Ross 	mutex_exit(&user->u_mutex);
591b210fedeSGordon Ross 
592b210fedeSGordon Ross 	if (authsock != NULL) {
593b210fedeSGordon Ross 		(void) ksocket_shutdown(authsock, SHUT_RDWR, sr->user_cr);
594b210fedeSGordon Ross 		ksocket_rele(authsock);
595b210fedeSGordon Ross 	}
596b210fedeSGordon Ross }
597b210fedeSGordon Ross 
59812b65585SGordon Ross /*
59912b65585SGordon Ross  * Send/recv a request/reply sequence on the auth socket.
60012b65585SGordon Ross  * Returns zero or an NT status.
60112b65585SGordon Ross  *
60212b65585SGordon Ross  * Errors here mean we can't communicate with the smbd_authsvc.
60312b65585SGordon Ross  * With limited authsock instances, this should be rare.
60412b65585SGordon Ross  */
60512b65585SGordon Ross static uint32_t
smb_authsock_sendrecv(smb_request_t * sr,smb_lsa_msg_hdr_t * hdr,void * sndbuf,void ** recvbuf)606b210fedeSGordon Ross smb_authsock_sendrecv(smb_request_t *sr, smb_lsa_msg_hdr_t *hdr,
6071160dcf7SMatt Barden     void *sndbuf, void **recvbuf)
60812b65585SGordon Ross {
609b210fedeSGordon Ross 	smb_user_t *user = sr->uid_user;
61012b65585SGordon Ross 	ksocket_t so;
61112b65585SGordon Ross 	uint32_t status;
61212b65585SGordon Ross 	int rc;
61312b65585SGordon Ross 
61412b65585SGordon Ross 	/*
61512b65585SGordon Ross 	 * Get a hold on the auth socket.
61612b65585SGordon Ross 	 */
61712b65585SGordon Ross 	mutex_enter(&user->u_mutex);
61812b65585SGordon Ross 	so = user->u_authsock;
61912b65585SGordon Ross 	if (so == NULL) {
62012b65585SGordon Ross 		mutex_exit(&user->u_mutex);
62112b65585SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
62212b65585SGordon Ross 	}
62312b65585SGordon Ross 	ksocket_hold(so);
62412b65585SGordon Ross 	mutex_exit(&user->u_mutex);
62512b65585SGordon Ross 
626*66b505f1SGordon Ross 	/*
627*66b505f1SGordon Ross 	 * Prepare for cancellable send/recv.
628*66b505f1SGordon Ross 	 */
629b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
630b210fedeSGordon Ross 	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
631b210fedeSGordon Ross 		mutex_exit(&sr->sr_mutex);
632b210fedeSGordon Ross 		status = NT_STATUS_CANCELLED;
633b210fedeSGordon Ross 		goto out;
634b210fedeSGordon Ross 	}
635b210fedeSGordon Ross 	sr->sr_state = SMB_REQ_STATE_WAITING_AUTH;
636b210fedeSGordon Ross 	sr->cancel_method = smb_authsock_cancel;
637b210fedeSGordon Ross 	sr->cancel_arg2 = user;
638b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
639b210fedeSGordon Ross 
640*66b505f1SGordon Ross 	/*
641*66b505f1SGordon Ross 	 * The actual send/recv work.
642*66b505f1SGordon Ross 	 */
64312b65585SGordon Ross 	rc = smb_authsock_send(so, hdr, sizeof (*hdr));
64412b65585SGordon Ross 	if (rc == 0 && hdr->lmh_msglen != 0) {
64512b65585SGordon Ross 		rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen);
64612b65585SGordon Ross 	}
647b210fedeSGordon Ross 	if (rc == 0)
648b210fedeSGordon Ross 		rc = smb_authsock_recv(so, hdr, sizeof (*hdr));
64912b65585SGordon Ross 	if (rc == 0 && hdr->lmh_msglen != 0) {
65012b65585SGordon Ross 		*recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP);
65112b65585SGordon Ross 		rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen);
65212b65585SGordon Ross 	}
65312b65585SGordon Ross 
65412b65585SGordon Ross 	switch (rc) {
65512b65585SGordon Ross 	case 0:
65612b65585SGordon Ross 		status = 0;
65712b65585SGordon Ross 		break;
65812b65585SGordon Ross 	case EIO:
65912b65585SGordon Ross 		status = RPC_NT_COMM_FAILURE;
66012b65585SGordon Ross 		break;
66112b65585SGordon Ross 	case ENOTCONN:
66212b65585SGordon Ross 		status = RPC_NT_PIPE_CLOSED;
66312b65585SGordon Ross 		break;
66412b65585SGordon Ross 	default:
66512b65585SGordon Ross 		status = RPC_NT_CALL_FAILED;
66612b65585SGordon Ross 		break;
66712b65585SGordon Ross 	}
66812b65585SGordon Ross 
669*66b505f1SGordon Ross 	/*
670*66b505f1SGordon Ross 	 * Did send/recv complete or was it cancelled?
671*66b505f1SGordon Ross 	 */
672b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
673*66b505f1SGordon Ross switch_state:
674b210fedeSGordon Ross 	switch (sr->sr_state) {
675b210fedeSGordon Ross 	case SMB_REQ_STATE_WAITING_AUTH:
676*66b505f1SGordon Ross 		/* Normal wakeup.  Keep status from above. */
677b210fedeSGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
678b210fedeSGordon Ross 		break;
679b210fedeSGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
680*66b505f1SGordon Ross 		/* cancel_method running. wait. */
681*66b505f1SGordon Ross 		cv_wait(&sr->sr_st_cv, &sr->sr_mutex);
682*66b505f1SGordon Ross 		goto switch_state;
683*66b505f1SGordon Ross 	case SMB_REQ_STATE_CANCELLED:
684b210fedeSGordon Ross 		status = NT_STATUS_CANCELLED;
685b210fedeSGordon Ross 		break;
686b210fedeSGordon Ross 	default:
687b210fedeSGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
688b210fedeSGordon Ross 		break;
689b210fedeSGordon Ross 	}
690*66b505f1SGordon Ross 	sr->cancel_method = NULL;
691*66b505f1SGordon Ross 	sr->cancel_arg2 = NULL;
692b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
693b210fedeSGordon Ross 
694b210fedeSGordon Ross out:
695b210fedeSGordon Ross 	ksocket_rele(so);
696b210fedeSGordon Ross 
697b210fedeSGordon Ross 	if (status != 0 && *recvbuf != NULL) {
698b210fedeSGordon Ross 		kmem_free(*recvbuf, hdr->lmh_msglen);
699b210fedeSGordon Ross 		*recvbuf = NULL;
700b210fedeSGordon Ross 	}
70112b65585SGordon Ross 	return (status);
70212b65585SGordon Ross }
70312b65585SGordon Ross 
70412b65585SGordon Ross /*
70512b65585SGordon Ross  * Hope this is interpreted per-zone...
70612b65585SGordon Ross  */
70712b65585SGordon Ross static struct sockaddr_un smbauth_sockname = {
70812b65585SGordon Ross 	AF_UNIX, SMB_AUTHSVC_SOCKNAME };
70912b65585SGordon Ross 
71012b65585SGordon Ross /*
71112b65585SGordon Ross  * Limit how long smb_authsock_sendrecv() will wait for a
71212b65585SGordon Ross  * response from the local authentication service.
71312b65585SGordon Ross  */
71412b65585SGordon Ross struct timeval smb_auth_recv_tmo = { 45, 0 };
71512b65585SGordon Ross 
71612b65585SGordon Ross /*
71712b65585SGordon Ross  * Also limit the time smb_authsock_sendrecv() will wait
71812b65585SGordon Ross  * trying to send a request to the authentication service.
71912b65585SGordon Ross  */
72012b65585SGordon Ross struct timeval smb_auth_send_tmo = { 15, 0 };
72112b65585SGordon Ross 
7228f70e16bSGordon Ross /*
7238f70e16bSGordon Ross  * Maximum time a user object may stay in state LOGGING_ON
7248f70e16bSGordon Ross  */
7258f70e16bSGordon Ross int smb_auth_total_tmo = 45;	/* seconds */
7268f70e16bSGordon Ross 
72712b65585SGordon Ross static uint32_t
smb_authsock_open(smb_request_t * sr)728b210fedeSGordon Ross smb_authsock_open(smb_request_t *sr)
72912b65585SGordon Ross {
730b210fedeSGordon Ross 	smb_user_t *user = sr->uid_user;
731b210fedeSGordon Ross 	smb_server_t *sv = sr->sr_server;
73212b65585SGordon Ross 	ksocket_t so = NULL;
733b210fedeSGordon Ross 	uint32_t status = 0;
73412b65585SGordon Ross 	int rc;
73512b65585SGordon Ross 
73612b65585SGordon Ross 	/*
737b210fedeSGordon Ross 	 * If the auth. service is busy, wait our turn.  This threshold
738b210fedeSGordon Ross 	 * limits the number of auth sockets we might have trying to
739b210fedeSGordon Ross 	 * communicate with the auth. service up in smbd.  Until we've
740b210fedeSGordon Ross 	 * set u_authsock, we need to "exit this threshold" in any
741b210fedeSGordon Ross 	 * error code paths after this "enter".
742b210fedeSGordon Ross 	 *
743b210fedeSGordon Ross 	 * Failure to "enter" may be frequent, so don't log.
74412b65585SGordon Ross 	 */
74512b65585SGordon Ross 	if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0)
74612b65585SGordon Ross 		return (NT_STATUS_NO_LOGON_SERVERS);
74712b65585SGordon Ross 
74812b65585SGordon Ross 	rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0,
74912b65585SGordon Ross 	    KSOCKET_SLEEP, CRED());
75012b65585SGordon Ross 	if (rc != 0) {
75112b65585SGordon Ross 		cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc);
752b210fedeSGordon Ross 		smb_threshold_exit(&sv->sv_ssetup_ct);
75312b65585SGordon Ross 		status = NT_STATUS_INSUFF_SERVER_RESOURCES;
75412b65585SGordon Ross 		goto errout;
75512b65585SGordon Ross 	}
75612b65585SGordon Ross 
757b210fedeSGordon Ross 	/*
758b210fedeSGordon Ross 	 * This (new) user object now gets an authsocket.
759b210fedeSGordon Ross 	 * Note: u_authsock cleanup in smb_user_logoff.
760b210fedeSGordon Ross 	 * After we've set u_authsock, smb_threshold_exit
7618f70e16bSGordon Ross 	 * is done in smb_authsock_close().  If we somehow
7628f70e16bSGordon Ross 	 * already have an authsock, close the new one and
7638f70e16bSGordon Ross 	 * error out.
764b210fedeSGordon Ross 	 */
765b210fedeSGordon Ross 	mutex_enter(&user->u_mutex);
766b210fedeSGordon Ross 	if (user->u_authsock != NULL) {
767b210fedeSGordon Ross 		mutex_exit(&user->u_mutex);
7688f70e16bSGordon Ross 		smb_authsock_close(user, so);
769b210fedeSGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
770b210fedeSGordon Ross 		goto errout;
771b210fedeSGordon Ross 	}
772b210fedeSGordon Ross 	user->u_authsock = so;
7738f70e16bSGordon Ross 	if (smb_auth_total_tmo != 0) {
7748f70e16bSGordon Ross 		user->u_auth_tmo = timeout(smb_user_auth_tmo, user,
7758f70e16bSGordon Ross 		    SEC_TO_TICK(smb_auth_total_tmo));
7768f70e16bSGordon Ross 	}
777b210fedeSGordon Ross 	mutex_exit(&user->u_mutex);
778b210fedeSGordon Ross 
77912b65585SGordon Ross 	/*
78012b65585SGordon Ross 	 * Set the send/recv timeouts.
78112b65585SGordon Ross 	 */
78212b65585SGordon Ross 	(void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
78312b65585SGordon Ross 	    &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED());
78412b65585SGordon Ross 	(void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
78512b65585SGordon Ross 	    &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED());
78612b65585SGordon Ross 
78712b65585SGordon Ross 	/*
788*66b505f1SGordon Ross 	 * Prepare for cancellable connect.
78912b65585SGordon Ross 	 */
790b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
791b210fedeSGordon Ross 	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
792b210fedeSGordon Ross 		mutex_exit(&sr->sr_mutex);
793b210fedeSGordon Ross 		status = NT_STATUS_CANCELLED;
794b210fedeSGordon Ross 		goto errout;
795b210fedeSGordon Ross 	}
796b210fedeSGordon Ross 	sr->sr_state = SMB_REQ_STATE_WAITING_AUTH;
797b210fedeSGordon Ross 	sr->cancel_method = smb_authsock_cancel;
798b210fedeSGordon Ross 	sr->cancel_arg2 = user;
799b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
800b210fedeSGordon Ross 
801*66b505f1SGordon Ross 	/*
802*66b505f1SGordon Ross 	 * Connect to the smbd auth. service.
803*66b505f1SGordon Ross 	 *
804*66b505f1SGordon Ross 	 * Would like to set the connect timeout too, but there's
805*66b505f1SGordon Ross 	 * apparently no easy way to do that for AF_UNIX.
806*66b505f1SGordon Ross 	 */
80712b65585SGordon Ross 	rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname,
80812b65585SGordon Ross 	    sizeof (smbauth_sockname), CRED());
80912b65585SGordon Ross 	if (rc != 0) {
81012b65585SGordon Ross 		DTRACE_PROBE1(error, int, rc);
81112b65585SGordon Ross 		status = NT_STATUS_NETLOGON_NOT_STARTED;
81212b65585SGordon Ross 	}
81312b65585SGordon Ross 
814*66b505f1SGordon Ross 	/*
815*66b505f1SGordon Ross 	 * Did connect complete or was it cancelled?
816*66b505f1SGordon Ross 	 */
817b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
818*66b505f1SGordon Ross switch_state:
819b210fedeSGordon Ross 	switch (sr->sr_state) {
820b210fedeSGordon Ross 	case SMB_REQ_STATE_WAITING_AUTH:
821*66b505f1SGordon Ross 		/* Normal wakeup.  Keep status from above. */
822b210fedeSGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
823b210fedeSGordon Ross 		break;
824b210fedeSGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
825*66b505f1SGordon Ross 		/* cancel_method running. wait. */
826*66b505f1SGordon Ross 		cv_wait(&sr->sr_st_cv, &sr->sr_mutex);
827*66b505f1SGordon Ross 		goto switch_state;
828*66b505f1SGordon Ross 	case SMB_REQ_STATE_CANCELLED:
829b210fedeSGordon Ross 		status = NT_STATUS_CANCELLED;
830b210fedeSGordon Ross 		break;
831b210fedeSGordon Ross 	default:
83212b65585SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
833b210fedeSGordon Ross 		break;
83412b65585SGordon Ross 	}
835*66b505f1SGordon Ross 	sr->cancel_method = NULL;
836*66b505f1SGordon Ross 	sr->cancel_arg2 = NULL;
837b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
83812b65585SGordon Ross 
83912b65585SGordon Ross errout:
84012b65585SGordon Ross 	return (status);
84112b65585SGordon Ross }
84212b65585SGordon Ross 
84312b65585SGordon Ross static int
smb_authsock_send(ksocket_t so,void * buf,size_t len)84412b65585SGordon Ross smb_authsock_send(ksocket_t so, void *buf, size_t len)
84512b65585SGordon Ross {
84612b65585SGordon Ross 	int rc;
84712b65585SGordon Ross 	size_t iocnt = 0;
84812b65585SGordon Ross 
84912b65585SGordon Ross 	rc = ksocket_send(so, buf, len, 0, &iocnt, CRED());
85012b65585SGordon Ross 	if (rc == 0 && iocnt != len) {
85112b65585SGordon Ross 		DTRACE_PROBE1(short, size_t, iocnt);
85212b65585SGordon Ross 		rc = EIO;
85312b65585SGordon Ross 	}
85412b65585SGordon Ross 	if (rc != 0) {
85512b65585SGordon Ross 		DTRACE_PROBE1(error, int, rc);
85612b65585SGordon Ross 	}
85712b65585SGordon Ross 
85812b65585SGordon Ross 	return (rc);
85912b65585SGordon Ross }
86012b65585SGordon Ross 
86112b65585SGordon Ross static int
smb_authsock_recv(ksocket_t so,void * buf,size_t len)86212b65585SGordon Ross smb_authsock_recv(ksocket_t so, void *buf, size_t len)
86312b65585SGordon Ross {
86412b65585SGordon Ross 	int rc;
86512b65585SGordon Ross 	size_t iocnt = 0;
86612b65585SGordon Ross 
86712b65585SGordon Ross 	rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED());
86812b65585SGordon Ross 	if (rc == 0) {
86912b65585SGordon Ross 		if (iocnt == 0) {
87012b65585SGordon Ross 			DTRACE_PROBE1(discon, struct sonode *, so);
87112b65585SGordon Ross 			rc = ENOTCONN;
87212b65585SGordon Ross 		} else if (iocnt != len) {
87312b65585SGordon Ross 			/* Should not happen with MSG_WAITALL */
87412b65585SGordon Ross 			DTRACE_PROBE1(short, size_t, iocnt);
87512b65585SGordon Ross 			rc = EIO;
87612b65585SGordon Ross 		}
87712b65585SGordon Ross 	}
87812b65585SGordon Ross 	if (rc != 0) {
87912b65585SGordon Ross 		DTRACE_PROBE1(error, int, rc);
88012b65585SGordon Ross 	}
88112b65585SGordon Ross 
88212b65585SGordon Ross 	return (rc);
88312b65585SGordon Ross }
88412b65585SGordon Ross 
885b210fedeSGordon Ross /*
886b210fedeSGordon Ross  * Caller has cleared user->u_authsock, passing the last ref
887b210fedeSGordon Ross  * as the 2nd arg here.  This can block, so it's called
888b210fedeSGordon Ross  * after exiting u_mutex.
889b210fedeSGordon Ross  */
89012b65585SGordon Ross void
smb_authsock_close(smb_user_t * user,ksocket_t so)891b210fedeSGordon Ross smb_authsock_close(smb_user_t *user, ksocket_t so)
89212b65585SGordon Ross {
89312b65585SGordon Ross 
8948f70e16bSGordon Ross 	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
895b210fedeSGordon Ross 	(void) ksocket_close(so, CRED());
89612b65585SGordon Ross 	smb_threshold_exit(&user->u_server->sv_ssetup_ct);
89712b65585SGordon Ross }
898