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