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