1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2019 Nexenta by DDN, Inc. All rights reserved.
24 * Copyright 2020 RackTop Systems, Inc.
25 */
26
27/*
28 * Authentication support for SMB session setup
29 */
30
31#include <sys/types.h>
32#include <sys/sid.h>
33#include <sys/priv_names.h>
34#include <sys/socket.h>
35#include <sys/un.h>
36#include <netinet/in.h>
37#include <smbsrv/smb_idmap.h>
38#include <smbsrv/smb_kproto.h>
39#include <smbsrv/smb_token.h>
40#include <smbsrv/smb2_kproto.h>
41
42static uint32_t smb_authsock_open(smb_request_t *);
43static int smb_authsock_send(ksocket_t, void *, size_t);
44static int smb_authsock_recv(ksocket_t, void *, size_t);
45static uint32_t smb_authsock_sendrecv(smb_request_t *, smb_lsa_msg_hdr_t *hdr,
46				void *sndbuf, void **recvbuf);
47/* void smb_authsock_close(smb_user_t *); kproto.h */
48
49static uint32_t smb_auth_do_clinfo(smb_request_t *);
50static uint32_t smb_auth_do_oldreq(smb_request_t *);
51static uint32_t smb_auth_get_token(smb_request_t *);
52static uint32_t smb_priv_xlate(smb_token_t *);
53
54/*
55 * Handle old-style session setup (non-extended security)
56 * Note: Used only by SMB1
57 *
58 * The user information is passed to smbd for authentication.
59 * If smbd can authenticate the user an access token is returned and we
60 * generate a cred and new user based on the token.
61 */
62int
63smb_authenticate_old(smb_request_t *sr)
64{
65	smb_user_t	*user = NULL;
66	uint32_t	status;
67
68	user = smb_user_new(sr->session);
69	if (user == NULL)
70		return (NT_STATUS_TOO_MANY_SESSIONS);
71
72	/* user cleanup in smb_request_free */
73	sr->uid_user = user;
74	sr->smb_uid = user->u_uid;
75	sr->smb2_ssnid = 0;
76
77	/*
78	 * Open a connection to the local logon service.
79	 * If we can't, it may be busy, or not running.
80	 * Don't log here - this may be frequent.
81	 */
82	if ((status = smb_authsock_open(sr)) != 0)
83		goto errout;
84
85	/*
86	 * Tell the auth. svc who this client is.
87	 */
88	if ((status = smb_auth_do_clinfo(sr)) != 0)
89		goto errout;
90
91	/*
92	 * Authentication proper
93	 */
94	if ((status = smb_auth_do_oldreq(sr)) != 0)
95		goto errout;
96
97	/*
98	 * Get the final auth. token.
99	 */
100	if ((status = smb_auth_get_token(sr)) != 0)
101		goto errout;
102
103	return (0);
104
105errout:
106	smb_user_logoff(user);
107	return (status);
108}
109
110/*
111 * Build an authentication request message and
112 * send it to the local logon service.
113 */
114static uint32_t
115smb_auth_do_oldreq(smb_request_t *sr)
116{
117	smb_lsa_msg_hdr_t	msg_hdr;
118	smb_logon_t	user_info;
119	XDR		xdrs;
120	smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
121	void		*sbuf = NULL;
122	void		*rbuf = NULL;
123	uint32_t	slen = 0;
124	uint32_t	rlen = 0;
125	uint32_t	status;
126	bool_t		ok;
127
128	bzero(&user_info, sizeof (smb_logon_t));
129
130	user_info.lg_level = NETR_NETWORK_LOGON;
131	user_info.lg_username = sinfo->ssi_user;
132	user_info.lg_domain = sinfo->ssi_domain;
133	user_info.lg_workstation = sr->session->workstation;
134	user_info.lg_clnt_ipaddr = sr->session->ipaddr;
135	user_info.lg_local_ipaddr = sr->session->local_ipaddr;
136	user_info.lg_local_port = sr->session->s_local_port;
137	user_info.lg_challenge_key.val = sr->session->challenge_key;
138	user_info.lg_challenge_key.len = sr->session->challenge_len;
139	user_info.lg_nt_password.val = sinfo->ssi_ntpwd;
140	user_info.lg_nt_password.len = sinfo->ssi_ntpwlen;
141	user_info.lg_lm_password.val = sinfo->ssi_lmpwd;
142	user_info.lg_lm_password.len = sinfo->ssi_lmpwlen;
143	user_info.lg_native_os = sr->session->native_os;
144	user_info.lg_native_lm = sr->session->native_lm;
145	/* lg_flags? */
146
147	slen = xdr_sizeof(smb_logon_xdr, &user_info);
148	sbuf = kmem_alloc(slen, KM_SLEEP);
149	xdrmem_create(&xdrs, sbuf, slen, XDR_ENCODE);
150	ok = smb_logon_xdr(&xdrs, &user_info);
151	xdr_destroy(&xdrs);
152	if (!ok) {
153		status = RPC_NT_BAD_STUB_DATA;
154		goto out;
155	}
156
157	msg_hdr.lmh_msgtype = LSA_MTYPE_OLDREQ;
158	msg_hdr.lmh_msglen = slen;
159	status = smb_authsock_sendrecv(sr, &msg_hdr, sbuf, &rbuf);
160	if (status != 0)
161		goto out;
162	rlen = msg_hdr.lmh_msglen;
163	kmem_free(sbuf, slen);
164	sbuf = NULL;
165
166	/*
167	 * Decode the response message.
168	 */
169	switch (msg_hdr.lmh_msgtype) {
170
171	case LSA_MTYPE_OK:
172		status = 0;
173		break;
174
175	case LSA_MTYPE_ERROR:
176		if (rlen == sizeof (smb_lsa_eresp_t)) {
177			smb_lsa_eresp_t *ler = rbuf;
178			status = ler->ler_ntstatus;
179			break;
180		}
181		/* FALLTHROUGH */
182
183	default:	/*  Bogus message type */
184		status = NT_STATUS_INTERNAL_ERROR;
185		break;
186	}
187
188out:
189	if (rbuf != NULL)
190		kmem_free(rbuf, rlen);
191	if (sbuf != NULL)
192		kmem_free(sbuf, slen);
193
194	return (status);
195}
196
197/*
198 * Handle new-style (extended security) session setup.
199 * Returns zero: success, non-zero: error (value not used)
200 *
201 * Note that this style uses a sequence of session setup requests,
202 * where the first has SMB UID=0, and subsequent requests in the
203 * same authentication sequence have the SMB UID returned for that
204 * first request.  We allocate a USER object when the first request
205 * in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that
206 * to maintain state between requests in this sequence.  The state
207 * for one sequence includes an AF_UNIX "authsock" connection to the
208 * user-space smbd.  The neat part of this is: in smbd, the handler
209 * for the server-side of one authsock gets only request specific to
210 * one authentication sequence, simplifying it's work immensely.
211 * When the authentication sequence is finished, with either success
212 * or failure, the local side of the authsock is closed.
213 *
214 * As with the old-style authentication, if we succeed, then the
215 * last message from smbd will be an smb_token_t encoding the
216 * information about the new user.
217 *
218 * Outline:
219 * (a) On the first request (UID==0) create a USER object,
220 *     and on subsequent requests, find USER by SMB UID.
221 * (b) Send message / recv. response as above,
222 * (c) If response says "we're done", close authsock
223 *     (both success and failure must close authsock)
224 */
225int
226smb_authenticate_ext(smb_request_t *sr)
227{
228	smb_lsa_msg_hdr_t	msg_hdr;
229	smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
230	smb_user_t	*user = NULL;
231	void		*rbuf = NULL;
232	uint32_t	rlen = 0;
233	uint32_t	status;
234
235	ASSERT(sr->uid_user == NULL);
236
237	/*
238	 * Paranoid:  While finding/creating the user object, make sure
239	 * SMB2 ignores smb_uid, and SMB1 ignores smb2_ssnid.  The
240	 * logic below assumes the "other" one is always zero; both
241	 * the "first request" tests and smb_session_lookup_uid_st.
242	 */
243	if (sr->session->dialect >= SMB_VERS_2_BASE) {
244		/* SMB2+ ignores smb_uid */
245		ASSERT(sr->smb_uid == 0);
246		sr->smb_uid = 0;
247	} else {
248		/* SMB1 ignores smb2_ssnid */
249		ASSERT(sr->smb2_ssnid == 0);
250		sr->smb2_ssnid = 0;
251	}
252
253	/*
254	 * On the first request (UID/ssnid==0) create a USER object.
255	 * On subsequent requests (UID/ssnid!=0) find the USER object.
256	 * Either way, sr->uid_user is set, so our ref. on the
257	 * user object is dropped during normal cleanup work
258	 * for the smb_request (sr).  Ditto u_authsock.
259	 */
260	if (sr->smb2_ssnid == 0 && sr->smb_uid == 0) {
261		user = smb_user_new(sr->session);
262		if (user == NULL)
263			return (NT_STATUS_TOO_MANY_SESSIONS);
264
265		/* user cleanup in smb_request_free */
266		sr->uid_user = user;
267		if (sr->session->dialect >= SMB_VERS_2_BASE) {
268			/* Intentionally leave smb_uid=0 for SMB2 */
269			sr->smb2_ssnid = user->u_ssnid;
270		} else {
271			/* Intentionally leave smb2_ssnid=0 for SMB1 */
272			sr->smb_uid = user->u_uid;
273		}
274
275		/*
276		 * Open a connection to the local logon service.
277		 * If we can't, it may be busy, or not running.
278		 * Don't log here - this may be frequent.
279		 */
280		if ((status = smb_authsock_open(sr)) != 0)
281			goto errout;
282
283		/*
284		 * Tell the auth. svc who this client is.
285		 */
286		if ((status = smb_auth_do_clinfo(sr)) != 0)
287			goto errout;
288
289		msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST;
290
291		if (sr->session->dialect >= SMB_VERS_3_11) {
292			if (smb31_preauth_sha512_calc(sr, &sr->command,
293			    sr->session->smb31_preauth_hashval,
294			    user->u_preauth_hashval) != 0)
295				cmn_err(CE_WARN, "(2) Preauth hash calculation "
296				    "failed");
297		}
298	} else {
299		user = smb_session_lookup_uid_st(sr->session,
300		    sr->smb2_ssnid, sr->smb_uid, SMB_USER_STATE_LOGGING_ON);
301		if (user == NULL)
302			return (NT_STATUS_USER_SESSION_DELETED);
303
304		/* user cleanup in smb_request_free */
305		sr->uid_user = user;
306
307		msg_hdr.lmh_msgtype = LSA_MTYPE_ESNEXT;
308
309		if (sr->session->dialect >= SMB_VERS_3_11) {
310			if (smb31_preauth_sha512_calc(sr, &sr->command,
311			    user->u_preauth_hashval,
312			    user->u_preauth_hashval) != 0)
313				cmn_err(CE_WARN, "(4) Preauth hash calculation "
314				    "failed");
315		}
316	}
317
318	/*
319	 * Wrap the "security blob" with our header
320	 * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT)
321	 * and send it up the authsock with either
322	 */
323	msg_hdr.lmh_msglen = sinfo->ssi_iseclen;
324	status = smb_authsock_sendrecv(sr, &msg_hdr,
325	    sinfo->ssi_isecblob, &rbuf);
326	if (status != 0)
327		goto errout;
328	rlen = msg_hdr.lmh_msglen;
329
330	/*
331	 * Decode the response message.
332	 * Note: allocated rbuf
333	 */
334	switch (msg_hdr.lmh_msgtype) {
335
336	case LSA_MTYPE_ES_CONT:
337		sinfo->ssi_oseclen = (uint16_t)rlen;
338		sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
339		bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
340		/*
341		 * This is not really an error, but tells the client
342		 * it should send another session setup request.
343		 */
344		status = NT_STATUS_MORE_PROCESSING_REQUIRED;
345		break;
346
347	case LSA_MTYPE_ES_DONE:
348		sinfo->ssi_oseclen = (uint16_t)rlen;
349		sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
350		bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
351		sinfo->ssi_ntpwlen = 0;
352		/*
353		 * Get the final auth. token.
354		 */
355		status = smb_auth_get_token(sr);
356		break;
357
358	case LSA_MTYPE_ERROR:
359		/*
360		 * Authentication failed.  Return the error
361		 * provided in the reply message.
362		 */
363		if (rlen == sizeof (smb_lsa_eresp_t)) {
364			smb_lsa_eresp_t *ler = rbuf;
365			status = ler->ler_ntstatus;
366			goto errout;
367		}
368		/* FALLTHROUGH */
369
370	default:	/*  Bogus message type */
371		status = NT_STATUS_INTERNAL_ERROR;
372		goto errout;
373	}
374
375	if (status != 0 && status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
376	errout:
377		smb_user_logoff(user);
378	}
379
380	if (rbuf != NULL)
381		kmem_free(rbuf, rlen);
382
383	return (status);
384}
385
386/*
387 * Send the "client info" up to the auth service.
388 */
389static uint32_t
390smb_auth_do_clinfo(smb_request_t *sr)
391{
392	smb_lsa_msg_hdr_t msg_hdr;
393	smb_lsa_clinfo_t clinfo;
394	void *rbuf = NULL;
395	uint32_t status;
396
397	/*
398	 * Send a message with info. about the client
399	 * (IP address, etc) and wait for an ACK.
400	 */
401	msg_hdr.lmh_msgtype = LSA_MTYPE_CLINFO;
402	msg_hdr.lmh_msglen = sizeof (clinfo);
403	clinfo.lci_clnt_ipaddr = sr->session->ipaddr;
404	(void) memcpy(clinfo.lci_challenge_key,
405	    sr->session->challenge_key,
406	    sizeof (clinfo.lci_challenge_key));
407	status = smb_authsock_sendrecv(sr, &msg_hdr, &clinfo, &rbuf);
408	/* We don't use this response. */
409	if (rbuf != NULL) {
410		kmem_free(rbuf, msg_hdr.lmh_msglen);
411		rbuf = NULL;
412	}
413
414	return (status);
415}
416
417/*
418 * After a successful authentication, ask the authsvc to
419 * send us the authentication token.
420 */
421static uint32_t
422smb_auth_get_token(smb_request_t *sr)
423{
424	smb_lsa_msg_hdr_t msg_hdr;
425	XDR		xdrs;
426	smb_user_t	*user = sr->uid_user;
427	smb_token_t	*token = NULL;
428	cred_t		*cr = NULL;
429	void		*rbuf = NULL;
430	uint32_t	rlen = 0;
431	uint32_t	privileges;
432	uint32_t	status;
433	bool_t		ok;
434
435	msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK;
436	msg_hdr.lmh_msglen = 0;
437
438	status = smb_authsock_sendrecv(sr, &msg_hdr, NULL, &rbuf);
439	if (status != 0)
440		goto errout;
441
442	rlen = msg_hdr.lmh_msglen;
443	switch (msg_hdr.lmh_msgtype) {
444
445	case LSA_MTYPE_TOKEN:
446		status = 0;
447		break;
448
449	case LSA_MTYPE_ERROR:
450		if (rlen == sizeof (smb_lsa_eresp_t)) {
451			smb_lsa_eresp_t *ler = rbuf;
452			status = ler->ler_ntstatus;
453			goto errout;
454		}
455		/* FALLTHROUGH */
456
457	default:
458		status = NT_STATUS_INTERNAL_ERROR;
459		goto errout;
460	}
461
462	/*
463	 * Authenticated.  Decode the LSA_MTYPE_TOKEN.
464	 */
465	xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE);
466	token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
467	ok = smb_token_xdr(&xdrs, token);
468	xdr_destroy(&xdrs);
469	if (!ok) {
470		status = RPC_NT_BAD_STUB_DATA;
471		goto errout;
472	}
473	kmem_free(rbuf, rlen);
474	rbuf = NULL;
475
476	/*
477	 * Setup the logon object.
478	 */
479	cr = smb_cred_create(token);
480	if (cr == NULL)
481		goto errout;
482	privileges = smb_priv_xlate(token);
483	(void) smb_user_logon(user, cr,
484	    token->tkn_domain_name, token->tkn_account_name,
485	    token->tkn_flags, privileges, token->tkn_audit_sid);
486	crfree(cr);
487
488	/*
489	 * Some basic processing for encryption needs to be done,
490	 * even for anonymous/guest sessions. In particular,
491	 * we need to set Session.EncryptData.
492	 *
493	 * Windows handling of anon/guest and encryption is strange.
494	 * It allows these accounts to get through session setup,
495	 * even when they provide no key material.
496	 * Additionally, Windows somehow manages to have key material
497	 * for anonymous accounts under unknown circumstances.
498	 * As such, We set EncryptData on anon/guest to behave like Windows,
499	 * at least through Session Setup.
500	 */
501	if (sr->session->dialect >= SMB_VERS_3_0)
502		smb3_encrypt_begin(sr, token);
503
504	/*
505	 * Save the session key, and (maybe) enable signing,
506	 * but only for real logon (not ANON or GUEST).
507	 */
508	if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) {
509		if (sr->session->dialect >= SMB_VERS_2_BASE) {
510			smb2_sign_begin(sr, token);
511		} else {
512			smb_sign_begin(sr, token);
513		}
514	}
515
516	smb_token_free(token);
517
518	sr->user_cr = user->u_cred;
519	return (0);
520
521errout:
522	if (rbuf != NULL)
523		kmem_free(rbuf, rlen);
524	if (token != NULL)
525		smb_token_free(token);
526	return (status);
527}
528
529/*
530 * Tokens are allocated in the kernel via XDR.
531 * Call xdr_free before freeing the token structure.
532 */
533void
534smb_token_free(smb_token_t *token)
535{
536	if (token != NULL) {
537		xdr_free(smb_token_xdr, (char *)token);
538		kmem_free(token, sizeof (smb_token_t));
539	}
540}
541
542/*
543 * Convert access token privileges to local definitions.
544 */
545static uint32_t
546smb_priv_xlate(smb_token_t *token)
547{
548	uint32_t	privileges = 0;
549
550	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
551		privileges |= SMB_USER_PRIV_SECURITY;
552
553	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
554		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
555
556	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
557		privileges |= SMB_USER_PRIV_BACKUP;
558
559	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
560		privileges |= SMB_USER_PRIV_RESTORE;
561
562	if (smb_token_query_privilege(token, SE_CHANGE_NOTIFY_LUID))
563		privileges |= SMB_USER_PRIV_CHANGE_NOTIFY;
564
565	if (smb_token_query_privilege(token, SE_READ_FILE_LUID))
566		privileges |= SMB_USER_PRIV_READ_FILE;
567
568	if (smb_token_query_privilege(token, SE_WRITE_FILE_LUID))
569		privileges |= SMB_USER_PRIV_WRITE_FILE;
570
571	return (privileges);
572}
573
574/*
575 * Unblock a request that might be blocked reading some
576 * authentication socket.  This can happen when either the
577 * client cancels a session setup or closes the connection.
578 */
579static void
580smb_authsock_cancel(smb_request_t *sr)
581{
582	smb_user_t *user = sr->cancel_arg2;
583	ksocket_t authsock = NULL;
584
585	if (user == NULL)
586		return;
587	ASSERT(user == sr->uid_user);
588
589	/*
590	 * Check user state, and get a hold on the auth socket.
591	 */
592	mutex_enter(&user->u_mutex);
593	if (user->u_state == SMB_USER_STATE_LOGGING_ON) {
594		if ((authsock = user->u_authsock) != NULL)
595			ksocket_hold(authsock);
596	}
597	mutex_exit(&user->u_mutex);
598
599	if (authsock != NULL) {
600		(void) ksocket_shutdown(authsock, SHUT_RDWR, sr->user_cr);
601		ksocket_rele(authsock);
602	}
603}
604
605/*
606 * Send/recv a request/reply sequence on the auth socket.
607 * Returns zero or an NT status.
608 *
609 * Errors here mean we can't communicate with the smbd_authsvc.
610 * With limited authsock instances, this should be rare.
611 */
612static uint32_t
613smb_authsock_sendrecv(smb_request_t *sr, smb_lsa_msg_hdr_t *hdr,
614    void *sndbuf, void **recvbuf)
615{
616	smb_user_t *user = sr->uid_user;
617	ksocket_t so;
618	uint32_t status;
619	int rc;
620
621	/*
622	 * Get a hold on the auth socket.
623	 */
624	mutex_enter(&user->u_mutex);
625	so = user->u_authsock;
626	if (so == NULL) {
627		mutex_exit(&user->u_mutex);
628		return (NT_STATUS_INTERNAL_ERROR);
629	}
630	ksocket_hold(so);
631	mutex_exit(&user->u_mutex);
632
633	mutex_enter(&sr->sr_mutex);
634	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
635		mutex_exit(&sr->sr_mutex);
636		status = NT_STATUS_CANCELLED;
637		goto out;
638	}
639	sr->sr_state = SMB_REQ_STATE_WAITING_AUTH;
640	sr->cancel_method = smb_authsock_cancel;
641	sr->cancel_arg2 = user;
642	mutex_exit(&sr->sr_mutex);
643
644	rc = smb_authsock_send(so, hdr, sizeof (*hdr));
645	if (rc == 0 && hdr->lmh_msglen != 0) {
646		rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen);
647	}
648	if (rc == 0)
649		rc = smb_authsock_recv(so, hdr, sizeof (*hdr));
650	if (rc == 0 && hdr->lmh_msglen != 0) {
651		*recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP);
652		rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen);
653	}
654
655	switch (rc) {
656	case 0:
657		status = 0;
658		break;
659	case EIO:
660		status = RPC_NT_COMM_FAILURE;
661		break;
662	case ENOTCONN:
663		status = RPC_NT_PIPE_CLOSED;
664		break;
665	default:
666		status = RPC_NT_CALL_FAILED;
667		break;
668	}
669
670	mutex_enter(&sr->sr_mutex);
671	sr->cancel_method = NULL;
672	sr->cancel_arg2 = NULL;
673	switch (sr->sr_state) {
674	case SMB_REQ_STATE_WAITING_AUTH:
675		sr->sr_state = SMB_REQ_STATE_ACTIVE;
676		break;
677	case SMB_REQ_STATE_CANCEL_PENDING:
678		sr->sr_state = SMB_REQ_STATE_CANCELLED;
679		status = NT_STATUS_CANCELLED;
680		break;
681	default:
682		status = NT_STATUS_INTERNAL_ERROR;
683		break;
684	}
685	mutex_exit(&sr->sr_mutex);
686
687out:
688	ksocket_rele(so);
689
690	if (status != 0 && *recvbuf != NULL) {
691		kmem_free(*recvbuf, hdr->lmh_msglen);
692		*recvbuf = NULL;
693	}
694	return (status);
695}
696
697/*
698 * Hope this is interpreted per-zone...
699 */
700static struct sockaddr_un smbauth_sockname = {
701	AF_UNIX, SMB_AUTHSVC_SOCKNAME };
702
703/*
704 * Limit how long smb_authsock_sendrecv() will wait for a
705 * response from the local authentication service.
706 */
707struct timeval smb_auth_recv_tmo = { 45, 0 };
708
709/*
710 * Also limit the time smb_authsock_sendrecv() will wait
711 * trying to send a request to the authentication service.
712 */
713struct timeval smb_auth_send_tmo = { 15, 0 };
714
715/*
716 * Maximum time a user object may stay in state LOGGING_ON
717 */
718int smb_auth_total_tmo = 45;	/* seconds */
719
720static uint32_t
721smb_authsock_open(smb_request_t *sr)
722{
723	smb_user_t *user = sr->uid_user;
724	smb_server_t *sv = sr->sr_server;
725	ksocket_t so = NULL;
726	uint32_t status = 0;
727	int rc;
728
729	/*
730	 * If the auth. service is busy, wait our turn.  This threshold
731	 * limits the number of auth sockets we might have trying to
732	 * communicate with the auth. service up in smbd.  Until we've
733	 * set u_authsock, we need to "exit this threshold" in any
734	 * error code paths after this "enter".
735	 *
736	 * Failure to "enter" may be frequent, so don't log.
737	 */
738	if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0)
739		return (NT_STATUS_NO_LOGON_SERVERS);
740
741	rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0,
742	    KSOCKET_SLEEP, CRED());
743	if (rc != 0) {
744		cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc);
745		smb_threshold_exit(&sv->sv_ssetup_ct);
746		status = NT_STATUS_INSUFF_SERVER_RESOURCES;
747		goto errout;
748	}
749
750	/*
751	 * This (new) user object now gets an authsocket.
752	 * Note: u_authsock cleanup in smb_user_logoff.
753	 * After we've set u_authsock, smb_threshold_exit
754	 * is done in smb_authsock_close().  If we somehow
755	 * already have an authsock, close the new one and
756	 * error out.
757	 */
758	mutex_enter(&user->u_mutex);
759	if (user->u_authsock != NULL) {
760		mutex_exit(&user->u_mutex);
761		smb_authsock_close(user, so);
762		status = NT_STATUS_INTERNAL_ERROR;
763		goto errout;
764	}
765	user->u_authsock = so;
766	if (smb_auth_total_tmo != 0) {
767		user->u_auth_tmo = timeout(smb_user_auth_tmo, user,
768		    SEC_TO_TICK(smb_auth_total_tmo));
769	}
770	mutex_exit(&user->u_mutex);
771
772	/*
773	 * Set the send/recv timeouts.
774	 */
775	(void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
776	    &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED());
777	(void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
778	    &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED());
779
780	/*
781	 * Connect to the smbd auth. service.
782	 *
783	 * Would like to set the connect timeout too, but there's
784	 * apparently no easy way to do that for AF_UNIX.
785	 */
786	mutex_enter(&sr->sr_mutex);
787	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
788		mutex_exit(&sr->sr_mutex);
789		status = NT_STATUS_CANCELLED;
790		goto errout;
791	}
792	sr->sr_state = SMB_REQ_STATE_WAITING_AUTH;
793	sr->cancel_method = smb_authsock_cancel;
794	sr->cancel_arg2 = user;
795	mutex_exit(&sr->sr_mutex);
796
797	rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname,
798	    sizeof (smbauth_sockname), CRED());
799	if (rc != 0) {
800		DTRACE_PROBE1(error, int, rc);
801		status = NT_STATUS_NETLOGON_NOT_STARTED;
802	}
803
804	mutex_enter(&sr->sr_mutex);
805	sr->cancel_method = NULL;
806	sr->cancel_arg2 = NULL;
807	switch (sr->sr_state) {
808	case SMB_REQ_STATE_WAITING_AUTH:
809		sr->sr_state = SMB_REQ_STATE_ACTIVE;
810		break;
811	case SMB_REQ_STATE_CANCEL_PENDING:
812		sr->sr_state = SMB_REQ_STATE_CANCELLED;
813		status = NT_STATUS_CANCELLED;
814		break;
815	default:
816		status = NT_STATUS_INTERNAL_ERROR;
817		break;
818	}
819	mutex_exit(&sr->sr_mutex);
820
821errout:
822	return (status);
823}
824
825static int
826smb_authsock_send(ksocket_t so, void *buf, size_t len)
827{
828	int rc;
829	size_t iocnt = 0;
830
831	rc = ksocket_send(so, buf, len, 0, &iocnt, CRED());
832	if (rc == 0 && iocnt != len) {
833		DTRACE_PROBE1(short, size_t, iocnt);
834		rc = EIO;
835	}
836	if (rc != 0) {
837		DTRACE_PROBE1(error, int, rc);
838	}
839
840	return (rc);
841}
842
843static int
844smb_authsock_recv(ksocket_t so, void *buf, size_t len)
845{
846	int rc;
847	size_t iocnt = 0;
848
849	rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED());
850	if (rc == 0) {
851		if (iocnt == 0) {
852			DTRACE_PROBE1(discon, struct sonode *, so);
853			rc = ENOTCONN;
854		} else if (iocnt != len) {
855			/* Should not happen with MSG_WAITALL */
856			DTRACE_PROBE1(short, size_t, iocnt);
857			rc = EIO;
858		}
859	}
860	if (rc != 0) {
861		DTRACE_PROBE1(error, int, rc);
862	}
863
864	return (rc);
865}
866
867/*
868 * Caller has cleared user->u_authsock, passing the last ref
869 * as the 2nd arg here.  This can block, so it's called
870 * after exiting u_mutex.
871 */
872void
873smb_authsock_close(smb_user_t *user, ksocket_t so)
874{
875
876	(void) ksocket_shutdown(so, SHUT_RDWR, CRED());
877	(void) ksocket_close(so, CRED());
878	smb_threshold_exit(&user->u_server->sv_ssetup_ct);
879}
880