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 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 * 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, sr->session);
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 return (privileges);
548 }
549
550 /*
551 * Unblock a request that might be blocked reading some
552 * authentication socket. This can happen when either the
553 * client cancels a session setup or closes the connection.
554 */
555 static void
556 smb_authsock_cancel(smb_request_t *sr)
557 {
558 smb_user_t *user = sr->cancel_arg2;
559 ksocket_t authsock = NULL;
560
561 if (user == NULL)
562 return;
563 ASSERT(user == sr->uid_user);
564
565 /*
566 * Check user state, and get a hold on the auth socket.
567 */
568 mutex_enter(&user->u_mutex);
569 if (user->u_state == SMB_USER_STATE_LOGGING_ON) {
570 if ((authsock = user->u_authsock) != NULL)
571 ksocket_hold(authsock);
572 }
573 mutex_exit(&user->u_mutex);
574
575 if (authsock != NULL) {
576 (void) ksocket_shutdown(authsock, SHUT_RDWR, sr->user_cr);
577 ksocket_rele(authsock);
578 }
579 }
580
581 /*
582 * Send/recv a request/reply sequence on the auth socket.
583 * Returns zero or an NT status.
584 *
585 * Errors here mean we can't communicate with the smbd_authsvc.
586 * With limited authsock instances, this should be rare.
587 */
588 static uint32_t
589 smb_authsock_sendrecv(smb_request_t *sr, smb_lsa_msg_hdr_t *hdr,
590 void *sndbuf, void **recvbuf)
591 {
592 smb_user_t *user = sr->uid_user;
593 ksocket_t so;
594 uint32_t status;
595 int rc;
596
597 /*
598 * Get a hold on the auth socket.
599 */
600 mutex_enter(&user->u_mutex);
601 so = user->u_authsock;
602 if (so == NULL) {
603 mutex_exit(&user->u_mutex);
604 return (NT_STATUS_INTERNAL_ERROR);
605 }
606 ksocket_hold(so);
607 mutex_exit(&user->u_mutex);
608
609 mutex_enter(&sr->sr_mutex);
610 if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
611 mutex_exit(&sr->sr_mutex);
612 status = NT_STATUS_CANCELLED;
613 goto out;
614 }
615 sr->sr_state = SMB_REQ_STATE_WAITING_AUTH;
616 sr->cancel_method = smb_authsock_cancel;
617 sr->cancel_arg2 = user;
618 mutex_exit(&sr->sr_mutex);
619
620 rc = smb_authsock_send(so, hdr, sizeof (*hdr));
621 if (rc == 0 && hdr->lmh_msglen != 0) {
622 rc = smb_authsock_send(so, sndbuf, hdr->lmh_msglen);
623 }
624 if (rc == 0)
625 rc = smb_authsock_recv(so, hdr, sizeof (*hdr));
626 if (rc == 0 && hdr->lmh_msglen != 0) {
627 *recvbuf = kmem_alloc(hdr->lmh_msglen, KM_SLEEP);
628 rc = smb_authsock_recv(so, *recvbuf, hdr->lmh_msglen);
629 }
630
631 switch (rc) {
632 case 0:
633 status = 0;
634 break;
635 case EIO:
636 status = RPC_NT_COMM_FAILURE;
637 break;
638 case ENOTCONN:
639 status = RPC_NT_PIPE_CLOSED;
640 break;
641 default:
642 status = RPC_NT_CALL_FAILED;
643 break;
644 }
645
646 mutex_enter(&sr->sr_mutex);
647 sr->cancel_method = NULL;
648 sr->cancel_arg2 = NULL;
649 switch (sr->sr_state) {
650 case SMB_REQ_STATE_WAITING_AUTH:
651 sr->sr_state = SMB_REQ_STATE_ACTIVE;
652 break;
653 case SMB_REQ_STATE_CANCEL_PENDING:
654 sr->sr_state = SMB_REQ_STATE_CANCELLED;
655 status = NT_STATUS_CANCELLED;
656 break;
657 default:
658 status = NT_STATUS_INTERNAL_ERROR;
659 break;
660 }
661 mutex_exit(&sr->sr_mutex);
662
663 out:
664 ksocket_rele(so);
665
666 if (status != 0 && *recvbuf != NULL) {
667 kmem_free(*recvbuf, hdr->lmh_msglen);
668 *recvbuf = NULL;
669 }
670 return (status);
671 }
672
673 /*
674 * Hope this is interpreted per-zone...
675 */
676 static struct sockaddr_un smbauth_sockname = {
677 AF_UNIX, SMB_AUTHSVC_SOCKNAME };
678
679 /*
680 * Limit how long smb_authsock_sendrecv() will wait for a
681 * response from the local authentication service.
682 */
683 struct timeval smb_auth_recv_tmo = { 45, 0 };
684
685 /*
686 * Also limit the time smb_authsock_sendrecv() will wait
687 * trying to send a request to the authentication service.
688 */
689 struct timeval smb_auth_send_tmo = { 15, 0 };
690
691 /*
692 * Maximum time a user object may stay in state LOGGING_ON
693 */
694 int smb_auth_total_tmo = 45; /* seconds */
695
696 static uint32_t
697 smb_authsock_open(smb_request_t *sr)
698 {
699 smb_user_t *user = sr->uid_user;
700 smb_server_t *sv = sr->sr_server;
701 ksocket_t so = NULL;
702 uint32_t status = 0;
703 int rc;
704
705 /*
706 * If the auth. service is busy, wait our turn. This threshold
707 * limits the number of auth sockets we might have trying to
708 * communicate with the auth. service up in smbd. Until we've
709 * set u_authsock, we need to "exit this threshold" in any
710 * error code paths after this "enter".
711 *
712 * Failure to "enter" may be frequent, so don't log.
713 */
714 if ((rc = smb_threshold_enter(&sv->sv_ssetup_ct)) != 0)
715 return (NT_STATUS_NO_LOGON_SERVERS);
716
717 rc = ksocket_socket(&so, AF_UNIX, SOCK_STREAM, 0,
718 KSOCKET_SLEEP, CRED());
719 if (rc != 0) {
720 cmn_err(CE_NOTE, "smb_authsock_open: socket, rc=%d", rc);
721 smb_threshold_exit(&sv->sv_ssetup_ct);
722 status = NT_STATUS_INSUFF_SERVER_RESOURCES;
723 goto errout;
724 }
725
726 /*
727 * This (new) user object now gets an authsocket.
728 * Note: u_authsock cleanup in smb_user_logoff.
729 * After we've set u_authsock, smb_threshold_exit
730 * is done in smb_authsock_close(). If we somehow
731 * already have an authsock, close the new one and
732 * error out.
733 */
734 mutex_enter(&user->u_mutex);
735 if (user->u_authsock != NULL) {
736 mutex_exit(&user->u_mutex);
737 smb_authsock_close(user, so);
738 status = NT_STATUS_INTERNAL_ERROR;
739 goto errout;
740 }
741 user->u_authsock = so;
742 if (smb_auth_total_tmo != 0) {
743 user->u_auth_tmo = timeout(smb_user_auth_tmo, user,
744 SEC_TO_TICK(smb_auth_total_tmo));
745 }
746 mutex_exit(&user->u_mutex);
747
748 /*
749 * Set the send/recv timeouts.
750 */
751 (void) ksocket_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
752 &smb_auth_send_tmo, sizeof (smb_auth_send_tmo), CRED());
753 (void) ksocket_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO,
754 &smb_auth_recv_tmo, sizeof (smb_auth_recv_tmo), CRED());
755
756 /*
757 * Connect to the smbd auth. service.
758 *
759 * Would like to set the connect timeout too, but there's
760 * apparently no easy way to do that for AF_UNIX.
761 */
762 mutex_enter(&sr->sr_mutex);
763 if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
764 mutex_exit(&sr->sr_mutex);
765 status = NT_STATUS_CANCELLED;
766 goto errout;
767 }
768 sr->sr_state = SMB_REQ_STATE_WAITING_AUTH;
769 sr->cancel_method = smb_authsock_cancel;
770 sr->cancel_arg2 = user;
771 mutex_exit(&sr->sr_mutex);
772
773 rc = ksocket_connect(so, (struct sockaddr *)&smbauth_sockname,
774 sizeof (smbauth_sockname), CRED());
775 if (rc != 0) {
776 DTRACE_PROBE1(error, int, rc);
777 status = NT_STATUS_NETLOGON_NOT_STARTED;
778 }
779
780 mutex_enter(&sr->sr_mutex);
781 sr->cancel_method = NULL;
782 sr->cancel_arg2 = NULL;
783 switch (sr->sr_state) {
784 case SMB_REQ_STATE_WAITING_AUTH:
785 sr->sr_state = SMB_REQ_STATE_ACTIVE;
786 break;
787 case SMB_REQ_STATE_CANCEL_PENDING:
788 sr->sr_state = SMB_REQ_STATE_CANCELLED;
789 status = NT_STATUS_CANCELLED;
790 break;
791 default:
792 status = NT_STATUS_INTERNAL_ERROR;
793 break;
794 }
795 mutex_exit(&sr->sr_mutex);
796
797 errout:
798 return (status);
799 }
800
801 static int
802 smb_authsock_send(ksocket_t so, void *buf, size_t len)
803 {
804 int rc;
805 size_t iocnt = 0;
806
807 rc = ksocket_send(so, buf, len, 0, &iocnt, CRED());
808 if (rc == 0 && iocnt != len) {
809 DTRACE_PROBE1(short, size_t, iocnt);
810 rc = EIO;
811 }
812 if (rc != 0) {
813 DTRACE_PROBE1(error, int, rc);
814 }
815
816 return (rc);
817 }
818
819 static int
820 smb_authsock_recv(ksocket_t so, void *buf, size_t len)
821 {
822 int rc;
823 size_t iocnt = 0;
824
825 rc = ksocket_recv(so, buf, len, MSG_WAITALL, &iocnt, CRED());
826 if (rc == 0) {
827 if (iocnt == 0) {
828 DTRACE_PROBE1(discon, struct sonode *, so);
829 rc = ENOTCONN;
830 } else if (iocnt != len) {
831 /* Should not happen with MSG_WAITALL */
832 DTRACE_PROBE1(short, size_t, iocnt);
833 rc = EIO;
834 }
835 }
836 if (rc != 0) {
837 DTRACE_PROBE1(error, int, rc);
838 }
839
840 return (rc);
841 }
842
843 /*
844 * Caller has cleared user->u_authsock, passing the last ref
845 * as the 2nd arg here. This can block, so it's called
846 * after exiting u_mutex.
847 */
848 void
849 smb_authsock_close(smb_user_t *user, ksocket_t so)
850 {
851
852 (void) ksocket_shutdown(so, SHUT_RDWR, CRED());
853 (void) ksocket_close(so, CRED());
854 smb_threshold_exit(&user->u_server->sv_ssetup_ct);
855 }