xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_authenticate.c (revision 0292c176d853baa7e46c9ff8e4f16f63b8cbd6e5)
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 
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  * 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  */
60 int
61 smb_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 
103 errout:
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  */
112 static uint32_t
113 smb_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 
186 out:
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  */
223 int
224 smb_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  */
371 static uint32_t
372 smb_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  */
403 static uint32_t
404 smb_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 
503 errout:
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  */
515 void
516 smb_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  */
527 static uint32_t
528 smb_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  */
561 static void
562 smb_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  */
594 static uint32_t
595 smb_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 
669 out:
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  */
682 static 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  */
689 struct 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  */
695 struct timeval smb_auth_send_tmo = { 15, 0 };
696 
697 /*
698  * Maximum time a user object may stay in state LOGGING_ON
699  */
700 int smb_auth_total_tmo = 45;	/* seconds */
701 
702 static uint32_t
703 smb_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 
803 errout:
804 	return (status);
805 }
806 
807 static int
808 smb_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 
825 static int
826 smb_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  */
854 void
855 smb_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