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