xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_authenticate.c (revision 48bbca816818409505a6e214d0911fda44e622e3)
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 	int		rc;
394 	bool_t		ok;
395 
396 	msg_hdr.lmh_msgtype = LSA_MTYPE_GETTOK;
397 	msg_hdr.lmh_msglen = 0;
398 
399 	status = smb_authsock_sendrecv(user, &msg_hdr, NULL, &rbuf);
400 	if (status != 0)
401 		goto errout;
402 
403 	rlen = msg_hdr.lmh_msglen;
404 	switch (msg_hdr.lmh_msgtype) {
405 
406 	case LSA_MTYPE_TOKEN:
407 		status = 0;
408 		break;
409 
410 	case LSA_MTYPE_ERROR:
411 		if (rlen == sizeof (smb_lsa_eresp_t)) {
412 			smb_lsa_eresp_t *ler = rbuf;
413 			status = ler->ler_ntstatus;
414 			goto errout;
415 		}
416 		/* FALLTHROUGH */
417 
418 	default:
419 		status = NT_STATUS_INTERNAL_ERROR;
420 		goto errout;
421 	}
422 
423 	/*
424 	 * Authenticated.  Decode the LSA_MTYPE_TOKEN.
425 	 */
426 	xdrmem_create(&xdrs, rbuf, rlen, XDR_DECODE);
427 	token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
428 	ok = smb_token_xdr(&xdrs, token);
429 	xdr_destroy(&xdrs);
430 	if (!ok) {
431 		status = RPC_NT_BAD_STUB_DATA;
432 		goto errout;
433 	}
434 	kmem_free(rbuf, rlen);
435 	rbuf = NULL;
436 
437 	/*
438 	 * Setup the logon object.
439 	 */
440 	cr = smb_cred_create(token);
441 	if (cr == NULL)
442 		goto errout;
443 	privileges = smb_priv_xlate(token);
444 	(void) smb_user_logon(user, cr,
445 	    token->tkn_domain_name, token->tkn_account_name,
446 	    token->tkn_flags, privileges, token->tkn_audit_sid);
447 	crfree(cr);
448 
449 	/*
450 	 * Save the session key, and (maybe) enable signing,
451 	 * but only for real logon (not ANON or GUEST).
452 	 */
453 	if ((token->tkn_flags & (SMB_ATF_GUEST | SMB_ATF_ANON)) == 0) {
454 		if (sr->session->dialect >= SMB_VERS_2_BASE) {
455 			rc = smb2_sign_begin(sr, token);
456 		} else {
457 			rc = smb_sign_begin(sr, token);
458 		}
459 		if (rc != 0) {
460 			status = NT_STATUS_INTERNAL_ERROR;
461 			goto errout;
462 		}
463 	}
464 
465 	smb_token_free(token);
466 
467 	sr->user_cr = user->u_cred;
468 	return (0);
469 
470 errout:
471 	if (rbuf != NULL)
472 		kmem_free(rbuf, rlen);
473 	if (token != NULL)
474 		smb_token_free(token);
475 	return (status);
476 }
477 
478 /*
479  * Tokens are allocated in the kernel via XDR.
480  * Call xdr_free before freeing the token structure.
481  */
482 void
483 smb_token_free(smb_token_t *token)
484 {
485 	if (token != NULL) {
486 		xdr_free(smb_token_xdr, (char *)token);
487 		kmem_free(token, sizeof (smb_token_t));
488 	}
489 }
490 
491 /*
492  * Convert access token privileges to local definitions.
493  */
494 static uint32_t
495 smb_priv_xlate(smb_token_t *token)
496 {
497 	uint32_t	privileges = 0;
498 
499 	if (smb_token_query_privilege(token, SE_BACKUP_LUID))
500 		privileges |= SMB_USER_PRIV_BACKUP;
501 
502 	if (smb_token_query_privilege(token, SE_RESTORE_LUID))
503 		privileges |= SMB_USER_PRIV_RESTORE;
504 
505 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID))
506 		privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
507 
508 	if (smb_token_query_privilege(token, SE_SECURITY_LUID))
509 		privileges |= SMB_USER_PRIV_SECURITY;
510 
511 	return (privileges);
512 }
513 
514 /*
515  * Send/recv a request/reply sequence on the auth socket.
516  * Returns zero or an NT status.
517  *
518  * Errors here mean we can't communicate with the smbd_authsvc.
519  * With limited authsock instances, this should be rare.
520  */
521 static uint32_t
522 smb_authsock_sendrecv(smb_user_t *user, smb_lsa_msg_hdr_t *hdr,
523 	void *sndbuf, void **recvbuf)
524 {
525 	ksocket_t so;
526 	uint32_t status;
527 	int rc;
528 
529 	/*
530 	 * Get a hold on the auth socket.
531 	 */
532 	mutex_enter(&user->u_mutex);
533 	so = user->u_authsock;
534 	if (so == NULL) {
535 		mutex_exit(&user->u_mutex);
536 		return (NT_STATUS_INTERNAL_ERROR);
537 	}
538 	ksocket_hold(so);
539 	mutex_exit(&user->u_mutex);
540 
541 	rc = smb_authsock_send(so, hdr, sizeof (*hdr));
542 	if (rc == 0 && hdr->lmh_msglen != 0) {
543 		rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen);
544 	}
545 	if (rc)
546 		goto out;
547 
548 	rc = smb_authsock_recv(so, hdr, sizeof (*hdr));
549 	if (rc == 0 && hdr->lmh_msglen != 0) {
550 		*recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP);
551 		rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen);
552 		if (rc) {
553 			kmem_free(*recvbuf, hdr->lmh_msglen);
554 			*recvbuf = NULL;
555 		}
556 	}
557 
558 out:
559 	ksocket_rele(so);
560 	switch (rc) {
561 	case 0:
562 		status = 0;
563 		break;
564 	case EIO:
565 		status = RPC_NT_COMM_FAILURE;
566 		break;
567 	case ENOTCONN:
568 		status = RPC_NT_PIPE_CLOSED;
569 		break;
570 	default:
571 		status = RPC_NT_CALL_FAILED;
572 		break;
573 	}
574 
575 	return (status);
576 }
577 
578 /*
579  * Hope this is interpreted per-zone...
580  */
581 static struct sockaddr_un smbauth_sockname = {
582 	AF_UNIX, SMB_AUTHSVC_SOCKNAME };
583 
584 /*
585  * Limit how long smb_authsock_sendrecv() will wait for a
586  * response from the local authentication service.
587  */
588 struct timeval smb_auth_recv_tmo = { 45, 0 };
589 
590 /*
591  * Also limit the time smb_authsock_sendrecv() will wait
592  * trying to send a request to the authentication service.
593  */
594 struct timeval smb_auth_send_tmo = { 15, 0 };
595 
596 static uint32_t
597 smb_authsock_open(smb_user_t *user)
598 {
599 	smb_server_t *sv = user->u_server;
600 	ksocket_t so = NULL;
601 	uint32_t status;
602 	int rc;
603 
604 	/*
605 	 * If the auth. service is busy, wait our turn.
606 	 * This may be frequent, so don't log.
607 	 */
608 	if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0)
609 		return (NT_STATUS_NO_LOGON_SERVERS);
610 
611 	rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0,
612 	    KSOCKET_SLEEP, CRED());
613 	if (rc != 0) {
614 		cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc);
615 		status = NT_STATUS_INSUFF_SERVER_RESOURCES;
616 		goto errout;
617 	}
618 
619 	/*
620 	 * Set the send/recv timeouts.
621 	 */
622 	(void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
623 	    &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED());
624 	(void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
625 	    &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED());
626 
627 	/*
628 	 * Connect to the smbd auth. service.
629 	 *
630 	 * Would like to set the connect timeout too, but there's
631 	 * apparently no easy way to do that for AF_UNIX.
632 	 */
633 	rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname,
634 	    sizeof (smbauth_sockname), CRED());
635 	if (rc != 0) {
636 		DTRACE_PROBE1(error, int, rc);
637 		status = NT_STATUS_NETLOGON_NOT_STARTED;
638 		goto errout;
639 	}
640 
641 	/* Note: u_authsock cleanup in smb_authsock_close() */
642 	mutex_enter(&user->u_mutex);
643 	if (user->u_authsock != NULL) {
644 		mutex_exit(&user->u_mutex);
645 		status = NT_STATUS_INTERNAL_ERROR;
646 		goto errout;
647 	}
648 	user->u_authsock = so;
649 	mutex_exit(&user->u_mutex);
650 	return (0);
651 
652 errout:
653 	if (so != NULL)
654 		(void) ksocket_close(so, CRED());
655 	smb_threshold_exit(&sv->sv_ssetup_ct);
656 
657 	return (status);
658 }
659 
660 static int
661 smb_authsock_send(ksocket_t so, void *buf, size_t len)
662 {
663 	int rc;
664 	size_t iocnt = 0;
665 
666 	rc = ksocket_send(so, buf, len, 0, &iocnt, CRED());
667 	if (rc == 0 && iocnt != len) {
668 		DTRACE_PROBE1(short, size_t, iocnt);
669 		rc = EIO;
670 	}
671 	if (rc != 0) {
672 		DTRACE_PROBE1(error, int, rc);
673 	}
674 
675 	return (rc);
676 }
677 
678 static int
679 smb_authsock_recv(ksocket_t so, void *buf, size_t len)
680 {
681 	int rc;
682 	size_t iocnt = 0;
683 
684 	rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED());
685 	if (rc == 0) {
686 		if (iocnt == 0) {
687 			DTRACE_PROBE1(discon, struct sonode *, so);
688 			rc = ENOTCONN;
689 		} else if (iocnt != len) {
690 			/* Should not happen with MSG_WAITALL */
691 			DTRACE_PROBE1(short, size_t, iocnt);
692 			rc = EIO;
693 		}
694 	}
695 	if (rc != 0) {
696 		DTRACE_PROBE1(error, int, rc);
697 	}
698 
699 	return (rc);
700 }
701 
702 void
703 smb_authsock_close(smb_user_t *user)
704 {
705 
706 	ASSERT(MUTEX_HELD(&user->u_mutex));
707 	if (user->u_authsock == NULL)
708 		return;
709 	(void) ksocket_close(user->u_authsock, CRED());
710 	user->u_authsock = NULL;
711 	smb_threshold_exit(&user->u_server->sv_ssetup_ct);
712 }
713