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