xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_session.c (revision 8c80da44415aa7ac14511811fca4d5c4f2c0c51d)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/atomic.h>
29 #include <sys/strsubr.h>
30 #include <sys/synch.h>
31 #include <sys/types.h>
32 #include <sys/socketvar.h>
33 #include <sys/sdt.h>
34 #include <smbsrv/netbios.h>
35 #include <smbsrv/smb_incl.h>
36 #include <smbsrv/smb_i18n.h>
37 
38 extern int smb_maxbufsize;
39 
40 extern unsigned int smb_nt_tcp_rcvbuf;
41 
42 uint32_t			smb_keep_alive = SSN_KEEP_ALIVE_TIMEOUT;
43 uint32_t			smb_send_retries = 0;
44 uint32_t			smb_receive_retries = 0;
45 
46 static int smb_session_message(smb_session_t *);
47 static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
48     uint8_t *, size_t);
49 
50 void smb_request_init_command_mbuf(smb_request_t *sr);
51 static void smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void);
52 
53 
54 void
55 smb_timers(smb_thread_t *thread, void *si_void)
56 {
57 	smb_info_t	*si = si_void;
58 	smb_session_t	*sn;
59 
60 	ASSERT(si != NULL);
61 
62 	while (smb_thread_continue_timedwait(thread, 1 /* Seconds */)) {
63 		/*
64 		 * Walk through the table and decrement each keep_alive
65 		 * timer that has not timed out yet. (keepalive > 0)
66 		 */
67 		smb_svcstate_lock_read(&si->si_svc_sm_ctx);
68 
69 		sn = NULL;
70 		while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx,
71 		    sn)) != NULL) {
72 			ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
73 			if (sn->keep_alive && (sn->keep_alive != (uint32_t)-1))
74 				sn->keep_alive--;
75 		}
76 		smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
77 
78 	}
79 }
80 
81 /*
82  * smb_reconnection_check
83  *
84  * This function is called when a client indicates its current connection
85  * should be the only one it has with the server, as indicated by VC=0 in
86  * a SessionSetupX request. We go through the session list and destroy any
87  * stale connections for that client.
88  *
89  * Clients don't associate IP addresses and servers. So a client may make
90  * independent connections (i.e. with VC=0) to a server with multiple
91  * IP addresses. So, when checking for a reconnection, we need to include
92  * the local IP address, to which the client is connecting, when checking
93  * for stale sessions.
94  *
95  * Also check the server's NetBIOS name to support simultaneous access by
96  * multiple clients behind a NAT server.  This will only work for SMB over
97  * NetBIOS on TCP port 139, it will not work SMB over TCP port 445 because
98  * there is no NetBIOS name.  See also Knowledge Base article Q301673.
99  */
100 void
101 smb_reconnection_check(struct smb_session *session)
102 {
103 	smb_info_t		*si = &smb_info;
104 	smb_session_t		*sn;
105 
106 	smb_svcstate_lock_read(&si->si_svc_sm_ctx);
107 
108 	sn = NULL;
109 	while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn))
110 	    != NULL) {
111 
112 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
113 		if ((sn != session) &&
114 		    (sn->ipaddr == session->ipaddr) &&
115 		    (sn->local_ipaddr == session->local_ipaddr) &&
116 		    (strcasecmp(sn->workstation, session->workstation) == 0) &&
117 		    (sn->opentime <= session->opentime) &&
118 		    (sn->s_kid < session->s_kid)) {
119 			smb_thread_stop(&sn->s_thread);
120 		}
121 	}
122 
123 	smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
124 }
125 
126 
127 void
128 smb_correct_keep_alive_values(uint32_t new_keep_alive)
129 {
130 	smb_info_t		*si = &smb_info;
131 	smb_session_t		*sn;
132 
133 	if (new_keep_alive == smb_keep_alive)
134 		return;
135 	/*
136 	 * keep alive == 0 means do not drop connection if it's idle
137 	 */
138 	smb_keep_alive = (new_keep_alive) ? new_keep_alive : -1;
139 
140 	/*
141 	 * Walk through the table and set each session to the new keep_alive
142 	 * value if they have not already timed out.  Block clock interrupts.
143 	 */
144 	smb_svcstate_lock_read(&si->si_svc_sm_ctx);
145 
146 	sn = NULL;
147 	while ((sn = smb_svcstate_session_getnext(&si->si_svc_sm_ctx, sn))
148 	    != NULL) {
149 		if (sn->keep_alive)
150 			sn->keep_alive = new_keep_alive;
151 	}
152 
153 	smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
154 }
155 
156 /*
157  * Send a session message - supports SMB-over-NBT and SMB-over-TCP.
158  *
159  * The mbuf chain is copied into a contiguous buffer so that the whole
160  * message is submitted to smb_sosend as a single request.  This should
161  * help Ethereal/Wireshark delineate the packets correctly even though
162  * TCP_NODELAY has been set on the socket.
163  *
164  * If an mbuf chain is provided, it will be freed and set to NULL here.
165  */
166 int
167 smb_session_send(smb_session_t *session, uint8_t type, struct mbuf_chain *mbc)
168 {
169 	struct mbuf	*m = NULL;
170 	smb_txbuf_t	*txb;
171 	int		len = 0;
172 	smb_xprt_t	hdr;
173 	int		rc;
174 	uint8_t		*data;
175 
176 	switch (session->s_state) {
177 	case SMB_SESSION_STATE_DISCONNECTED:
178 	case SMB_SESSION_STATE_TERMINATED:
179 		if ((mbc != NULL) && (mbc->chain != NULL)) {
180 			m_freem(mbc->chain);
181 			mbc->chain = NULL;
182 			mbc->flags = 0;
183 		}
184 		return (ENOTCONN);
185 	default:
186 		break;
187 	}
188 
189 	txb = smb_net_txb_alloc();
190 
191 	if ((mbc != NULL) && (mbc->chain != NULL)) {
192 		len = NETBIOS_HDR_SZ;	/* Account for the NBT header. */
193 		m = mbc->chain;
194 		data = &txb->tb_data[len];
195 
196 		while (m) {
197 			if ((len + m->m_len) > sizeof (txb->tb_data)) {
198 				smb_net_txb_free(txb);
199 				m_freem(mbc->chain);
200 				mbc->chain = NULL;
201 				mbc->flags = 0;
202 				return (EMSGSIZE);
203 			}
204 			bcopy(m->m_data, data, m->m_len);
205 			data += m->m_len;
206 			len += m->m_len;
207 			m = m->m_next;
208 		}
209 
210 		m_freem(mbc->chain);
211 		mbc->chain = NULL;
212 		mbc->flags = 0;
213 		len -= NETBIOS_HDR_SZ;
214 	}
215 
216 	hdr.xh_type = type;
217 	hdr.xh_length = len;
218 
219 	rc = smb_session_xprt_puthdr(session, &hdr, txb->tb_data,
220 	    NETBIOS_HDR_SZ);
221 	if (rc == 0) {
222 		txb->tb_len = len + NETBIOS_HDR_SZ;
223 		rc = smb_net_txb_send(session->sock, &session->s_txlst, txb);
224 	} else {
225 		smb_net_txb_free(txb);
226 	}
227 	return (rc);
228 }
229 
230 /*
231  * Read, process and respond to a NetBIOS session request.
232  *
233  * A NetBIOS session must be established for SMB-over-NetBIOS.  Validate
234  * the calling and called name format and save the client NetBIOS name,
235  * which is used when a NetBIOS session is established to check for and
236  * cleanup leftover state from a previous session.
237  *
238  * Session requests are not valid for SMB-over-TCP, which is unfortunate
239  * because without the client name leftover state cannot be cleaned up
240  * if the client is behind a NAT server.
241  */
242 static int
243 smb_session_request(struct smb_session *session)
244 {
245 	int			rc;
246 	char			*calling_name;
247 	char			*called_name;
248 	char 			client_name[NETBIOS_NAME_SZ];
249 	struct mbuf_chain 	mbc;
250 	char 			*names = NULL;
251 	mts_wchar_t		*wbuf = NULL;
252 	smb_xprt_t		hdr;
253 	char *p;
254 	unsigned int cpid = oem_get_smb_cpid();
255 	int rc1, rc2;
256 
257 	session->keep_alive = smb_keep_alive;
258 
259 	if (smb_session_xprt_gethdr(session, &hdr) != 0)
260 		return (EINVAL);
261 
262 	DTRACE_PROBE2(receive__session__req__xprthdr, struct session *, session,
263 	    smb_xprt_t *, &hdr);
264 
265 	if ((hdr.xh_type != SESSION_REQUEST) ||
266 	    (hdr.xh_length != NETBIOS_SESSION_REQUEST_DATA_LENGTH)) {
267 		DTRACE_PROBE1(receive__session__req__failed,
268 		    struct session *, session);
269 		return (EINVAL);
270 	}
271 
272 	names = kmem_alloc(hdr.xh_length, KM_SLEEP);
273 
274 	if ((rc = smb_sorecv(session->sock, names, hdr.xh_length)) != 0) {
275 		kmem_free(names, hdr.xh_length);
276 		DTRACE_PROBE1(receive__session__req__failed,
277 		    struct session *, session);
278 		return (rc);
279 	}
280 
281 	DTRACE_PROBE3(receive__session__req__data, struct session *, session,
282 	    char *, names, uint32_t, hdr.xh_length);
283 
284 	called_name = &names[0];
285 	calling_name = &names[NETBIOS_ENCODED_NAME_SZ + 2];
286 
287 	rc1 = netbios_name_isvalid(called_name, 0);
288 	rc2 = netbios_name_isvalid(calling_name, client_name);
289 
290 	if (rc1 == 0 || rc2 == 0) {
291 
292 		DTRACE_PROBE3(receive__invalid__session__req,
293 		    struct session *, session, char *, names,
294 		    uint32_t, hdr.xh_length);
295 
296 		kmem_free(names, hdr.xh_length);
297 		MBC_INIT(&mbc, MAX_DATAGRAM_LENGTH);
298 		(void) smb_encode_mbc(&mbc, "b",
299 		    DATAGRAM_INVALID_SOURCE_NAME_FORMAT);
300 		(void) smb_session_send(session, NEGATIVE_SESSION_RESPONSE,
301 		    &mbc);
302 		return (EINVAL);
303 	}
304 
305 	DTRACE_PROBE3(receive__session__req__calling__decoded,
306 	    struct session *, session,
307 	    char *, calling_name, char *, client_name);
308 
309 	/*
310 	 * The client NetBIOS name is in oem codepage format.
311 	 * We need to convert it to unicode and store it in
312 	 * multi-byte format.  We also need to strip off any
313 	 * spaces added as part of the NetBIOS name encoding.
314 	 */
315 	wbuf = kmem_alloc((SMB_PI_MAX_HOST * sizeof (mts_wchar_t)), KM_SLEEP);
316 	(void) oemstounicodes(wbuf, client_name, SMB_PI_MAX_HOST, cpid);
317 	(void) mts_wcstombs(session->workstation, wbuf, SMB_PI_MAX_HOST);
318 	kmem_free(wbuf, (SMB_PI_MAX_HOST * sizeof (mts_wchar_t)));
319 
320 	if ((p = strchr(session->workstation, ' ')) != 0)
321 		*p = '\0';
322 
323 	kmem_free(names, hdr.xh_length);
324 	return (smb_session_send(session, POSITIVE_SESSION_RESPONSE, NULL));
325 }
326 
327 /*
328  * Read 4-byte header from the session socket and build an in-memory
329  * session transport header.  See smb_xprt_t definition for header
330  * format information.
331  *
332  * Direct hosted NetBIOS-less SMB (SMB-over-TCP) uses port 445.  The
333  * first byte of the four-byte header must be 0 and the next three
334  * bytes contain the length of the remaining data.
335  */
336 int
337 smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr)
338 {
339 	unsigned char buf[NETBIOS_HDR_SZ];
340 
341 	if (smb_sorecv(session->sock, buf, NETBIOS_HDR_SZ) != 0)
342 		return (-1);
343 
344 	switch (session->s_local_port) {
345 	case SSN_SRVC_TCP_PORT:
346 		ret_hdr->xh_type = buf[0];
347 		ret_hdr->xh_length = (((uint32_t)buf[1] & 1) << 16) |
348 		    ((uint32_t)buf[2] << 8) |
349 		    ((uint32_t)buf[3]);
350 		break;
351 
352 	case SMB_SRVC_TCP_PORT:
353 		ret_hdr->xh_type = buf[0];
354 
355 		if (ret_hdr->xh_type != 0) {
356 			cmn_err(CE_WARN, "0x%08x: invalid type (%u)",
357 			    session->ipaddr, ret_hdr->xh_type);
358 			return (-1);
359 		}
360 
361 		ret_hdr->xh_length = ((uint32_t)buf[1] << 16) |
362 		    ((uint32_t)buf[2] << 8) |
363 		    ((uint32_t)buf[3]);
364 		break;
365 
366 	default:
367 		cmn_err(CE_WARN, "0x%08x: invalid port %u",
368 		    session->ipaddr, session->s_local_port);
369 		return (-1);
370 	}
371 
372 	return (0);
373 }
374 
375 /*
376  * Encode a transport session packet header into a 4-byte buffer.
377  * See smb_xprt_t definition for header format information.
378  */
379 static int
380 smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr,
381     uint8_t *buf, size_t buflen)
382 {
383 	if (session == NULL || hdr == NULL ||
384 	    buf == NULL || buflen < NETBIOS_HDR_SZ) {
385 		return (-1);
386 	}
387 
388 	switch (session->s_local_port) {
389 	case SSN_SRVC_TCP_PORT:
390 		buf[0] = hdr->xh_type;
391 		buf[1] = ((hdr->xh_length >> 16) & 1);
392 		buf[2] = (hdr->xh_length >> 8) & 0xff;
393 		buf[3] = hdr->xh_length & 0xff;
394 		break;
395 
396 	case SMB_SRVC_TCP_PORT:
397 		buf[0] = hdr->xh_type;
398 		buf[1] = (hdr->xh_length >> 16) & 0xff;
399 		buf[2] = (hdr->xh_length >> 8) & 0xff;
400 		buf[3] = hdr->xh_length & 0xff;
401 		break;
402 
403 	default:
404 		cmn_err(CE_WARN, "0x%08x: invalid port (%u)",
405 		    session->ipaddr, session->s_local_port);
406 		return (-1);
407 	}
408 
409 	return (0);
410 }
411 
412 /*
413  * smb_request_alloc
414  *
415  * Allocate an smb_request_t structure from the kmem_cache.  Partially
416  * initialize the found/new request.
417  *
418  * Returns pointer to a request
419  */
420 smb_request_t *
421 smb_request_alloc(struct smb_session *session, int req_length)
422 {
423 	struct smb_request *sr;
424 
425 	sr = kmem_cache_alloc(smb_info.si_cache_request, KM_SLEEP);
426 
427 	/*
428 	 * Future:  Use constructor to pre-initialize some fields.  For now
429 	 * there are so many fields that it is easiest just to zero the
430 	 * whole thing and start over.
431 	 */
432 	bzero(sr, sizeof (smb_request_t));
433 
434 	mutex_init(&sr->sr_mutex, NULL, MUTEX_DEFAULT, NULL);
435 	sr->session = session;
436 	sr->request_storage.forw = &sr->request_storage;
437 	sr->request_storage.back = &sr->request_storage;
438 	sr->command.max_bytes = req_length;
439 	sr->reply.max_bytes = smb_maxbufsize;
440 	sr->sr_req_length = req_length;
441 	sr->sr_request_buf = kmem_alloc(req_length, KM_SLEEP);
442 	sr->sr_magic = SMB_REQ_MAGIC;
443 	sr->sr_state = SMB_REQ_STATE_INITIALIZING;
444 	smb_slist_insert_tail(&session->s_req_list, sr);
445 	return (sr);
446 }
447 
448 void
449 smb_request_init_command_mbuf(smb_request_t *sr)
450 {
451 	MGET(sr->command.chain, 0, MT_DATA);
452 
453 	/*
454 	 * Setup mbuf, mimic MCLGET but use the complete packet buffer.
455 	 */
456 	sr->command.chain->m_ext.ext_buf = sr->sr_request_buf;
457 	sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf;
458 	sr->command.chain->m_len = sr->sr_req_length;
459 	sr->command.chain->m_flags |= M_EXT;
460 	sr->command.chain->m_ext.ext_size = sr->sr_req_length;
461 	sr->command.chain->m_ext.ext_ref = &mclrefnoop;
462 
463 	/*
464 	 * Initialize the rest of the mbuf_chain fields
465 	 */
466 	sr->command.flags = 0;
467 	sr->command.shadow_of = 0;
468 	sr->command.max_bytes = sr->sr_req_length;
469 	sr->command.chain_offset = 0;
470 }
471 
472 /*
473  * smb_request_cancel
474  *
475  * Handle a cancel for a request properly depending on the current request
476  * state.
477  */
478 void
479 smb_request_cancel(smb_request_t *sr)
480 {
481 	mutex_enter(&sr->sr_mutex);
482 	switch (sr->sr_state) {
483 
484 	case SMB_REQ_STATE_SUBMITTED:
485 	case SMB_REQ_STATE_ACTIVE:
486 	case SMB_REQ_STATE_CLEANED_UP:
487 		sr->sr_state = SMB_REQ_STATE_CANCELED;
488 		break;
489 
490 	case SMB_REQ_STATE_WAITING_LOCK:
491 		/*
492 		 * This request is waiting on a lock.  Wakeup everything
493 		 * waiting on the lock so that the relevant thread regains
494 		 * control and notices that is has been canceled.  The
495 		 * other lock request threads waiting on this lock will go
496 		 * back to sleep when they discover they are still blocked.
497 		 */
498 		sr->sr_state = SMB_REQ_STATE_CANCELED;
499 
500 		ASSERT(sr->sr_awaiting != NULL);
501 		mutex_enter(&sr->sr_awaiting->l_mutex);
502 		cv_broadcast(&sr->sr_awaiting->l_cv);
503 		mutex_exit(&sr->sr_awaiting->l_mutex);
504 
505 		break;
506 
507 	case SMB_REQ_STATE_WAITING_EVENT:
508 	case SMB_REQ_STATE_EVENT_OCCURRED:
509 		/*
510 		 * Cancellations for these states are handled by the
511 		 * notify-change code
512 		 */
513 		break;
514 
515 	case SMB_REQ_STATE_COMPLETED:
516 	case SMB_REQ_STATE_CANCELED:
517 		/*
518 		 * No action required for these states since the request
519 		 * is completing.
520 		 */
521 		break;
522 	/*
523 	 * Cases included:
524 	 *	SMB_REQ_STATE_FREE:
525 	 *	SMB_REQ_STATE_INITIALIZING:
526 	 */
527 	default:
528 		ASSERT(0);
529 		break;
530 	}
531 	mutex_exit(&sr->sr_mutex);
532 }
533 
534 /*
535  * smb_request_free
536  *
537  * release the memories which have been allocated for a smb request.
538  */
539 void
540 smb_request_free(smb_request_t *sr)
541 {
542 	ASSERT(sr->session);
543 
544 	ASSERT(sr->fid_ofile == NULL);
545 	ASSERT(sr->sid_odir == NULL);
546 	ASSERT(sr->tid_tree == NULL);
547 	ASSERT(sr->uid_user == NULL);
548 	ASSERT(sr->r_xa == NULL);
549 
550 	smb_slist_remove(&sr->session->s_req_list, sr);
551 
552 	sr->session = 0;
553 
554 	/* Release any temp storage */
555 	smbsr_free_malloc_list(&sr->request_storage);
556 
557 	if (sr->sr_request_buf)
558 		kmem_free(sr->sr_request_buf, sr->sr_req_length);
559 	if (sr->command.chain)
560 		m_freem(sr->command.chain);
561 	if (sr->reply.chain)
562 		m_freem(sr->reply.chain);
563 	if (sr->raw_data.chain)
564 		m_freem(sr->raw_data.chain);
565 
566 	sr->sr_magic = (uint32_t)~SMB_REQ_MAGIC;
567 	mutex_destroy(&sr->sr_mutex);
568 	kmem_cache_free(smb_info.si_cache_request, sr);
569 }
570 
571 /*ARGSUSED*/
572 void
573 smb_wakeup_session_daemon(smb_thread_t *thread, void *session_void)
574 {
575 	struct smb_session	*session = session_void;
576 
577 	ASSERT(session);
578 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
579 
580 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
581 	switch (session->s_state) {
582 	case SMB_SESSION_STATE_TERMINATED:
583 	case SMB_SESSION_STATE_DISCONNECTED:
584 		break;
585 	default:
586 		smb_soshutdown(session->sock);
587 		break;
588 	}
589 	smb_rwx_rwexit(&session->s_lock);
590 }
591 
592 /*
593  * This is the entry point for processing SMB messages over NetBIOS or
594  * SMB-over-TCP.
595  *
596  * NetBIOS connections require a session request to establish a session
597  * on which to send session messages.
598  *
599  * Session requests are not valid on SMB-over-TCP.  We don't need to do
600  * anything here as session requests will be treated as an error when
601  * handling session messages.
602  */
603 /*ARGSUSED*/
604 void
605 smb_session_daemon(smb_thread_t *thread, void *session_void)
606 {
607 	struct smb_session *session = session_void;
608 	int rc = 0;
609 
610 	ASSERT(session != NULL);
611 
612 	if (session->s_local_port == SSN_SRVC_TCP_PORT)
613 		rc = smb_session_request(session);
614 
615 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
616 
617 	if ((rc == 0) || (session->s_local_port == SMB_SRVC_TCP_PORT))
618 		session->s_state = SMB_SESSION_STATE_ESTABLISHED;
619 	else
620 		session->s_state = SMB_SESSION_STATE_DISCONNECTED;
621 
622 	while (session->s_state != SMB_SESSION_STATE_DISCONNECTED) {
623 		smb_rwx_rwexit(&session->s_lock);
624 
625 		rc = smb_session_message(session);
626 
627 		smb_rwx_rwenter(&session->s_lock, RW_WRITER);
628 
629 		if (rc != 0)
630 			break;
631 	}
632 
633 	smb_soshutdown(session->sock);
634 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
635 	smb_rwx_rwexit(&session->s_lock);
636 
637 	DTRACE_PROBE2(session__drop, struct session *, session, int, rc);
638 
639 	smb_session_cancel(session);
640 
641 	/*
642 	 * At this point everything related to the session should have been
643 	 * cleaned up and we expect that nothing will attempt to use the
644 	 * socket.
645 	 */
646 	smb_rwx_rwenter(&session->s_lock, RW_WRITER);
647 	session->s_state = SMB_SESSION_STATE_TERMINATED;
648 	smb_sodestroy(session->sock);
649 	session->sock = NULL;
650 	smb_rwx_rwexit(&session->s_lock);
651 
652 	/*
653 	 * Notify SMB service state machine so it can cleanup the session
654 	 */
655 	smb_svcstate_event(SMB_SVCEVT_SESSION_DELETE, (uintptr_t)session);
656 }
657 
658 /*
659  * Read and process SMB requests.
660  *
661  * Returns:
662  *	0	Success
663  *	1	Unable to read transport header
664  *	2	Invalid transport header type
665  *	3	Invalid SMB length (too small)
666  *	4	Unable to read SMB header
667  *	5	Invalid SMB header (bad magic number)
668  *	6	Unable to read SMB data
669  *	2x	Write raw failed
670  */
671 static int
672 smb_session_message(smb_session_t *session)
673 {
674 	struct smb_request *sr = NULL;
675 	smb_xprt_t hdr;
676 	uint8_t *req_buf;
677 	uint32_t resid;
678 	int rc;
679 
680 	if (smb_session_xprt_gethdr(session, &hdr) != 0)
681 		return (1);
682 
683 	DTRACE_PROBE2(session__receive__xprthdr, struct session *, session,
684 	    smb_xprt_t *, &hdr);
685 
686 	if (hdr.xh_type != SESSION_MESSAGE) {
687 		/*
688 		 * Anything other than SESSION_MESSAGE or SESSION_KEEP_ALIVE
689 		 * is an error.  A SESSION_REQUEST may indicate a new session
690 		 * request but we need to close this session and we can treat
691 		 * it as an error here.
692 		 */
693 		if (hdr.xh_type == SESSION_KEEP_ALIVE) {
694 			session->keep_alive = smb_keep_alive;
695 			return (0);
696 		}
697 
698 		return (2);
699 	}
700 
701 	if (hdr.xh_length < SMB_HEADER_LEN)
702 		return (3);
703 
704 	session->keep_alive = smb_keep_alive;
705 
706 	/*
707 	 * Allocate a request context, read the SMB header and validate it.
708 	 * The sr includes a buffer large enough to hold the SMB request
709 	 * payload.  If the header looks valid, read any remaining data.
710 	 */
711 	sr = smb_request_alloc(session, hdr.xh_length);
712 
713 	req_buf = (uint8_t *)sr->sr_request_buf;
714 	resid = hdr.xh_length;
715 
716 	if (smb_sorecv(session->sock, req_buf, SMB_HEADER_LEN) != 0) {
717 		smb_request_free(sr);
718 		return (4);
719 	}
720 
721 	if (SMB_PROTOCOL_MAGIC_INVALID(sr)) {
722 		smb_request_free(sr);
723 		return (5);
724 	}
725 
726 	if (resid > SMB_HEADER_LEN) {
727 		req_buf += SMB_HEADER_LEN;
728 		resid -= SMB_HEADER_LEN;
729 
730 		if (smb_sorecv(session->sock, req_buf, resid) != 0) {
731 			smb_request_free(sr);
732 			return (6);
733 		}
734 	}
735 
736 	/*
737 	 * Initialize command MBC to represent the received data.
738 	 */
739 	smb_request_init_command_mbuf(sr);
740 
741 	DTRACE_PROBE1(session__receive__smb, smb_request_t *, sr);
742 
743 	/*
744 	 * If this is a raw write, hand off the request.  The handler
745 	 * will retrieve the remaining raw data and process the request.
746 	 */
747 	if (SMB_IS_WRITERAW(sr)) {
748 		rc = smb_handle_write_raw(session, sr);
749 		/* XXX smb_request_free(sr); ??? */
750 		return (rc);
751 	}
752 
753 	sr->sr_state = SMB_REQ_STATE_SUBMITTED;
754 	(void) taskq_dispatch(smb_info.thread_pool, smb_session_worker,
755 	    sr, TQ_SLEEP);
756 	return (0);
757 }
758 
759 /*
760  * smb_session_wakeup_daemon
761  *
762  * When the smbsrv kernel module/driver gets unloaded, chances are the
763  * smb_nbt_daemon and smb_tcp_daemon threads are blocked in soaccept.
764  * We can't get control of the threads until they return from soaccept.
765  * This function will attempt to connect to the SMB service via
766  * "localhost" to wake up the threads.
767  */
768 /*ARGSUSED*/
769 static void
770 smb_session_wakeup_daemon(smb_thread_t *thread, void *so_void)
771 {
772 	struct sonode	*so = so_void;
773 
774 	ASSERT(so != NULL);
775 
776 	mutex_enter(&so->so_lock);
777 	so->so_error = EINTR;
778 	cv_signal(&so->so_connind_cv);
779 	mutex_exit(&so->so_lock);
780 }
781 
782 /*
783  * SMB-over-NetBIOS service.
784  *
785  * Traditional SMB service over NetBIOS (port 139), which requires
786  * that a NetBIOS session be established.
787  */
788 void
789 smb_nbt_daemon(smb_thread_t *thread, void *arg)
790 {
791 	/* XXX Defaults for these values should come from smbd and SMF */
792 	uint32_t		txbuf_size = 128*1024;
793 	uint32_t		on = 1;
794 	struct smb_session	*session;
795 	struct sonode		*l_so, *s_so;
796 	struct sockaddr_in	sin;
797 	int			error;
798 	smb_info_t		*si = arg;
799 
800 	ASSERT(si != NULL);
801 	sin.sin_family = AF_INET;
802 	sin.sin_port = htons(SSN_SRVC_TCP_PORT);
803 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
804 
805 	l_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
806 	if (l_so == NULL) {
807 		cmn_err(CE_WARN, "NBT: socket create failed");
808 		smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM);
809 		return;
810 	}
811 
812 	(void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR,
813 	    (const void *)&on, sizeof (on));
814 
815 	if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin),
816 	    0, 0)) != 0) {
817 		cmn_err(CE_WARN, "NBT: bind failed");
818 		smb_soshutdown(l_so);
819 		smb_sodestroy(l_so);
820 		smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
821 		return;
822 	}
823 	if ((error = solisten(l_so, 20)) < 0) {
824 		cmn_err(CE_WARN, "NBT: listen failed");
825 		smb_soshutdown(l_so);
826 		smb_sodestroy(l_so);
827 		smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
828 		return;
829 	}
830 
831 	smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so);
832 	si->si_connect_progress |= SMB_SI_NBT_CONNECTED;
833 	smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL);
834 
835 	while (smb_thread_continue_nowait(thread)) {
836 		DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so);
837 
838 		error = soaccept(l_so, 0, &s_so);
839 		if (error) {
840 			DTRACE_PROBE1(so__accept__error, int, error);
841 			if (error == EINTR) {
842 				continue;
843 			}
844 
845 			break;
846 		}
847 
848 		DTRACE_PROBE1(so__accept, struct sonode *, s_so);
849 
850 		(void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
851 		    (const void *)&on, sizeof (on));
852 		(void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
853 		    (const void *)&on, sizeof (on));
854 		(void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
855 		    (const void *)&txbuf_size, sizeof (txbuf_size));
856 
857 		/*
858 		 * Create a session for this connection and notify the SMB
859 		 * service state machine.  The service state machine may
860 		 * start a session thread or reject the session depending
861 		 * on the current service state or number of connections.
862 		 */
863 		session = smb_session_create(s_so, SSN_SRVC_TCP_PORT);
864 		smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE,
865 		    (uintptr_t)session);
866 
867 	}
868 
869 	smb_soshutdown(l_so);
870 	smb_sodestroy(l_so);
871 	si->si_connect_progress &= ~SMB_SI_NBT_CONNECTED;
872 	smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
873 }
874 
875 /*
876  * SMB-over-TCP (or NetBIOS-less SMB) service.
877  *
878  * SMB service natively over TCP (port 445), i.e. no NetBIOS support.
879  */
880 void
881 smb_tcp_daemon(smb_thread_t *thread, void *arg)
882 {
883 	/* XXX Defaults for these values should come from smbd and SMF */
884 	uint32_t		txbuf_size = 128*1024;
885 	uint32_t		on = 1;
886 	struct smb_session	*session;
887 	struct sonode		*l_so, *s_so;
888 	struct sockaddr_in	sin;
889 	int			error;
890 	smb_info_t		*si = arg;
891 
892 	ASSERT(si != NULL);
893 	sin.sin_family = AF_INET;
894 	sin.sin_port = htons(SMB_SRVC_TCP_PORT);
895 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
896 
897 	l_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
898 	if (l_so == NULL) {
899 		cmn_err(CE_WARN, "TCP: socket create failed");
900 		smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)ENOMEM);
901 		return;
902 	}
903 
904 	(void) sosetsockopt(l_so, SOL_SOCKET, SO_REUSEADDR,
905 	    (const void *)&on, sizeof (on));
906 
907 	if ((error = sobind(l_so, (struct sockaddr *)&sin, sizeof (sin),
908 	    0, 0)) != 0) {
909 		cmn_err(CE_WARN, "TCP: bind failed");
910 		smb_soshutdown(l_so);
911 		smb_sodestroy(l_so);
912 		smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
913 		return;
914 	}
915 	if ((error = solisten(l_so, 20)) < 0) {
916 		cmn_err(CE_WARN, "TCP: listen failed");
917 		smb_soshutdown(l_so);
918 		smb_sodestroy(l_so);
919 		smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
920 		return;
921 	}
922 
923 	smb_thread_set_awaken(thread, smb_session_wakeup_daemon, l_so);
924 	si->si_connect_progress |= SMB_SI_TCP_CONNECTED;
925 	smb_svcstate_event(SMB_SVCEVT_CONNECT, NULL);
926 
927 	while (smb_thread_continue_nowait(thread)) {
928 		DTRACE_PROBE1(so__wait__accept, struct sonode *, l_so);
929 
930 		error = soaccept(l_so, 0, &s_so);
931 		if (error) {
932 			DTRACE_PROBE1(so__accept__error, int, error);
933 			if (error == EINTR) {
934 				continue;
935 			}
936 
937 			break;
938 		}
939 
940 		DTRACE_PROBE1(so__accept, struct sonode *, s_so);
941 
942 		(void) sosetsockopt(s_so, IPPROTO_TCP, TCP_NODELAY,
943 		    (const void *)&on, sizeof (on));
944 		(void) sosetsockopt(s_so, SOL_SOCKET, SO_KEEPALIVE,
945 		    (const void *)&on, sizeof (on));
946 		(void) sosetsockopt(s_so, SOL_SOCKET, SO_SNDBUF,
947 		    (const void *)&txbuf_size, sizeof (txbuf_size));
948 
949 		/*
950 		 * Create a session for this connection and notify the SMB
951 		 * service state machine.  The service state machine may
952 		 * start a session thread or reject the session depending
953 		 * on the current service state or number of connections.
954 		 */
955 		session = smb_session_create(s_so, SMB_SRVC_TCP_PORT);
956 		smb_svcstate_event(SMB_SVCEVT_SESSION_CREATE,
957 		    (uintptr_t)session);
958 
959 	}
960 
961 	smb_soshutdown(l_so);
962 	smb_sodestroy(l_so);
963 	si->si_connect_progress &= ~SMB_SI_TCP_CONNECTED;
964 	smb_svcstate_event(SMB_SVCEVT_DISCONNECT, (uintptr_t)error);
965 }
966 
967 /*
968  * smb_session_reject
969  *
970  * Build and send a NEGATIVE_SESSION_RESPONSE on the specified socket.
971  * The reason is written to the log.
972  */
973 /*ARGSUSED*/
974 void
975 smb_session_reject(smb_session_t *session, char *reason)
976 {
977 	smb_txbuf_t	*txb;
978 
979 	smb_rwx_rwenter(&session->s_lock, RW_READER);
980 	if (session->sock != NULL) {
981 		txb = smb_net_txb_alloc();
982 		txb->tb_data[0] = NEGATIVE_SESSION_RESPONSE;
983 		txb->tb_data[1] = 0;
984 		txb->tb_data[2] = 0;
985 		txb->tb_data[3] = 1;
986 		txb->tb_data[4] = SESSION_INSUFFICIENT_RESOURCES;
987 		txb->tb_len = 5;
988 		(void) smb_net_txb_send(session->sock, &session->s_txlst, txb);
989 	}
990 	smb_rwx_rwexit(&session->s_lock);
991 }
992 
993 /*
994  * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT.
995  */
996 smb_session_t *
997 smb_session_create(struct sonode *new_so, uint16_t port)
998 {
999 	uint32_t		ipaddr;
1000 	uint32_t		local_ipaddr;
1001 	struct sockaddr_in	sin;
1002 	smb_session_t		*session;
1003 
1004 	session = kmem_cache_alloc(smb_info.si_cache_session, KM_SLEEP);
1005 	bzero(session, sizeof (smb_session_t));
1006 
1007 	if (smb_idpool_constructor(&session->s_uid_pool)) {
1008 		kmem_cache_free(smb_info.si_cache_session, session);
1009 		return (NULL);
1010 	}
1011 
1012 	session->s_kid = SMB_NEW_KID();
1013 	session->s_state = SMB_SESSION_STATE_DISCONNECTED;
1014 	session->native_os = NATIVE_OS_UNKNOWN;
1015 	session->opentime = lbolt64;
1016 	session->keep_alive = smb_keep_alive;
1017 	session->activity_timestamp = lbolt64;
1018 
1019 	smb_slist_constructor(&session->s_req_list, sizeof (smb_request_t),
1020 	    offsetof(smb_request_t, sr_session_lnd));
1021 
1022 	smb_llist_constructor(&session->s_user_list, sizeof (smb_user_t),
1023 	    offsetof(smb_user_t, u_lnd));
1024 
1025 	smb_llist_constructor(&session->s_xa_list, sizeof (smb_xa_t),
1026 	    offsetof(smb_xa_t, xa_lnd));
1027 
1028 	smb_net_txl_constructor(&session->s_txlst);
1029 
1030 	smb_thread_init(&session->s_thread, "smb_session", &smb_session_daemon,
1031 	    session, smb_wakeup_session_daemon, session);
1032 
1033 	smb_rwx_init(&session->s_lock);
1034 
1035 	bcopy(new_so->so_faddr_sa, &sin, new_so->so_faddr_len);
1036 	ipaddr = sin.sin_addr.s_addr;
1037 
1038 	bcopy(new_so->so_laddr_sa, &sin, new_so->so_faddr_len);
1039 	local_ipaddr = sin.sin_addr.s_addr;
1040 
1041 	session->s_local_port = port;
1042 	session->ipaddr = ipaddr;
1043 	session->local_ipaddr = local_ipaddr;
1044 	session->sock = new_so;
1045 
1046 	session->s_magic = SMB_SESSION_MAGIC;
1047 	return (session);
1048 }
1049 
1050 void
1051 smb_session_delete(smb_session_t *session)
1052 {
1053 	ASSERT(session);
1054 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1055 
1056 	session->s_magic = (uint32_t)~SMB_SESSION_MAGIC;
1057 
1058 	smb_rwx_destroy(&session->s_lock);
1059 	smb_thread_destroy(&session->s_thread);
1060 	smb_net_txl_destructor(&session->s_txlst);
1061 	smb_slist_destructor(&session->s_req_list);
1062 	smb_llist_destructor(&session->s_user_list);
1063 	smb_llist_destructor(&session->s_xa_list);
1064 
1065 	ASSERT(session->s_tree_cnt == 0);
1066 	ASSERT(session->s_file_cnt == 0);
1067 	ASSERT(session->s_dir_cnt == 0);
1068 
1069 	smb_idpool_destructor(&session->s_uid_pool);
1070 	kmem_cache_free(smb_info.si_cache_session, session);
1071 }
1072 
1073 void
1074 smb_session_cancel(smb_session_t *session)
1075 {
1076 	smb_xa_t	*xa, *nextxa;
1077 
1078 	/* All the request currently being treated must be canceled. */
1079 	smb_session_cancel_requests(session);
1080 
1081 	/*
1082 	 * We wait for the completion of all the requests associated with
1083 	 * this session.
1084 	 */
1085 	smb_slist_wait_for_empty(&session->s_req_list);
1086 
1087 	/*
1088 	 * At this point the reference count of the users, trees, files,
1089 	 * directories should be zero. It should be possible to destroy them
1090 	 * without any problem.
1091 	 */
1092 	xa = smb_llist_head(&session->s_xa_list);
1093 	while (xa) {
1094 		nextxa = smb_llist_next(&session->s_xa_list, xa);
1095 		smb_xa_close(xa);
1096 		xa = nextxa;
1097 	}
1098 	smb_user_logoff_all(session);
1099 }
1100 
1101 void
1102 smb_session_cancel_requests(
1103     smb_session_t	*session)
1104 {
1105 	smb_request_t	*sr;
1106 	smb_request_t	*tmp;
1107 
1108 	/* All the SMB requests on the notification queue are canceled. */
1109 	smb_process_session_notify_change_queue(session);
1110 
1111 	smb_slist_enter(&session->s_req_list);
1112 	sr = smb_slist_head(&session->s_req_list);
1113 	while (sr) {
1114 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1115 		tmp = smb_slist_next(&session->s_req_list, sr);
1116 
1117 		smb_request_cancel(sr);
1118 
1119 		sr = tmp;
1120 	}
1121 	smb_slist_exit(&session->s_req_list);
1122 }
1123 
1124 void
1125 smb_session_worker(
1126     void	*arg)
1127 {
1128 	smb_request_t	*sr;
1129 
1130 	sr = (smb_request_t *)arg;
1131 
1132 	ASSERT(sr != NULL);
1133 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1134 
1135 	mutex_enter(&sr->sr_mutex);
1136 	switch (sr->sr_state) {
1137 	case SMB_REQ_STATE_SUBMITTED:
1138 		mutex_exit(&sr->sr_mutex);
1139 		if (smb_dispatch_request(sr) < 0) {
1140 			smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
1141 			if (sr->session->s_state !=
1142 			    SMB_SESSION_STATE_DISCONNECTED) {
1143 				smb_soshutdown(sr->session->sock);
1144 				sr->session->s_state =
1145 				    SMB_SESSION_STATE_DISCONNECTED;
1146 			}
1147 			smb_rwx_rwexit(&sr->session->s_lock);
1148 		}
1149 		mutex_enter(&sr->sr_mutex);
1150 		if (!sr->sr_keep) {
1151 			sr->sr_state = SMB_REQ_STATE_COMPLETED;
1152 			mutex_exit(&sr->sr_mutex);
1153 			smb_request_free(sr);
1154 			break;
1155 		}
1156 		mutex_exit(&sr->sr_mutex);
1157 		break;
1158 
1159 	default:
1160 		ASSERT(sr->sr_state == SMB_REQ_STATE_CANCELED);
1161 		sr->sr_state = SMB_REQ_STATE_COMPLETED;
1162 		mutex_exit(&sr->sr_mutex);
1163 		smb_request_free(sr);
1164 		break;
1165 	}
1166 }
1167 
1168 /*
1169  * smb_session_disconnect_share
1170  *
1171  * Disconnects the specified share. This function should be called after the
1172  * share passed in has been made unavailable by the "share manager".
1173  */
1174 void
1175 smb_session_disconnect_share(char *sharename)
1176 {
1177 	smb_session_t	*session;
1178 
1179 	smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
1180 
1181 	session = NULL;
1182 	while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx,
1183 	    session)) != NULL) {
1184 
1185 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1186 		smb_rwx_rwenter(&session->s_lock, RW_READER);
1187 		switch (session->s_state) {
1188 		case SMB_SESSION_STATE_NEGOTIATED:
1189 		case SMB_SESSION_STATE_OPLOCK_BREAKING:
1190 		case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
1191 			smb_user_t	*user;
1192 			smb_user_t	*next;
1193 
1194 			user = smb_user_lookup_by_state(session, NULL);
1195 			while (user) {
1196 				smb_user_disconnect_share(user, sharename);
1197 				next = smb_user_lookup_by_state(session, user);
1198 				smb_user_release(user);
1199 				user = next;
1200 			}
1201 			break;
1202 
1203 		}
1204 		default:
1205 			break;
1206 		}
1207 		smb_rwx_rwexit(&session->s_lock);
1208 	}
1209 	smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
1210 }
1211 
1212 /*
1213  * smb_session_disconnect_volume
1214  *
1215  * This function is called when a volume is deleted. We need to ensure
1216  * all trees with a reference to the volume are destroyed before we
1217  * discard the fs_online. Before destroying each tree, we notify any
1218  * in-progress requests and give them a chance to complete.
1219  *
1220  * NOTE:
1221  * We shouldn't be accepting any new connection on this volume while
1222  * we are in this function.
1223  */
1224 void
1225 smb_session_disconnect_volume(fs_desc_t *fsd)
1226 {
1227 	smb_session_t	*session;
1228 
1229 	smb_svcstate_lock_read(&smb_info.si_svc_sm_ctx);
1230 
1231 	session = NULL;
1232 	while ((session = smb_svcstate_session_getnext(&smb_info.si_svc_sm_ctx,
1233 	    session)) != NULL) {
1234 
1235 		ASSERT(session->s_magic == SMB_SESSION_MAGIC);
1236 		smb_rwx_rwenter(&session->s_lock, RW_READER);
1237 		switch (session->s_state) {
1238 		case SMB_SESSION_STATE_NEGOTIATED:
1239 		case SMB_SESSION_STATE_OPLOCK_BREAKING:
1240 		case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: {
1241 			smb_user_t	*user;
1242 			smb_user_t	*next;
1243 
1244 			user = smb_user_lookup_by_state(session, NULL);
1245 			while (user) {
1246 				smb_user_disconnect_volume(user, fsd);
1247 				next = smb_user_lookup_by_state(session, user);
1248 				smb_user_release(user);
1249 				user = next;
1250 			}
1251 			break;
1252 
1253 		}
1254 		default:
1255 			break;
1256 		}
1257 		smb_rwx_rwexit(&session->s_lock);
1258 	}
1259 	smb_svcstate_unlock(&smb_info.si_svc_sm_ctx);
1260 }
1261