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
smb_authenticate_old(smb_request_t * sr)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
smb_auth_do_oldreq(smb_request_t * sr)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
smb_authenticate_ext(smb_request_t * sr)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
smb_auth_do_clinfo(smb_request_t * sr)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
smb_auth_get_token(smb_request_t * sr)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
smb_token_free(smb_token_t * token)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
smb_priv_xlate(smb_token_t * token)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
smb_authsock_cancel(smb_request_t * sr)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
smb_authsock_sendrecv(smb_request_t * sr,smb_lsa_msg_hdr_t * hdr,void * sndbuf,void ** recvbuf)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
smb_authsock_open(smb_request_t * sr)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
smb_authsock_send(ksocket_t so,void * buf,size_t len)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
smb_authsock_recv(ksocket_t so,void * buf,size_t len)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
smb_authsock_close(smb_user_t * user,ksocket_t so)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