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